EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=590)
-   -   KEYRING by Jaystonian (aka James76) (https://www.eqemulator.org/forums/showthread.php?t=26177)

James76 09-14-2008 01:01 PM

KEYRING by Jaystonian (aka James76)
 
Discussion: http://eqemulator.net/forums/showthread.php?t=26177

Please forgive the indent loss. This should be straight-forward. The last modification in Doors::HandleClick, the /*NEW*/ lines indicate what to add, just look for the start and don't miss the curly braces.

================================================== ========================
[in SQL]

Quote:

drop table if exists `keyring`;
create table `keyring`(
`char_id` integer not null,
`item_id` integer not null
) engine=MyISAM DEFAULT CHARSET=latin1;
================================================== ========================
[in ./common/database.cpp add to method Database::DeleteCharacter(char *name)]:

Quote:

#if DEBUG >= 5
printf(" keyring");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM keyring WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
if(query)
{
safe_delete_array(query);
query = NULL;
}
================================================== ========================
[in ./zone/client.h add to header:]
Quote:

#include <list>
================================================== ========================
[in ./zone/client.h add to private section of Client class definition:]
Quote:

std::list<int32> keyring;
================================================== ========================
[in ./zone/client.h add to public section of Client class definition:]
Quote:

void KeyRingLoad();
void KeyRingAdd(int32 item_id);
bool KeyRingCheck(int32 item_id);
void KeyRingList();
================================================== ========================
[in ./zone/client.cpp add to constructor:]
Quote:

keyring.clear();
================================================== ========================
[in ./zone/client.cpp add:]
Quote:

void Client::KeyRingLoad()
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
query = new char[256];

keyring.clear();
sprintf(query, "SELECT item_id FROM keyring WHERE char_id='%i' ORDER BY item_id",character_id);
if (database.RunQuery(query, strlen(query), errbuf, &result))
{
safe_delete_array(query);
while(0 != (row = mysql_fetch_row(result))){
keyring.push_back(atoi(row[0]));
}
mysql_free_result(result);
}else {
cerr << "Error in Client::KeyRingLoad query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return;
}
}

void Client::KeyRingAdd(int32 item_id)
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
int32 affected_rows = 0;
query = new char[256];
bool bFound = KeyRingCheck(item_id);
if(!bFound){
sprintf(query, "INSERT INTO keyring(char_id,item_id) VALUES(%i,%i)",character_id,item_id);
if(database.RunQuery(query, strlen(query), errbuf, 0, &affected_rows))
{
Message(4,"Added to keyring.");
safe_delete_array(query);
}
else
{
cerr << "Error in Doors::HandleClick query '" << query << "' " << errbuf << endl;
safe_delete_array(query);
return;
}
keyring.push_back(item_id);
}
}

bool Client::KeyRingCheck(int32 item_id)
{
for(std::list<int32>::iterator iter = keyring.begin();
iter != keyring.end();
++iter)
{
if(*iter == item_id)
return true;
}
return false;
}

void Client::KeyRingList()
{
Message(4,"Keys on Keyring:");
const Item_Struct *item = 0;
for(std::list<int32>::iterator iter = keyring.begin();
iter != keyring.end();
++iter)
{
if ((item = database.GetItem(*iter))!=NULL) {
Message(4,item->Name);
}
}
}
================================================== ========================
[in ./common/emu_oplist.h add]
Quote:

N(OP_KeyRing),
================================================== ========================
[in patch_Titanium.conf add]
Quote:

OP_KeyRing=0x68c4
================================================== ========================
[in ./zone/client_packet.h add]
Quote:

void Handle_OP_KeyRing(const EQApplicationPacket *app);
================================================== ========================
[in ./zone/client_packet.cpp in function MapOpcodes() add]
Quote:

ConnectedOpcodes[OP_KeyRing] = &Client::Handle_OP_KeyRing;
================================================== ========================
[in ./zone/client_packet.cpp add]
Quote:

void Client::Handle_OP_KeyRing(const EQApplicationPacket *app)
{
KeyRingList();
}
================================================== ========================
[in ./zone/client_packet.cpp, insert in Client::FinishConnState2() just after SetEndurance():]
Quote:

KeyRingLoad();
================================================== ========================
[in ./zone/doors.cpp in method Doors::HandleClick(...) add code on lines]
Quote:

if (sender->GetGM()) // GM can always open locks - should probably be changed to require a key
{
sender->Message_StringID(4,DOORS_GM);
if( !IsDoorOpen() || opentype == 58 )
{
md->action = OPEN_DOOR;
}
else
{
md->action = CLOSE_DOOR;
}
}
else if (playerkey)
{ // they have something they are trying to open it with
if (keyneeded && keyneeded == playerkey)
{ // key required and client is using the right key
/*NEW*/ sender->KeyRingAdd(playerkey);
sender->Message(4,"You got it open!"); // more debug spam
if( !IsDoorOpen() || opentype == 58 )
{
md->action = OPEN_DOOR;
}
else
{
md->action = CLOSE_DOOR;
}
}
}
else if(lockpicks != NULL)
{
if(sender->GetSkill(PICK_LOCK))
{
if(lockpicks->GetItem()->ItemType == ItemTypeLockPick)
{
float modskill=sender->GetSkill(PICK_LOCK);
sender->CheckIncreaseSkill(PICK_LOCK, 1);
#if EQDEBUG>=5
LogFile->write(EQEMuLog::Debug,"Client has lockpicks: skill=%f", modskill);
#endif

if(GetLockpick() <= modskill)
{
if(!IsDoorOpen())
{
md->action = OPEN_DOOR;
}
else
{
md->action = CLOSE_DOOR;
}
sender->Message_StringID(4,DOORS_SUCCESSFUL_PICK);
}
else
{
sender->Message_StringID(4,DOORS_INSUFFICIENT_SKILL);
return;
}
}
else
{
sender->Message_StringID(4,DOORS_NO_PICK);
return;
}
}
else
{
sender->Message_StringID(4,DOORS_CANT_PICK);
return;
}
}
else
{ // locked door and nothing to open it with
/*NEW*/ if(keyneeded != 0){
/*NEW*/ //search for key on keyring
/*NEW*/ if(sender->KeyRingCheck(keyneeded)){
/*NEW*/ sender->Message(4,"You got it open!"); // more debug spam
/*NEW*/ if( !IsDoorOpen() || opentype == 58 )
/*NEW*/ {
/*NEW*/ md->action = OPEN_DOOR;
/*NEW*/ }
/*NEW*/ else
/*NEW*/ {
/*NEW*/ md->action = CLOSE_DOOR;
/*NEW*/ }
/*NEW*/ }
/*NEW*/ }
/*NEW*/ else
/*NEW*/ {
sender->Message_StringID(4,DOORS_LOCKED);
return;
/*NEW*/ }
}
================================================== ========================

James76 09-14-2008 01:09 PM

final note:
 
This is only for door keys.

trevius 09-14-2008 07:10 PM

Quote:

Originally Posted by James76 (Post 155836)
This is only for door keys.

As apposed to what? Are there other things that would go on the keyring?

Thanks for the code submission! Have you tested this and verified that it all works? I can't wait to get this on my server and try it out :)

James76 09-14-2008 07:59 PM

Yes, flawless victory.

cavedude 09-14-2008 08:47 PM

Great work! Would you mind posting a diff, or at the least approximate line numbers?

James76 09-14-2008 09:03 PM

Quote:

Originally Posted by cavedude (Post 155866)
Great work! Would you mind posting a diff, or at the least approximate line numbers?

Sure, for the larger files, np. The rest is simple, just add your methods anywhere to the file (usually at bottom) or modify near the top..

Working down my list of mods,

line 493 ./common/database.cpp

line 46 ./zone/client.h (header section)
line 877 ./zone/client.h (private section)
line 190 ./zone/client.h (public section)

line 3281 ./zone/client.cpp (4 methods to insert)

line 318 ./zone/client_packet.cpp
line 7000 ./zone/client_packet.cpp (add Client::Handle_OP_KeyRing())
line 6436 ./zone/client_packet.cpp (mod FinishConnState2())

line 165 ./zone/doors.cpp (this is start of section)



You may find it easier to open some sort of text editor, copy my entire post over, and delete each section as you add it in.

joligario 09-15-2008 02:11 AM

Quote:

Originally Posted by trevius (Post 155858)
As apposed to what? Are there other things that would go on the keyring?

Thanks for the code submission! Have you tested this and verified that it all works? I can't wait to get this on my server and try it out :)

One thing that comes to mind, Trakanon's Idol goes on keyring and it is not a door.

trevius 09-15-2008 04:16 AM

I think the port into Seb is an object in the doors table. So even though it isn't a door in the way you would normally think of one, I imagine it would be treated the same as far as the emulator and this code is concerned. Unless it is a zone point that requires a key or something. Don't really feel like searching the DB to check which one hehe.

James76 09-15-2008 08:51 PM

bug found
 
Somehow it breaks the code for clicking on the factory door in Plane of Innovation after killing Xanamech. I get:

You got the door open.
This is locked...

Hold tight, I'll figure it out.

cavedude 09-15-2008 08:58 PM

The factory door is handled by a Perl script, because it requires a character flag, and not a key. The door is permalocked using keyitem 1, and it's up to the script to determine if the player can open the door or not, and if so to do it. There are also doors in a similar situation, but the door can accept two keys. In that case, the script would be the same except for looking for a global, it would look for one of the keys in the player's inventory. Here is the script:

Code:

sub EVENT_CLICKDOOR {
 
  if($doorid == 7 || $doorid == 263){
      if($qglobals{pop_poi_dragon} == 1) {
            $client->Message(0,"You got the door open.");
            quest::forcedooropen(7);
      }
  }
  $qglobals{pop_poi_dragon}=undef;
  }

In other news, I must be a complete idiot, because I can't get this code to work at all. Even if I manually insert the keyitem into my database, it doesn't show up on /key, and I can't open the door without the item. (I've been trying the Paineel door.) Of course, it may be a compatibility issue as PEQ's code is significantly different than EQEmu's. Though, I think doors are the same, it could very well be my error. Also, I admit I only tried one keyitem/door so it just may be that one that is broken.

James76 09-16-2008 01:09 AM

ok I had some time to look at this... i disabled my code and I found I could click on the door for a while and it still wouldn't open. It looks like Client::Message_StringID(4,DOORS_LOCKED) has been hijacked with a flags check to unlock the door....

So one fix and one change.

In ./zone/doors.cpp it should look like:

Code:

                // a key is required or the door is locked but can be picked or both
                sender->Message(4,"This is locked...");                // debug spam - should probably go
                if (sender->GetGM())                // GM can always open locks - should probably be changed to require a key
                {
                        sender->Message_StringID(4,DOORS_GM);
                        if( !IsDoorOpen() || opentype == 58 )
                        {
                                md->action = OPEN_DOOR;
                        }
                        else
                        {
                                md->action = CLOSE_DOOR;
                        }
                }
                else if (playerkey)
                {        // they have something they are trying to open it with
                        if (keyneeded && keyneeded == playerkey)
                        {        // key required and client is using the right key
/*NEW*/                                sender->KeyRingAdd(playerkey);
                                sender->Message(4,"You got it open!");                // more debug spam
                                if( !IsDoorOpen() || opentype == 58 )
                                {
                                        md->action = OPEN_DOOR;
                                }
                                else
                                {
                                        md->action = CLOSE_DOOR;
                                }
                        }
                }
                else if(lockpicks != NULL)
                {
                        if(sender->GetSkill(PICK_LOCK))
                        {
                                if(lockpicks->GetItem()->ItemType == ItemTypeLockPick)
                                {
                                        float modskill=sender->GetSkill(PICK_LOCK);
                                        sender->CheckIncreaseSkill(PICK_LOCK, 1);
#if EQDEBUG>=5
                                        LogFile->write(EQEMuLog::Debug,"Client has lockpicks: skill=%f", modskill);
#endif

                                        if(GetLockpick() <= modskill)
                                        {
                                                if(!IsDoorOpen())
                                                {
                                                        md->action = OPEN_DOOR;
                                                }
                                                else
                                                {
                                                        md->action = CLOSE_DOOR;
                                                }
                                                sender->Message_StringID(4,DOORS_SUCCESSFUL_PICK);
                                        }
                                        else
                                        {
                                                sender->Message_StringID(4,DOORS_INSUFFICIENT_SKILL);
                                                return;
                                        }
                                }
                                else
                                {
                                        sender->Message_StringID(4,DOORS_NO_PICK);
                                        return;
                                }
                        }
                        else
                        {
                                sender->Message_StringID(4,DOORS_CANT_PICK);
                                return;
                        }
                }
                else
                {        // locked door and nothing to open it with
                        //search for key on keyring
/*NEW*/                        if(sender->KeyRingCheck(keyneeded)){
/*NEW*/                                sender->Message(4,"You got it open!");                // more debug spam
/*NEW*/                                if( !IsDoorOpen() || opentype == 58 )
/*NEW*/                                {
/*NEW*/                                        md->action = OPEN_DOOR;
/*NEW*/                                }
/*NEW*/                                else
/*NEW*/                                {
/*NEW*/                                        md->action = CLOSE_DOOR;
/*NEW*/                                }
/*NEW*/                        }
/*NEW*/                        else
/*NEW*/                        {
                                sender->Message_StringID(4,DOORS_LOCKED);
                                return;
/*NEW*/                        }
                }
        }


Then in ./zone/client.cpp add to very start of Client::KeyRingAdd()

Code:

if(0==item_id)return;
Now the PoI factory door works. The message is still FUNKY but whatever.

trevius 09-16-2008 04:39 AM

I think you missed Cavedude's post :P

KLS 09-16-2008 05:59 AM

I'll be a few days at least (probably more) before I can get this and everything else posted in this section looked at. R.I.P free time =p

Angelox 09-16-2008 08:56 AM

Quote:

Originally Posted by KLS (Post 156017)
I'll be a few days at least (probably more) before I can get this and everything else posted in this section looked at. R.I.P free time =p

Well, You got plenty of people I'm sure would help; people that have been around, and we all know, like trevius, Derision - those are just the first two that come to my head out of a whole bunch. And what about Scorpious2k? what happened to him? he was helping and now hes gone.
I have yet to understand what the idea is behind all this 'closed doors' operation.

trevius 09-16-2008 09:28 AM

LOL, well I can certainly build a working source and test it for bugs, but I am no where near good enough to read code and see if something is horribly wrong with it somewhere. I am sure that most of the time it would be just fine, but I am also sure that it would be done much sloppier than how KLS would add it. I know she sometimes edits the code some before actually adding it.

I feel like Derision would do a good job at it, but he isn't a developer yet. Not exactly sure where S2K is, but I know he was having some PC problems for a while. He may have just popped out as quickly as he popped back in :P

No rush, KLS. I still haven't tested alot of the new code updates yet. I have been super busy with finalizing a zone I have been working on for about 4 months. It should be done in a day or 2 and I will try to get all of the new code submissions in and test them as best I can. I will let you all know what I find :) So far I know that my scribespells and traindiscs code works well.

Though, I have been seeing a considerably large amount of "world zone disconnects". Where it will send a message like that and then say it reconnected to all zones in use by each zone name. It doesn't actually cause a crash as long as you stay in the zone, but if you try to zone out, you get booted back to login. Then, if you login again you are fine, at least until it happens again. Currently it seems to happen every couple of hours.

I have seen this happen before, but never this bad. The only time in the past that I ever saw it was when I was using the emulator admin tool and doing database searches for accounts/characters.

The only thing I can think of that is causing it now is the 1129 source, or custom code I have added in. Or, it could be that I gave 2 of my GMs remote database access recently. But, the problem happens even when neither of them are doing any changes/queries. I will look into this issue more later, but if anyone else is having this problem too, I would be glad to know that it isn't just me. Plus, that helps narrow down what is causing it.

I guess I should have made a whole new support post about that issue lol. Got carried away =P

cavedude 09-16-2008 11:00 AM

Quote:

Originally Posted by trevius (Post 156023)
Though, I have been seeing a considerably large amount of "world zone disconnects". Where it will send a message like that and then say it reconnected to all zones in use by each zone name. It doesn't actually cause a crash as long as you stay in the zone, but if you try to zone out, you get booted back to login. Then, if you login again you are fine, at least until it happens again. Currently it seems to happen every couple of hours.

PEQ has been seeing world disconnects for a long while now. Every 2 days or so world would decide to chain crash, like 3 or 4 times in a row. Then, it would be fine for a bit, and then start crashing again until the server was unplayable. My band-aid was to implement daily automatic reboots, which has prevented those crashes for the time being. At least I know I'm not going crazy and other people do have this problem!

James76 09-16-2008 12:06 PM

Well you're right, I didn't see his post about the perl script when I wrote mine. But I knew about the perl script and it wasn't hitting the perl event -- if it didn't get to call that Message_StringID(). I had to change my code to remove the single "if" statement because it wasn't ever going to get to the message if it was locked and you had no way of opening it.

So I went to Paineel, by creating an Erudite, I figured he'd get his newb key, nope. Had to look it up in the database. Key #6378 will open the elevator, and attaches to keyring properly. Key 6379 is the hole key, and adds to keyring too. Now I destroy both keys after using them, and he still can open those doors.

cavedude 09-16-2008 01:30 PM

Quote:

Originally Posted by James76 (Post 156032)
So I went to Paineel, by creating an Erudite, I figured he'd get his newb key, nope. Had to look it up in the database. Key #6378 will open the elevator, and attaches to keyring properly. Key 6379 is the hole key, and adds to keyring too. Now I destroy both keys after using them, and he still can open those doors.

Which DB and code revision are you using? New heretic Erudites start with their key fine on PEQ 1129a. They have for some time ever since starting_items was fixed in the code.

KLS 09-16-2008 10:37 PM

If people wanted to put together and test patches off of submitted stuff that'd help. I don't have the ability to add more people to SVN access so the options are kind of limited.

We could setup separate svn perhaps that more people have access to. And could move changes over to official every so often? It's not that I don't want to accept help it's just that the options are limited.

James76 09-16-2008 11:01 PM

Quote:

Originally Posted by cavedude (Post 156037)
Which DB and code revision are you using? New heretic Erudites start with their key fine on PEQ 1129a. They have for some time ever since starting_items was fixed in the code.

Using 1129, pretty sure its not 1129a. I see itemid 6378 in the starting_items table, where race=0 and class=0, deityid=0, zone=75. But I set the starting zone to tutorialb, because the tutorial button on character creation doesn't seem to do anything. I tried finding out why it doesn't work but the furthest I got was just to set starting zone for all characters. So maybe because the character was created in a zone where the zoneidnumber wasn't 75 is why I didn't get the key. Interesting bug.

James76 09-17-2008 06:39 PM

Quote:

Originally Posted by cavedude (Post 156037)
Which DB and code revision are you using? New heretic Erudites start with their key fine on PEQ 1129a. They have for some time ever since starting_items was fixed in the code.

Code:

update starting_items set zoneid=0, deityid=203 where id=178;
That should fix the DB to give all Erudites, with chosen deity of The Faceless, their key to Paineel. Any Erudite that starts in Paineel has to have this Deity, and I found that if you don't get to START in Paineel, such as starting in a tutorial, you don't get the key. Now you do.

cavedude 09-17-2008 08:05 PM

Thanks, it's already been done. I made the change as soon I realized what had happened.

As for getting the tutorial to work from character select, I think for that we may be missing an opcode. That's Derision's territory.

cavedude 09-20-2008 04:44 PM

keyring does indeed work great, I can confirm. I figured out what what wrong, I had missed sender->KeyRingAdd(playerkey); in doors.cpp.

I do have a request, is there anyway you can add perl support for keyrings? Specifically a variable like $haskey to check if a player has a given key on their keyring, and a function like quest::addkey(12345); to add a key? This will help with doors that open with multiple keys and are controlled via Perl.

ChaosSlayer 09-20-2008 04:57 PM

good point Cavedude.

There were some keys which were openign specific doors key and there were some master keys which could open any door in a dungeon which otherwise would requre a specific key

So_1337 09-20-2008 05:56 PM

Charasis was great for that. I put the key parts and combine in, and CaveDude rigged up the rest. It worked perfectly with both the single ground spawn keys and the master key opening the same doors. I'm sure that's one of the zones you have in mind.

Switching everything over to this new system should be very doable. Glad to hear it's working, great work!

James76 09-21-2008 03:16 AM

Not sure if I understand what you are asking. Does it currently work with multiple keys per door? I know that the perl flag/door system has a problem, it doesn't work 100% of the time, and I have no idea why. I can stand in PoI at the factory door and click it for 10 minutes, keeps telling me its locked, then it finally opens saying I got it open, but still says its locked.

If multiple keys per door does not work, then there should be an extra table to break keyitem out of the doors table. Remove field 'keyitem' from the doors table completely, after creating the new data.

create table keys(
door_id integer not null,
item_id integer not null
);

Then you insert into keys selecting from doors. Master keys would have multiple rows in keys table where the item_id is the same. The primary key for the table would be composite of both fields if we desired the constraint to make each row unique.

Then a simple change to some code, or even just make a view to the doors data to join the tables. Whatever, its pretty easy, and it doesn't have to go to ugly inconsistent perl.

So I don't know what doors use multiple keys to try this with... Does it already work or should I implement this change?

James76 09-21-2008 10:44 AM

Quote:

Originally Posted by cavedude (Post 156410)
keyring does indeed work great, I can confirm. I figured out what what wrong, I had missed sender->KeyRingAdd(playerkey); in doors.cpp.

I do have a request, is there anyway you can add perl support for keyrings? Specifically a variable like $haskey to check if a player has a given key on their keyring, and a function like quest::addkey(12345); to add a key? This will help with doors that open with multiple keys and are controlled via Perl.

KeyRing is a member of Client, and it doesn't make sense in an Object-Oriented mindset to give a method to Quest. Like I stated above, if we need the functionality to use multiple keys per door, or have a key per multiple doors, it would be best to push it straight to the database and minimize whatever goes through game scripting (ie, Perl). Just give the word and I'll put together a list of more changes. For your PEQ DB, I'll just make a script to build the data, and when you release your next PEQ download, you can just dump the table data into INSERT lines for your new DB system creation script to distribute.

cavedude 09-21-2008 02:02 PM

I'd rather see multiple keys in the DB, I only mentioned Perl because that's the only way a door can have multiple keys at present. Though, I am not sure about adding a new table. I can't think of any door that has 3 or more keys, so I believe we can get by with adding a second keyitem column to doors. keyitem2 I guess.

As for your problem with Perl controlled doors, try turning off your GM flag. I sometimes have the same problem, but when I turn my GM flag off it works every time.

James76 09-21-2008 02:22 PM

Quote:

Originally Posted by cavedude (Post 156478)
I'd rather see multiple keys in the DB, I only mentioned Perl because that's the only way a door can have multiple keys at present. Though, I am not sure about adding a new table. I can't think of any door that has 3 or more keys, so I believe we can get by with adding a second keyitem column to doors. keyitem2 I guess.

As for your problem with Perl controlled doors, try turning off your GM flag. I sometimes have the same problem, but when I turn my GM flag off it works every time.

Having the extra table would be a viable database solution, otherwise known as a transformation table. This fits better with a normalized database than adding an extra column. Having the extra column as you suggest would have compounded code to check the extra field, whereas with my suggestion we're using the same code to check for a key to work on the door. And like I said, we can just use a view if necessary to read multiple rows of the keys table onto one doors row.. But some doors may have 2 or 3 keys, so we'd need 3 fields? Then what if you need 4 keys? 4 fields? The best solution is just to have another table. Don't let it scare you -- in fact, many of the existing tables could really use some normalization, for both database optimization as well as database integrity. Usually any table with more than 4 columns would be better for the database to normalize it, which is the process of breaking a single table into many based on the kind of information they carry. Essentially break the table into many using some scripts, and then use a VIEW to the joined tables as if it was the original huge table, and you would be surprised by the performance boost. For really large enterprise-based databases this tactic is absolutely essential, by placing specific tables on their own devices (disk drives), usually in some RAID configuration as part of a cluster. Our largest table is Items, and by comparison its very small and hardly grows. But the idea is sound.

When I get a chance I'll do some analysis through the code and compare which would be easier. Going to be busy for this week though, so I probably won't get any time to implement anything until the 28th.

Also with having the extra table, you could create master game keys or master zone keys or anything you wanted, it would really simplify some aspects of custom servers.

cavedude 09-21-2008 03:20 PM

I'm merely concerned with ease of use. If I have a door that I want to change two keyitems, and lockpick I can do that all with one UPDATE query. Having the extra table would require an UPDATE and two INSERTS. Human error being what it is, I feel that's less efficient. VIEWS unfortunately are out, because they were added with MySQL 5.0. Many people are still using 4.0 here, which we still have full compatibility with. It's silly to remove compatibility with 4.0 when there is no real reason to.

James76 09-22-2008 02:38 AM

Quote:

Originally Posted by cavedude (Post 156485)
I'm merely concerned with ease of use. If I have a door that I want to change two keyitems, and lockpick I can do that all with one UPDATE query. Having the extra table would require an UPDATE and two INSERTS. Human error being what it is, I feel that's less efficient. VIEWS unfortunately are out, because they were added with MySQL 5.0. Many people are still using 4.0 here, which we still have full compatibility with. It's silly to remove compatibility with 4.0 when there is no real reason to.

Ah, I didn't realize people were still using MySQL 4. We don't need views anyway.

To counter your argument, adding an extra field would mean a table ALTER and an UPDATE, as opposed to a table CREATE, an INSERT, and an ALTER. For human error, they can screw anything up, no matter how simple it can get. Updating is riskier, if you can prove the insert worked correctly it is safer to alter the table and remove the field. Both require changes to code in 2 or 3 files. Its only another table; this is an improvement to schema. In both cases, because schema changed there would either be a drop and rebuild script for the next release, or a patch script. If you want to talk about ease of use maybe its better not doing it at all.

Would KLS like to chime in and make a decision for us? I personally don't care which way to go, I just feel its a more professional solution and better in the long run to have a keys transformation table. :cool:

AndMetal 09-22-2008 11:07 AM

Quote:

Originally Posted by James76 (Post 156553)
I personally don't care which way to go, I just feel its a more professional solution and better in the long run to have a keys transformation table. :cool:

I personally agree. What if you're running a custom server and want to have 50 different keys to work on a door? You don't want to have 50 additional columns, especially since most doors won't need something like that (can we say wasted space?) Yes, adding columns will work, and would be a feasible, short term solution, but it's not really the "best" way to do it.

As far as human error, that's why we have tools to help with the editing process. This could be done using PHP or a standalone tool *looks at GeorgeS*. It would be similar to loot tables, spawns, tradeskills, etc.

Anyway, just my 2cp...

cavedude 09-22-2008 12:37 PM

I have no problem in creating a new table in this case. The advantages outweigh the disadvantages. What I don't want is for this to become a trend. We can keep splitting tables off, but to what end? When PEQ comes back up, I have large update sql, that will create 9 or 10 new tables. When the adventure system goes in, that's another 4 tables at current development. The database is becoming bloated with system tables. The problem is, most of them are required, and make sense. But what about the ones that can be trimmed? Is it better to have 50 4 column tables, or 20 columns of varying length? Honestly, given the fact that EQEmu will gain very little if anything at all from normalization, I choose the later. None of our tables are even remotely close to being big enough to create a performance bottleneck.

cavedude 09-22-2008 01:12 PM

I just had a thought, we're going to need those Perl functions afterall for the doors with optional keys. Plane of Time is one example. Once alternate progression is put in, players can enter that zone with either a key OR a flag. That has to be handled by Perl. Unless you want to add a column to the table that says something along the lines of, this key is not required, however if they have it let them in and add it to their keyring.

James76 09-22-2008 01:37 PM

Quote:

Originally Posted by cavedude (Post 156584)
I just had a thought, we're going to need those Perl functions afterall for the doors with optional keys. Plane of Time is one example. Once alternate progression is put in, players can enter that zone with either a key OR a flag. That has to be handled by Perl. Unless you want to add a column to the table that says something along the lines of, this key is not required, however if they have it let them in and add it to their keyring.

If a player has a key then it won't get to the perl flag code, so nothing needs to change for that reason.

As for database tables, its not like we're going crazy and normalizing every 3 columns into its own table, this is a legitimate reason for a table. Its not uncommon for databases to have in excess of 100 tables. This is the only real solution, and it has the added benefit that it never has to get addressed again. If a case ever comes up in the future where 3 keys could be used, you won't have 99% of the rows with a null field where it only applies to one door. Even with 2 keys, it only applies to 0.1% of the doors, that hardly justifies its own column. This is my professional opinion.

cavedude 09-22-2008 01:59 PM

Quote:

Originally Posted by James76 (Post 156589)
If a player has a key then it won't get to the perl flag code, so nothing needs to change for that reason.

Edit: I agreed with you at first, but that's not right. Think about it, the door would REQUIRE the key to allow the player in. We need the key to be optional. In the current system if keyitem is filled in, then that key is required.

Quote:

Originally Posted by James76 (Post 156589)
As for database tables, its not like we're going crazy and normalizing every 3 columns into its own table, this is a legitimate reason for a table. Its not uncommon for databases to have in excess of 100 tables. This is the only real solution, and it has the added benefit that it never has to get addressed again. If a case ever comes up in the future where 3 keys could be used, you won't have 99% of the rows with a null field where it only applies to one door. Even with 2 keys, it only applies to 0.1% of the doors, that hardly justifies its own column. This is my professional opinion.

Yep I have no real problem with this new table, I can certainly get behind it.

James76 09-23-2008 01:31 AM

Quote:

Originally Posted by cavedude (Post 156593)
Edit: I agreed with you at first, but that's not right. Think about it, the door would REQUIRE the key to allow the player in. We need the key to be optional. In the current system if keyitem is filled in, then that key is required.

OK I did some further testing before posting... And back at the POI factory door, I decided to put a debug message in the code to tell me the key needed on the door so I wouldn't be mistaken. It defaults to 1, which is a nonexistent item. So I set it to 25755, rebooted the servers, and tried the door.

I found that "u"sing the door doesn't work when we talk about perl scripts for the quest lock, you actually have to click on the door. This should now be considered a known bug. And its telling me that the key required is 25755 but because of the perl code (and the fact I killed the mech dragon for the flag) its still letting me through.

And if I click low on the door it doesn't trigger the perl event for some weird reason. But every time I click above the 50% mark of the screen (at any angle) the event_clickdoor fires.

OK so then I created the key, and clicked low on the door so it wouldn't fire the perl script.. Door opens, added to keyring. Destroying key.. Now clicking high on the door to fire the perl event script.. And the door is opening and then closing because the script fires first and then the door code fires, but because the door is open it sets the door flag to close. So it opens and closes promptly in the same server's game iteration cycle, so you don't get to see it move at all.

So that's something to think about. I'm going to bed to ponder an elegant solution..

cavedude 09-23-2008 02:18 AM

Quote:

Originally Posted by James76 (Post 156642)
It defaults to 1, which is a nonexistent item. So I set it to 25755, rebooted the servers, and tried the door.

Setting keyitem to 1 is our ghetto way of permalocking a door. So, somebody without the flag cannot open the door.

Quote:

And its telling me that the key required is 25755 but because of the perl code (and the fact I killed the mech dragon for the flag) its still letting me through.
That's correct and intentional. quest::forcedooropen is doing exactly what it should do, open the door when called.

Quote:

And if I click low on the door it doesn't trigger the perl event for some weird reason. But every time I click above the 50% mark of the screen (at any angle) the event_clickdoor fires.
Strange indeed, but at least we have a repeatable procedure to recreate the problem.

Quote:

OK so then I created the key, and clicked low on the door so it wouldn't fire the perl script.. Door opens, added to keyring. Destroying key.. Now clicking high on the door to fire the perl event script.. And the door is opening and then closing because the script fires first and then the door code fires, but because the door is open it sets the door flag to close. So it opens and closes promptly in the same server's game iteration cycle, so you don't get to see it move at all.
Yep, I encountered this issue a while ago. What it comes down to is if a keyitem is set, the player has that key, and there is a Perl script further controlling the door, then it will not open visually. If the player doesn't have the keyitem (like in the case of permalocked 1), or keyitem is set to 0, then Perl will do whatever it needs to do correctly. In cases where we need a script on a door and it also has a keyitem, we set keyitem to 1, and have Perl check for the key. Of course, this key will not be added to the keyring.

ChaosSlayer 09-23-2008 02:58 AM

I am curious why Factory door has to be opened with any sort of script at all?

You kill Junk dragon, you hail the gnome and get the key.
Now you go click on the door and add it to the keyring- no script involved.

So_1337 09-23-2008 09:04 AM

That's not actually correct. You kill the dragon and the flag is what allows you to open the door. There isn't a physical key item for the door. There was one for a short time that dropped off the dragon, but only until KLS wrote the player.pl code and we were able to open doors via perl.

The way it is currently, controlled from perl, is all that's really needed. I don't even remember for sure if it was somehow indicated on your keyring if you had the ability to open the PoI door. All that happens is you click on the door and get the "three small turns to the left" message.


All times are GMT -4. The time now is 08:30 PM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.