Download 22.2KB zip
The idea is that when you "start" a connection, it "compiles" the scripts into a single object and creates an instance of it. This takes the pain of writing switch blocks away from the programmer. I will be working on the current setup, but I would really appreciate any ideas/thoughts/comments/opinions/whatever.
I will still be supporting the other version, but no major updates will be done to it (only fixing errors).
Download 55KB gml
I apologize if this does not work. Ever since WHFF dropped, I had to sort through all my files, and unfortunately I was in the process of upgrading this to the next version and was not finished. I wrapped up as much as I could, hopefully it still works. Please report any errors, thank you.
mp_init(DLLFilename) - call this first once. It will check if you've already called it, but it's bad programming practice calling init functions more than once.
mp_free() - call this at the closing of your game.
These create a database map either new or loaded from a file. It returns the 'dbID' used in other functions.db_save(dbID, filename)
The first saves a database to a file, the second destroys the 'dbID' map, freeing up memory.db_entry_new(dbID, name, md5password)
This creates an entry in the database. 'md5password' must be the hash of the password, not the password itself because communications will never know the password ahead of time. It will return 0 if 'name' is already in database, 1 if successful entry.db_entry_remove(dbID, name)
Removes name from database, returns 0 if name wasn't found, 1 if successful.db_entry_get_md5(dbID, name)
Returns the 'md5password' corresponding to 'name' in the database, or an empty string ("") if 'name' not founddb_entry_get_uid(dbID, name)
When using db_entry_new, it creates a 16 byte random and unique ID based on files, although I need to update this to check the database itself...haven't had time. This was to be used in creating player extension files to be able to store extra information (like location, equipment, whatever is needed to be saved on server-side for the player). Returns an empty string ("") if 'name' not found.BetterINI
These functions were created to be able to open ini files in any directory, not just the game directory. They mimic the regular built-in ini functions. You will need to use 'bini_init()' after 'mp_init()' has been called, because it uses some of the functions included with 39dll to operate, here's the list:
bini_init() - initialize
bini_new() - clear current INI cache
bini_load(filename) - load file to cache (clearing if needed)
bini_save(filename) - save current cache to file
bini_write(section, key, value) - write a key, or overwrite
bini_read(section, key, default, setit) - read a key, default if not there (if 'setit' is true, it will do a bini_write with default if needed)
bini_section_exists(section) - returns if 'section' exists
bini_section_delete(section) - deletes 'section'
bini_key_exists(section, key) - returns if key exists
bini_key_delete(section, key) - deletes key
mp_server_create(Port, dbID, pObject)
Placed in one object's specific events to perform login services. 'Port' is the listening port for incoming connection requests. 'dbID' is the database used for authentication purposes, put '-1' if you want no authentication. 'pObject's are created and assigned a socket ID automatically, the 'pObject' should contain the next set of functions. If 'create' returns 1, there was a problem (and object will automatically be destroyed at end of script)mp_player_create()
These functions initialize and control the incoming and outgoing transmissions on the specific client connections. To save network space and time, I have made the data buffer before sending, so that it sends in one shot instead of several smaller ones. 'bufferleft' variable is used to determine how much data is left on the incoming transmission (all 'read' message functions automatically drop this value as needed). If 'mp_player_step' returns a '1', you can break out of your script because there's nothing to read.mp_player_sendmessage(pObjectInstanceID)
All 'write' message functions currently write to the default buffer. Calling this function will copy the current data on the default buffer to the specific clients buffer for them. The default buffer is cleared afterward.Groups
Other than sending messages to a specific client, you can also set up groups and allow messages to several people at the same time based on a commonality. You can put people in "zone" groups and have their positions registered to their specified 'zone' so that someone in a different 'zone' will not get the message. You can put people in "channels" and allow communications...etc. etc. Most functions applies to the object it is contained in, you will need to use "with" in order to target a different client.
Each player is allowed to be in only 1 of each group, and each group can have several subgroups. Placing players in a different subgroup will automatically degroup them from the other subgroup. This function creates the actual groups. For example: mp_group_add("Zones", 100) - creates a group named "Zones" numbered 0 to 99. Returns 1 if 'GroupName' already exists.mp_group_find(GroupName)
Returns '-1' if not found, otherwise it is an index of an array used by other functions. It is best not to directly affect this return or the array itself, simply checking if the return is '-1' should be sufficient.mp_group_player_add(GroupName, Subgroup)
Puts player in 'GroupName', moving him to 'Subgroup'. Returns: '-4' if 'GroupName' isn't found, '-3' if 'Subgroup' is out-of-range, '-2' if player is already in the group, '-1' if player joined the group for first time, otherwise the number of last subgroup player was in.mp_group_player_remove(GroupName)
Removes player from 'GroupName', doesn't matter what subgroup they are in. Returns: '-2' if 'GroupName' was not found, '-1' if not in 'GroupName' at all, or a number of subgroup player was removed from.mp_group_sendmessage(GroupName, Subgroup)
This copies the current default buffer into all clients currently in the specified Group/Subgroup. It clears the default buffer when finished.Client
mp_login_create(Host, Port, Name, Password, cObject)
These are placed in a single object on the client-side to connect to a specified 'Host' and 'Port'. It uses 'Name' and 'Password' for authentication purposes (use empty strings if no authentication required). 'cObject' is created upon successful login and should contain the next set of functions. 'mp_login_create' returns 1 if there was a problem, and 'mp_login_step' returns a number 0-4 depending on situation (0=success, 1=problem finding server, 2=handshake problem or bad name/pass, 3=disc or time out, 4=no servermp_client_create()
Same as 'mp_player_*' functions but this is client-side. It controls the incoming and outgoing buffer transmissions and also uses 'bufferleft' for your convenience. It also returns '1' from 'mp_client_step' if you should break out of your script because there's no data to read.mp_client_sendmessage()
Since client-side does not use groups or several client connections, it has a single communication point, this is how to send messages to the server. Simply 'write' your info, then call this function to copy to the outgoing buffer. This will clear the default buffer just like the other 2 'sendmessage' functions.mp_id_me(sID)
These functions are quick convenience to map the server's ID points 'sID' to the client's created objects 'oObject'. You have the server send a code and ID for each player, and each player uses 'mp_id_me' to map the ID to themselves. 'mp_id_translate' returns either '-2' to identify that specific client, '-1' if not in map, or the instance of the oObject ID on that specific client. 'mp_id_new' creates a new 'oObject' and assigns the 'sID' to it.Messages
All the messages are similar to the ones from 39ster's functionality, but I will go over briefly the one's I created.
When using an authenticated login, a 16 byte crypto key is created between the connections. In order to increase the key size, simply call these functions in unison to create the key, either side can start the increase with 'mp_key_increase_write', and the other side must use the 'mp_key_increase_read' function. Each time these functions are called in combination, the key increases by 16 bytes.readsecret()
This is where the crypto key comes in, these 2 functions write/read a string that is encrypted/decrypted. All other message functions are open. CAUTION: Using these sparingly is ok, but overly using the encryption can compromise not only the crypt key but your login ID and md5 hash password.Internal
These are functions used by the other ones and should not be called directly at all.
These are the functions from 39ster's script file, modified slightly. Using these can be devistating to the other functions if you do not know what you are doing. I placed them here because some of my functions do use them, and just in case anyone needs to still use the others.
I have altered the authentication system as such:
Client requests connection
Client sends name in plain text
Server finds name in database along with md5password. Server creates a random 16 byte cypher 'SeqA' and xors it with the md5password. If name is not in database, it sends a random 16 byte cypher anyway to stall.
Client takes the data and xors it with the md5hash of the password client provided, which should yield 'SeqA' if client put the right password in. Client then sends the md5hash of (SeqA + md5password) which is a 32byte to 16 byte one-way compression.
Server receives this and checks it against the real md5hash of (SeqA+md5password). If name was not in database or the check was unsuccessful, client is dropped...otherwise 'SeqA' is used for the crypto and Server and Client successfully authenticate.
Let me know what you think, ideas, if you break the scheme, etc.
Edited by sabriath, 07 November 2011 - 04:51 AM.