components

Want to discuss changes to the UOX3 source code? Got a code-snippet you'd like to post? Anything related to coding/programming goes here!
Post Reply
punt
VIP
Posts: 244
Joined: Wed Mar 24, 2004 7:46 pm
Has thanked: 0
Been thanked: 9 times

components

Post by punt »

Ok, almost up to coding, so dabbled a little with a few more components.

I looked over accounts, and came up with the following:

1. There is no need for accounts to be in memory. It is only checked by the login thread when accessed (so a disk access at time of check is fine).

2. Online accounts do need to be "known". These status can be in memory or not (with appropriate thread locks).

3. There isn't a great advantage to use the Packet/Socket classes for the login sequence. A matter of convience (not saying not to use, just noting it isn't really a agreat advantage).
4. Any approach, should have virtual methods, encouraging other implementations (database, etc) without having to do code changes (just change where the class is created, and subitute the new class that is inherited from the base).



Ok, given that, I felt the following made sense:

An Online class that has the following:

Code: Select all

class Online
{
public:
	Online();
	virtual ~Online() ;
	virtual bool find(UString,online_account&) ;
	virtual bool remove(UString) ;
	virtual bool update(UString,online_account&) ;
protected:
	std::list<online_account> Accounts ;
	PRLock* lock ;

};

This is the class that can holds online accounts, and is accessed to retieve the information. The implemenation can be easily changed to whatever (sharable memory, etc). It currently just uses a list.

Login

Code: Select all

class Login
{
public:
    Login();
    virtual ~Login();
    virtual bool create(UString account,UString pwd,enpriv=enNormal) ;
    virtual  enCode valid(UString account,UString pwd) ;
    virtual bool character(UString account,std::vector<UString>&) ;
    virtual bool delChar(Ustring account,UString character) ;
     virtual bool remove(UString account) ;
}

Lastely, I have a class, Gateway, which opens the Server, socket, and implements the loging protocool (and is run via a thread). It instantiates these. So if one now wants to change the login implemenation, just inherit from the class, make your own class, and change the "new" where login/online is made.

Now, why I didn't do the Packet class/Socket class in the login. This uses the NSPR socket implemenation, and wasn't ready to tackle that conversion. After this is complete, that seem to be the next thing to do.

Anyway, open to thoughts.
Maarc
Developer
Posts: 576
Joined: Sat Mar 27, 2004 6:22 am
Location: Fleet, UK
Has thanked: 0
Been thanked: 0
Contact:

Post by Maarc »

I can understand why you didn't use the socket/packet class implementation, it really is just a small sequence. It was only done originally for consistency, more than anything, and to try and figure out what is really sent in a login (as more packets were handled than what was really sent).

I agree that accounts don't need to be in memory all the time, but I don't think the memory utilisation is that big a hit. It will add up, of course, as the number of accounts increases. But compared to the number of characters or number of items, it's relatively small fry.

From what I can see, I think you've covered pretty much everything for the login/online account purposes. There's nothing missing that I see, anyway. Though I do wonder about the Login class, the valid() method. Why is it returning an enCode? Shouldn't it return a bool? Though perhaps I'm missing something. However, I'm not sure what's actually in online_account. Does that contain information such as last registered activity and so on? Otherwise, Login may (or may not) have to care about when the account did anything, and whether it should be logged out or not. Just a thought.

I haven't seen all the threads, so I cannot be sure whether this has been discussed or not. But this, combined with your ideas of a Console class which might be a separate process, I had some ideas the other day during a break at Uni. It's a similar vein, and (I think) only takes the ideas you've suggested a bit further. But if it is offtopic and irrelevant to you, then feel free to ignore. Just some thoughts I've had, nothing too deep.

=================

ScriptManager
  • Manages executable scripts - loading, unloading, exposure to script objects
    Each script is a "package" - defines type, name, code, other details
DefinitionManager
  • Manages data definitions - dictionaries, existing DFNs, exposes ScriptSections
    Responsible for loading/unloading and searching of data
AccountManager
  • Manages account information - similar responsibilities to above, stores current account state
LoginManager
  • Responsible for listening to and responding to login attempts
StateManager
  • Stores world state - towns, guilds, chars/items, multis and so on
ConsoleManager
  • More transparent than the others - responsible for display and retrieval of input/ouput to the admin
Consider the idea of message pump/queue/shared memory socket for each manager. Most, excepting ConsoleManager, would be implementation specific and opaque to the core systems. Could push all packet handling onto some sort of queue, rather than taking them one at a time as we do now. Maybe a list of queues, one for each socket, but stored under one access method.

Idea: Initial implementation would be the *same* as now - secondary implementation (optional based on compile) could be DB specific / seperate threads / seperate processes

Roll AccountManager and LoginManager together? Similar details/information

=====================

The AccountManager / LoginManager tends to coincide with what you've done.
punt
VIP
Posts: 244
Joined: Wed Mar 24, 2004 7:46 pm
Has thanked: 0
Been thanked: 9 times

Post by punt »

Maarc wrote:I can understand why you didn't use the socket/packet class implementation, it really is just a small sequence. It was only done originally for consistency, more than anything, and to try and figure out what is really sent in a login (as more packets were handled than what was really sent).
The only reason I didn't use it yet, was Ihadn't tackled converting over the Socket class and what not to NSPR use of sockets. So since it didn't buy a lot, and let me tackle that at one time, I deferred it.

I agree that accounts don't need to be in memory all the time, but I don't think the memory utilisation is that big a hit. It will add up, of course, as the number of accounts increases. But compared to the number of characters or number of items, it's relatively small fry.
it wasn't the memory utilization I was after (although if you have 2000 accounts,and only 20 active...). It was the syncronization aspect. Say you want to add an account. Just add the entry. There is no "loading" of accounts needed. It just removes complexity that wasn't buying anything (performance, usage, etc).

From what I can see, I think you've covered pretty much everything for the login/online account purposes. There's nothing missing that I see, anyway. Though I do wonder about the Login class, the valid() method. Why is it returning an enCode? Shouldn't it return a bool?
I had bool, but changed to enCode. Figured it would need to return a few states (account not present, present but invalid pwd, valid but logged on, etc).
Though perhaps I'm missing something. However, I'm not sure what's actually in online_account. Does that contain information such as last registered activity and so on? Otherwise, Login may (or may not) have to care about when the account did anything, and whether it should be logged out or not. Just a thought.
online_account is the structure to pass the minimimum amount of information between the two threads (mainly accessed by the Login on). It has the account name, character name, time of login, account priv, character priv, NSPR socket handle, and state. It can easily expand, but that is all I think login needs.
I haven't seen all the threads, so I cannot be sure whether this has been discussed or not. But this, combined with your ideas of a Console class which might be a separate process, I had some ideas the other day during a break at Uni. It's a similar vein, and (I think) only takes the ideas you've suggested a bit further. But if it is offtopic and irrelevant to you, then feel free to ignore. Just some thoughts I've had, nothing too deep.
Nothing I consider offtopic. Looking for input, regardless of the specific area.
=================

ScriptManager
  • Manages executable scripts - loading, unloading, exposure to script objects
    Each script is a "package" - defines type, name, code, other details

DefinitionManager
  • Manages data definitions - dictionaries, existing DFNs, exposes ScriptSections
    Responsible for loading/unloading and searching of data
So is this like my scpparser, secstore, multisect class? Covered in "Hope to continue" thread I think.
AccountManager
  • Manages account information - similar responsibilities to above, stores current account state
LoginManager
  • Responsible for listening to and responding to login attempts
Ok, so this is the classes described above
StateManager
  • Stores world state - towns, guilds, chars/items, multis and so on
ConsoleManager
  • More transparent than the others - responsible for display and retrieval of input/ouput to the admin
Sounds reasonable. I would have to think more on StateManager, especialy concerinng chars/items and how that expands.
Consider the idea of message pump/queue/shared memory socket for each manager. Most, excepting ConsoleManager, would be implementation specific and opaque to the core systems. Could push all packet handling onto some sort of queue, rather than taking them one at a time as we do now. Maybe a list of queues, one for each socket, but stored under one access method.
What I have been trying to do, is get the class structure setup, with the appropriate virtual methods. The goal is that one can then do a "simple" implementation initially, and later, subclass it, with a more specific/involved implementation, without impact to the rest of the system. One thing I think the current code base does not afford. Take accounts for instance. To go to database, one just subclasses, and changes the virtual methods. Seems one could do the same for the managers as well.
Idea: Initial implementation would be the *same* as now - secondary implementation (optional based on compile) could be DB specific / seperate threads / seperate processes
That fits in what I stated above, I think.
Roll AccountManager and LoginManager together? Similar details/information
Well, there are I think three classes, but they use each other. One tomanage the socket/interface. One to manage validation of accounts, character listsing, and one to interface tothe system on the online state. But yes, I think conceptually we are stating the same thing.

Look at the other threads, and see if the scpparser, secstore, and setmulti don't fit some of the other ones as well.
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

I would agree with keeping accounts out of memory for synchronization simplicity. Perhaps an indexing could be done of the accounts file at startup, which creates a file offset for each account name, which is then kept in memory. Upon login, the server could jump straight to this location and just read the account information from that point forward.

If the account name at the offset does not exactly match the one in the index list, the index list could then be rebuilt. This would all be transparent to the user, but would eliminate a lot of processing when someone logs in on a very account-laden server.

Just a spur-of-the-moment thought.
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

I suppose it would also have to be rebuilt whenever someone enters an invalid login name… but that would take no more time than iterating through the file anyway (in fact, it could take less).
Sydius
UOX3 Apprentice
Posts: 171
Joined: Thu Mar 25, 2004 3:22 am
Has thanked: 0
Been thanked: 0

Post by Sydius »

Another thought: you could just query the last time the file was modified and rebuild if it doesn’t match. You would still want to check the username for matching, though, in case of some odd-ball weirdness happening.

Question: how platform-dependent is file last modified? That would be the primary drawback to doing this.
Post Reply