*discontinued* MOTDPlayer

Custom Packages that plugins can require for common usages.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

*discontinued* MOTDPlayer

Postby iPlayer » Sun Apr 24, 2016 9:39 pm

DISCONTINUED
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.
Last edited by iPlayer on Mon Apr 10, 2017 6:24 pm, edited 4 times in total.
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Re: MOTDPlayer

Postby BackRaw » Mon Apr 25, 2016 9:27 am

Didn't test this yet, but looking at the video... man this is awesome! :D
Does it work with CSGO aswell?
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Re: MOTDPlayer

Postby iPlayer » Mon Apr 25, 2016 9:56 am

Yes, it uses a hack to make MoTD work in CS:GO.

You can watch CS:GO version of that:
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
your-name-here
Developer
Posts: 168
Joined: Sat Jul 07, 2012 1:58 am

Re: MOTDPlayer

Postby your-name-here » Thu Apr 28, 2016 12:31 am

Absolutely lost my mind at this. What an incredible piece of software you've created!
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Re: MOTDPlayer

Postby iPlayer » Thu Apr 28, 2016 1:19 am

Thanks! I appreciate it
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
Predz
Senior Member
Posts: 158
Joined: Wed Aug 08, 2012 9:05 pm
Location: Bristol, United Kingdom

Re: MOTDPlayer

Postby Predz » Thu Apr 28, 2016 8:17 am

iPlayer, great thanks for putting the effort into this project! :)

I am planning to use this for a few of my plugins if that is okay? I have a few people to help me design some neat GUI for this so I will give you a glimpse of it soon. Just getting used to how Flask interacts at the moment, whilst the others work on the HTML layouts, hehe.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Re: MOTDPlayer

Postby iPlayer » Thu Apr 28, 2016 9:03 am

Hey Predz, of course it's okay to use it, that's why I published this. If you need any help, be sure to add me on Steam (link in my signature), and I'll build a FAQ based on your questions.
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image

Return to “Custom Packages”

Who is online

Users browsing this forum: No registered users and 3 guests