This is an old version of MOTDPlayer which is replaced by a brand new MOTDPlayer v2
MOTDPlayer Package
by Kirill "iPlayer" Mysnik
What's this?
As some of you may know, the purpose of this package is to connect in-game MoTD screens to the server software, allowing scripters, for example, receive information from MoTD page when player clicks something inside of it, and send information back to render in MoTD.
Model
As I discussed in SRCDS integration with the webserver thread, there're several possible ways to approach such cooperation between Source Dedicated Server and web-pages that it sends through MoTD. I went with the following model:
SRCDS ↔ Web-server with WSGI and Flask framework ↔ MoTD
This model requires opening an extra TCP port on SRCDS for communication with the web-server, but at the same time, you can hide this port from the internet and only make web-server's port visible, so it's pretty much secure. Additionally, even if your web-server and SRCDS happen to be hosted on different networks and the only way to connect them together is over internet, MOTDPlayer Package is still able to provide you some-what protection by dropping all connections that are coming from non-whitelisted hosts. By default this whitelist looks like localhost,127.0.0.1.
However, this model, along with all other models in the mentioned thread, pushes some serious requirements. This particular model requires you to host a web-server. Not every game hosting allows that. What is more, it requires opening another port on SRCDS and I've never heard of the game hosting that will allow THAT. So the package usage is very restricted at the moment, but at the same time, it opens very powerful opportunities. Regular shared hosted server won't be able to afford this package. Maybe some gaming networks will.
Example
Just to make sure you realize how powerful said opportunities are, I give you a link to ArcRPG inventory/stats demo video. Some of you have already seen it.
Installation
SRCDS
1. Install latest Source.Python
2. Install its NewPerms branch over it as we need SQLAlchemy lib and GameThread class
3. Copy contents of the srcds folder from the latest MOTDPlayer release archive to your mod directory (e.g. "cstrike").
4. Go to addons/source-python/data/custom/motdplayer/config.ini. It should look something like this:
Code: Select all
[server]
id=my_server01
host=
port=28080
whitelist=127.0.0.1,localhost
[database]
uri=sqlite:///{motdplayer_data_path}/user_personal_salts.db
[motd]
url=http://127.0.0.1:5000/{server_id}/{plugin_id}/{page_id}/{steamid}/{auth_method}/{auth_token}/{session_id}/
url_csgo=http://127.0.0.1:5000/csgo/{server_id}/{plugin_id}/{page_id}/{steamid}/{auth_method}/{auth_token}/{session_id}/
There you only need replace 127.0.0.1:5000 with the address/port that your web-server will run on.
Web-Server
1. If you run Apache, install mod-wsgi. If you run nginx, install uWSGI.
2. Install Flask and Flask-SQLAlchemy
3. Copy contents of the flask folder from the archive to your flask folder on the web-server, contents of the flask-static folder to your flask static folder and flask-templates folder to your flask templates folder.
4. Go to <your flask directory>/motdplayer/data/config.ini. It should look something like this:
Code: Select all
[srcds]
host=127.0.0.1
port=28080
[application]
base_route=/{server_id}/{plugin_id}/{page_id}/<int:steamid>/<int:auth_method>/<auth_token>/<int:session_id>/
base_route_with_auth_method=/{server_id}/{plugin_id}/{page_id}/<int:steamid>/{auth_method}/<auth_token>/<int:session_id>/
csgo_redirect_from=/csgo/<server_id>/<plugin_id>/<page_id>/<int:steamid>/<int:auth_method>/<auth_token>/<int:session_id>/
csgo_redirect_to=/{server_id}/{plugin_id}/{page_id}/{steamid}/{auth_method}/{auth_token}/{session_id}/
retarget_url=/json/retarget/<server_id>/<plugin_id>/<new_page_id>/<page_id>/<int:steamid>/<int:auth_method>/<auth_token>/<int:session_id>/
The only thing to change here is 127.0.0.1 – this should be the IP of your SRCDS. Note that you don't change 28080 as it's not game port, it's MOTDPlayer communication port.
After you have loaded any plugin that uses the package for the first time
Before the first run, go to addons/source-python/data/custom/motdplayer/config.ini and copy server_salt.dat from your SRCDS directory to <your flask directory>/motdplayer/data/server_salts and rename it to look like <server_id>.dat, by default it should look like my_server01.dat.
The file is only created the first time MOTDPlayer package is loaded. Be sure to keep this file safe. If you leak it, players might be able to successfully open MoTD pages they shouldn't be able to open, e.g. administration panel of your server. If you leak it, remove it from SRCDS folder and it will be recreated, then copy it to web-server once again.
How to use it in your plugin
SRCDS
Syntax: Select all
from filters.players import PlayerIter
from motdplayer.plugin_instance import PluginInstance
# Create a PluginInstance object that will serve pages for your plugin
plugin_instance = PluginInstance("my_plugin") # Use your plugin basename
# Let's obtain a Player entity for testing purposes
for player in PlayerIter('human'):
break
else:
raise RuntimeError("No human players")
# Define a data exchanging callback – it will receive data from web-server
def page01_callback(data, error):
if error is not None: # Error is either None or a string
return
# data is just a dictionary
attr_to_get = data.get('attr_to_get', "name")
attr_value = getattr(player, attr_to_get)
# Note how easily we can pass any JSONable data
return {
'value': attr_value,
}
# Send a MoTD page to a player
plugin_instance.send_page(player, 'page01', page01_callback)
Web-server
Syntax: Select all
from flask import Flask, render_template
from flask.ext.sqlalchemy import SQLAlchemy
# Create Flask object
app = Flask(__name__)
# Database object
db = SQLAlchemy(app)
import motdplayer
# Initialize MOTDPlayer with the application and database objects
motdplayer.init(app, db)
# Only after that create your tables
db.create_all()
db.session.commit()
# Now import PluginInstance - only now!
from motdplayer.plugin_instance import PluginInstance
# Create a PluginInstance object that will serve pages for this particular
# SRCDS server for your particular plugin
plugin_instance = PluginInstance(app, "my_server01", "my_plugin")
# Define a view for page01
@plugin_instance.base_authed_request('page01')
def route_page01(steamid, web_auth_token, session_id, data_exchanger, error):
"""
steamid -- CommunityID for the player that we're serving
We know it's him, all auth checks were done in the background
web_auth_token -- auth token we will use for any succeeding requests
E.g. to make a AJAX request from this MoTD page, you'll need this token
session_id -- session ID, also needed to form an URL to make further
requests
data_exchanger -- CustomDataExchanger instance, used to send and receive
data to and from SRCDS. Every time you send data, you receive data.
And every time we do this, page01_callback will be called in your
SP plugin.
error -- either None or a string with the error message.
Just give up if it's not None.
"""
# So, first things first, check the error
if error is not None:
return render_template("error.html", error_msg=error)
# Now let's talk to that page01_callback
data = data_exchanger.exchange({
'attr_to_get': "speed",
})
# Yay, now we've got player speed
speed = data.get('value', 0)
# Render HTML
return render_template("player_info.html", speed=speed)
This the easiest of the possible applications. Real MOTDPlayer application assumes you will use Ajax to communicate with the webserver, thus there's modplayer.js included in the package.
Why so complicated?
The main idea behind this package is to ensure:
1. Random user from the web can't pretend to be a player on your server
2. Player on your server can't pretend to be another player on your server
3. Having valid URL for one plugin/page, you can't access MoTD for another plugin or page
4. Once having valid URL for the page, you won't be able to access it ever again - even pressing F5 in-game will fail, you'll get an error - SRCDS plugin will need to use send_page every time you want to visit the page
5. If you work on page A and want to go on page B, SRCDS will need to confirm such action. This is what I called retargeting - basically, apart from page01_callback, you define page01_retargeting_callback and pass it along to send_page.
6. Single Web-server can serve multiple SRCDS servers and multiple plugins on each server
Full documentation coming soon - if any of you guys is actually interested.
GitHub: KirillMysnik/sp-motdplayer-package
Thanks.