Very Early in the works; this is a simple and easy to use Client Server oriented Networking system.
It will be entirely free for anyone to use it as per the terms of the MIT license.
The progress on the project can be followed on my github here.
There will be some dependencies for it to run, most importantly it will require a Google Cloud account as well as a Go Compiler.
It utilizes two third party Go Libraries the Julien Schmidt Router and nu7hatch's Go UUID generator.
Lastly it will require Hudell's "Orange Custom Event Creator" so be sure to give credit to Hudell as well.
Below is the theory on how it will run. If you don't like text blocks and just want to wait for the result then you can stop reading here. : )
Any questions?
It will be entirely free for anyone to use it as per the terms of the MIT license.
The progress on the project can be followed on my github here.
There will be some dependencies for it to run, most importantly it will require a Google Cloud account as well as a Go Compiler.
It utilizes two third party Go Libraries the Julien Schmidt Router and nu7hatch's Go UUID generator.
Lastly it will require Hudell's "Orange Custom Event Creator" so be sure to give credit to Hudell as well.
Metablob information is now able to be passed.
It is essentially an extremely volatile database. It doesn't hold onto information after the server shuts down. Storage, Retrieval, and Deletion is O(1) so you wont have to worry about speed bottlenecks outside of the request speed.
While entries can be overwritten they wont delete themselves. So if you are making one time throwaway data be sure to clean it up otherwise its a memory leak.
It is separated into levels.
"Owner" -> "Purpose" -> "Client" -> "PrimaryKey" -> "SecondaryKey" => StoredValue
It's a little overkill but the way it is intended to be used is as follows.
Owner: The plugin that is utilizing the Metablob.
Purpose: The given Function for which the plugin is using.(In case it may need multiple functions.)
Client: Typically the UUID of the client.
PrimaryKey: Arbitrary Key for primary categories of the client data
SecondaryKey: Client Sub-Catagories
The methods are as follows(the script will have nice ways of interfacing with them.)
GET
/MetaBlob/Get/:owner/:purpose/:client/:primarykey/:secondarykey
Returns the JSON representation of that level. You could for example leave out a field and it will print out the below levels. Note however that you can only see levels below. So you can't get data
on all Owners. This prevents multiple plugins from interfering with eachother.
POST
/MetaBlob/Post/:owner/:purpose/:client/:primarykey/:secondarykey/:input
Requires a fully formed key. Stores the value of input with the formed key to be retrieved later.
If the entry already exists it will simply overwrite it.
POST
/MetaBlob/Delete/:owner/:purpose/:client/:primarykey/:secondarykey
Wont break anything if the entry doesn't already exist. Deletes the entry from the server.
Like adding a value you can ommit a field to delete an entire section.
ie: /MetaBlob/Delete/:owner
will delete everything that your plugin is using.
ie: /MetaBlob/Delete/:owner/:purpose
will delete everything used by a part of your plugin like one time initialization data.
One last example to demonstrate how an actual call could be done.
/MetaBlob/Post/MegaABS/StatInfo/192we-183b2/BattleInfo/StatusRecieved/poisoned
Then when the ABS on someone else's game checks for it with
/MetaBlob/Get/MegaABS/StatInfo/192we-183b2/BattleInfo/StatusRecieved
they can verify that the player with that id is in fact poisoned.
Here are some of the other API calls available for the User(and not just the plugin itself.)
GET
/map/:mapid
Gets all the information of those logged into that map as a JSON object.
GET
/uuid/
Generates a UUID as plaintext. Mostly used by the plugin, however knowlege of it is good as knowledge of the player UUID will be needed for other plugins to interface with it. A player's UUID can also just be grabbed from the map data. On the plugin side there will be an easy way for grabbing the 'current player' UUID.
It is essentially an extremely volatile database. It doesn't hold onto information after the server shuts down. Storage, Retrieval, and Deletion is O(1) so you wont have to worry about speed bottlenecks outside of the request speed.
While entries can be overwritten they wont delete themselves. So if you are making one time throwaway data be sure to clean it up otherwise its a memory leak.
It is separated into levels.
"Owner" -> "Purpose" -> "Client" -> "PrimaryKey" -> "SecondaryKey" => StoredValue
It's a little overkill but the way it is intended to be used is as follows.
Owner: The plugin that is utilizing the Metablob.
Purpose: The given Function for which the plugin is using.(In case it may need multiple functions.)
Client: Typically the UUID of the client.
PrimaryKey: Arbitrary Key for primary categories of the client data
SecondaryKey: Client Sub-Catagories
The methods are as follows(the script will have nice ways of interfacing with them.)
GET
/MetaBlob/Get/:owner/:purpose/:client/:primarykey/:secondarykey
Returns the JSON representation of that level. You could for example leave out a field and it will print out the below levels. Note however that you can only see levels below. So you can't get data
on all Owners. This prevents multiple plugins from interfering with eachother.
POST
/MetaBlob/Post/:owner/:purpose/:client/:primarykey/:secondarykey/:input
Requires a fully formed key. Stores the value of input with the formed key to be retrieved later.
If the entry already exists it will simply overwrite it.
POST
/MetaBlob/Delete/:owner/:purpose/:client/:primarykey/:secondarykey
Wont break anything if the entry doesn't already exist. Deletes the entry from the server.
Like adding a value you can ommit a field to delete an entire section.
ie: /MetaBlob/Delete/:owner
will delete everything that your plugin is using.
ie: /MetaBlob/Delete/:owner/:purpose
will delete everything used by a part of your plugin like one time initialization data.
One last example to demonstrate how an actual call could be done.
/MetaBlob/Post/MegaABS/StatInfo/192we-183b2/BattleInfo/StatusRecieved/poisoned
Then when the ABS on someone else's game checks for it with
/MetaBlob/Get/MegaABS/StatInfo/192we-183b2/BattleInfo/StatusRecieved
they can verify that the player with that id is in fact poisoned.
Here are some of the other API calls available for the User(and not just the plugin itself.)
GET
/map/:mapid
Gets all the information of those logged into that map as a JSON object.
GET
/uuid/
Generates a UUID as plaintext. Mostly used by the plugin, however knowlege of it is good as knowledge of the player UUID will be needed for other plugins to interface with it. A player's UUID can also just be grabbed from the map data. On the plugin side there will be an easy way for grabbing the 'current player' UUID.
The interface for variable and switch consistency is done.
GET
/switches/
Returns a JSON representation of the switches.
GET
/variables/
Returns a JSON representation of the variables.
POST
/switches/:id/:value
Sets the switch id to the value. Can only write to existing keys.
POST
/variables/:id/:value
Sets the variable id to the value. Can only write to existing keys.
In addition if they aren't initialized and any of them are called then they will be loaded from JSON objects in
files/Switches.ini
and
files/Variables.ini
and example object can look like so
{
"1":true,
"2":false,
"4":true
}
Manually going to to retrieval sections will give you the JSON objects in the correct form if you wanted to manually update your files.
I have included a separate program that can be run to automatically update the files so the user doesn't have to. (It'd be a shame for players to lose their progress right?)
GET
/switches/
Returns a JSON representation of the switches.
GET
/variables/
Returns a JSON representation of the variables.
POST
/switches/:id/:value
Sets the switch id to the value. Can only write to existing keys.
POST
/variables/:id/:value
Sets the variable id to the value. Can only write to existing keys.
In addition if they aren't initialized and any of them are called then they will be loaded from JSON objects in
files/Switches.ini
and
files/Variables.ini
and example object can look like so
{
"1":true,
"2":false,
"4":true
}
Manually going to to retrieval sections will give you the JSON objects in the correct form if you wanted to manually update your files.
I have included a separate program that can be run to automatically update the files so the user doesn't have to. (It'd be a shame for players to lose their progress right?)
I made one hell of an AJAX function. For those interested here's the code...
Basically give it up to two objects as settings. It is about as powerful and flexible as the JQuery ajax function(atleast for common usage) but without the slowdown that JQuery is known for. I'm rather proud of it. : )
JavaScript:
ajax = function(req,res){
if(res === undefined){ res = {}; } // If no response specified then make an empty object.
if(req["url"] === undefined){ req["method"] = "/"; } // If no URL specified default to relative location.
if(req["method"] === undefined){ req["method"] = "GET"; } // If no method set assume GET.
if(req["send"] === undefined){ req["send"] = ""; } // If no send set assume empty.
if(req["async"] === undefined){ req["async"] = true; } // If not specified then assume asynchronous.
var xhttp = new XMLHttpRequest(); // Open XML HTTP Request
if(res != '{}'){ // Is a response set?
xhttp.onreadystatechange = function() { // When ready...
if (xhttp.readyState == 4 && xhttp.status == 200) {
// If it exists tie the response text into an object.
if(res["ret"] !== undefined){ res["ret"].ret = xhttp.responseText; }
// If parameters weren't specified default to an empty array.
if(res["parameters"] === undefined){ res["parameters"] = []; }
// If a callback was specified then execute it with optional parameters.
if(res["callback"] !== undefined){ res["callback"].apply({},[xhttp.responseText].concat(res["parameters"])); }
}
}
}
// Make the request.
xhttp.open(req["method"], req["url"], req["async"]);
xhttp.send(req["send"]);
};
A Client will need atleast 0.3kb/s download speed.
A Free Appengine project will only support about 35 people per day. (due to the 1GB free quota.)
Each additional gigabyte in a billed project will add about another 35 people. Though that's about $3.70 a month extra per additional gigabyte which can get pretty expensive.
For this reason I'll make an appengine independent server as well for use with dedicated servers. But for the time being appengine will be used for the shorter development cycles it provides.
A Free Appengine project will only support about 35 people per day. (due to the 1GB free quota.)
Each additional gigabyte in a billed project will add about another 35 people. Though that's about $3.70 a month extra per additional gigabyte which can get pretty expensive.
For this reason I'll make an appengine independent server as well for use with dedicated servers. But for the time being appengine will be used for the shorter development cycles it provides.
There are three participants in the Network: The Clients, The Host, and the Go Server.
The Host is the 'True Simulation.' Any switches or variables set as 'shared' will have their state tied to the host. If a client's switch does not match up to the Host's then the client's switch is forced to conform to the Host's.
However any data that isn't 'shared' is local data.
Very likely the Host will be integrated as part of the server itself. If I can make an admin friendly way of handling the shared resources. Then the host simulation wont be needed.
The Clients are the players plain and simple. They will be capable of seeing each other but the script wont give a direct way of having them interact outside of the Host Simulation. Instead a 'metablob' will be passed along as simulation data. Script designers can send whatever data they want over the arbitrary 'metablob handler' which can be parsed to handle things such as PvP Battle Systems or otherwise. I chose metablob because it sounds funnier than "string" and makes it distinctive from the rest of the system.
The system is usernameless and passwordless as its based off the gamedata of the client; though I may add facilities for user authentication in the future with a secondary UUID in order to prevent account stealing through catching the GET requests.
Players are given distinct identities through a UUID, this UUID is only relevant during the game session.
This system is taking advantage of the fact that MV is javascript based and can make AJAX requests. AJAX will be used to speak with the Go Server.
The Host is the 'True Simulation.' Any switches or variables set as 'shared' will have their state tied to the host. If a client's switch does not match up to the Host's then the client's switch is forced to conform to the Host's.
However any data that isn't 'shared' is local data.
Very likely the Host will be integrated as part of the server itself. If I can make an admin friendly way of handling the shared resources. Then the host simulation wont be needed.
The Clients are the players plain and simple. They will be capable of seeing each other but the script wont give a direct way of having them interact outside of the Host Simulation. Instead a 'metablob' will be passed along as simulation data. Script designers can send whatever data they want over the arbitrary 'metablob handler' which can be parsed to handle things such as PvP Battle Systems or otherwise. I chose metablob because it sounds funnier than "string" and makes it distinctive from the rest of the system.
The system is usernameless and passwordless as its based off the gamedata of the client; though I may add facilities for user authentication in the future with a secondary UUID in order to prevent account stealing through catching the GET requests.
Players are given distinct identities through a UUID, this UUID is only relevant during the game session.
This system is taking advantage of the fact that MV is javascript based and can make AJAX requests. AJAX will be used to speak with the Go Server.
Any questions?
Last edited: