Welcome to piqueserver’s documentation!¶
Piqueserver is an Ace of Spades 0.75 Server based on Pysnip.
Installation¶
Note
piqueserver only supports python 3.7 and above
All platforms¶
Installing with pip¶
pip3 install piqueserver # vanilla install
pip3 install piqueserver[ssh] # if you also want ssh server
Unix-like¶
Installing from source¶
# required for https, pillow, map compression etc.
# these are for ubuntu 16.04, find similar packages for your own distro/OSs
sudo apt-get install python3-dev libssl-dev libffi-dev libjpeg-dev zlib1g-dev
# get the source
git clone https://github.com/piqueserver/piqueserver
cd piqueserver
# we make git tags for every version so you can checkout out to specific version if you want
# git checkout v0.1.3
# create a new python3 venv
virtualenv -p python3 venv
source venv/bin/activate
# install deps.
pip install -r requirements.txt
# install piqueserver
python setup.py install
# don't forget to deactivate the venv when finished!
deactivate
Windows¶
Installation from source¶
Note
Most of the piqueserver team uses Linux and we aren’t experienced with Cython on windows. If you can help us improve windows support we’d greatly appreciate it.
Tricky bit for windows is to get Cython working.
- Install Visual C++ compiler please follow this guide.
- Don’t forget to upgrade
setuptools
- Install git or download sources from github and unzip
- If you decided to use git:
git clone https://github.com/piqueserver/piqueserver
Tip
If you see errors like “unable to find vcvarsall.bat” refer to this article.
cd piqueserver
pip3 install -r requirements.txt
python setup.py install
Configuring Piqueserver¶
Piqueserver is configured through a config file, usually named
config.toml
. Piqueserver uses the configuration language TOML (Tom’s
Obvious Markup Language). A detailed description of TOML can be found in the
TOML readme, but a
short example is provided below.
Note
PySpades, PySnip and versions of piqueserver before 1.0.0 used a JSON file for settings. These files will still be read, if no config.toml is available. However, the structure piqueserver expects might differ.
TOML Syntax¶
TOML files are plaintext files. They can be edited with any plaintext editor of your choice, such as Notepad++ on windows, editor on mac and, nano or gedit on Linux.
Configuration is case-sensitive. This means that your settings will not apply correctly if you use the incorrect case.
The section header is followed by key-value pairs:
name = "best server ever"
If a # is encountered, the rest of the line will be ignored.
There are a number of types of values:
text = "text, surrounded by quotes"
motd = """
a longer text
that can stretch
over more lines
(useful for the MOTD!)"""
list = ["a", "list",
"of", "values"]
a_number = 123.5
enable_thing = true # or false
TOML supports sections similar to the Microsoft .ini
file format. The
beginning of a section is marked by the name of the section surrounded by
square brackets:
[general]
Any key-value pairs that follow this are part of that section, until a new section is started.
Substitution¶
Some config options allow data about the server to be substituted. These options are enclosed in curly braces. This example uses all substitutions that are available when substitution is available for a config option:
motd = [
"Welcome to {server_name}! See /help for commands.",
"you are playing {game_mode}",
"Map is {map_name} by {map_author}.",
"Map description: {map_description}.",
"(server powered by piqueserver)",
]
Individual config options might have additional substitutions available. This is noted in the documentation for the relevant option.
New in version 1.0.0: The {name}
format was added. The older, %(name)s
format is deprecated.
Config directory structure¶
The configuration directory follows a strict structure.
By default the configuration directory lives at $XDG_CONFIG_HOME/piqueserver/
with a fallback to $HOME/.config/piqueserver/
, as specified by the XDG Base Directory Specification.
This can be overridden by the -d
command line option.
.
├── bans.txt # Player bans get stored in this file; it is created automatically.
├── config.toml # The main configuration file. By default piqueserver will look for config.toml in the config directory.
│ # This can be overridden by the -c command line option.
├── game_modes # Scripts that are specifically game modes will be stored here.
│ └── buildandsplat.py # Your custom game mode script
├── logs # This directory contains logs output by the server.
│ └── log.txt # The main server logfile; If you disable daily rotation of log files all logs go here.
├── maps # Any map files should be stored in here. Where a map is specified by name in "rotation" config option
│ ├── classicgen.txt # the server will look for a .txt or .txt/.vxl file with that name.
│ └── random.txt
├── scripts # You can add other scripts not included with piqueserver here.
│ │ # The server will load any scripts listed in "scripts" config option by name from here.
│ └── showhp.py # For example, if "showhp" is listed in the "scripts" config option, then scripts/showhp.py will be loaded.
│
└── data # Various other data files are stored here.
└── GeoLiteCity.dat # Currently it's only used for the geoip data file required by the /from command in-game.
Options¶
Base Configuration Options¶
These are the base configuration options available in piqueserver.
General¶
This section contains general information and configuration for the server
name¶
The Name of the server, as displayed on the master server list:
name = "piqueserver instance"
This config option supports Substitution.
motd¶
A list of lines which should be sent when the player joins:
motd = [
"Welcome to the server",
"Have fun! <3",
]
This config option supports Substitution.
help¶
This is the text shown by the /help command. If not defined, /help will just display a list of the available commands.
This config option supports Substitution.
tips¶
A line picked at random from this text will be shown every tip_frequency minutes.
This config option supports Substitution.
tip_frequency¶
How often the tip will be shown, in minutes. 0 means no tips. Default 5.
max_players¶
The maximum number of players on the server. Going over 32 players will break the vanilla AoS client, as is not designed to support more. Default 32.
game_mode¶
The ctf
for “Capture the Flag”, tc
for “Territory Control”. or a script
name for a custom game mode.
cap_limit¶
The number of captures that are required to end the game.
rotation¶
A list of maps to use
default_time_limit¶
The default time limit to set per map. When the time limit runs out, the map rotation is advanced.
advance_on_win¶
If true, advance the map rotation when the game ends.
random_rotation¶
false
if the order should be as in rotation, true
if the order
should be shuffled. Default false.
max_connections_per_ip¶
Limits how many players can connect from the same IP address. 0 disables this limit. Default 0.
team1/team2¶
This section configures the teams:
[team1]
# name of the team to be displayed in-game
name = "Blue"
# color of the players in RGB, 0-255
color = [ 0, 0, 255]
[team2]
name = "Green"
color = [ 0, 255, 0]
bans¶
This section defines the behaviour when admins ban players:
[bans]
# default duration a banned player will be banned for
default_duration = "1day"
# location the bans are saved and loaded from
file = "bans.txt"
# Ban publish allows you to synchronize bans between servers. When enabled,
# the server listens on the given port and responds to any requests with a list
# of bans
publish = false
publish_port = 32885
# Bansubscribe allows you to inherit bans from another server with banpublish enabled.
# `url` is the URL returning the json list, `whitelist` is a list of names which should
# be exempt from the filter
bansubscribe = [
{ url = "http://www.blacklist.spadille.net/subscribe.json", whitelist = []},
]
# how often the subscribed servers are frequented to update bans
bansubscribe_interval = "5min"
respawn_waves¶
When true, respawn all dead players every respawn_time seconds. When false, respawn a player respawn_time seconds after their death. Spawning in groups decreases the effectiveness of spawnkilling. Default true.
respawn_time¶
see respawn_waves
cap_limit¶
The number of intel captures before the game is won. Default 10.
respawn_time¶
The number of seconds before a player respawns. Default 5.
master¶
‘true’ shows server on the master serverlist. ‘false’ disables this, for private games want a private game. Default false.
friendly_fire¶
true
: enables friendly fire.
false
: disables friendly fire.
friendly_fire_on_grief¶
if true, friendly fire is enabled temporarily if a player destroys a block.
spade_teamkills_on_grief¶
If friendly fire should be enabled for the spade too. This is disabled by default, because it often causes accidental teamkills in tunnels.
grief_friendly_fire_time¶
The number of seconds a player is vulnerable to friendly fire after destroying a block when friendly_fire_on_grief is enabled.
teamswitch_interval¶
Forces players to wait a set duration before being able to switch back again after they switched teams.
“0sec” disables the cooldown.
teamswitch_allowed¶
If true
you only get to pick a team when you join.
detect_speedhack¶
If true
, attempt to detect if users are speedhacking. This is not 100%
accurate, so it might be a good idea to disable it for servers where the users
are trusted.
rubberband_distance¶
Distance the server tolerates between the place it thinks the client is to where the client actually is. Default 10.
melee_damage¶
The amount of damage dealt by the spade. Default 80.
fall_damage¶
controls whether players receive damage by falling from height
passwords¶
This section contains roles and their associated passwords. When playing, a player may gain that role by typing:
/login <password>
Any name may be used for a role, but there are two special roles:
admin
and trusted
. Users with the admin
role have the maximum rights
available, while trusted
users are not affected by votekicks and similar.
Each account can have a list of passwords. It is usually a good idea to give out one password per person:
[passwords]
admin = ["password","sesame","watermelon"],
trusted = ["semi","coolness"]
custom = ["mypass"]
rights¶
This section contains the commands each role can execute.
scripts¶
Piqueserver ships with a set of scripts you can use to customize the features of your server. They are loaded in order, “on top of” each other.
Scripts can either be absolute python import paths
(piqueserver.scripts.aimbot2
) or the name of scripts in the scripts folder,
excluding the file extension (mycustomscript
for a script at
scripts/mycustomscript.py
):
scripts = [
"piqueserver.scripts.rollback",
"piqueserver.scripts.protect",
"myscript",
]
Logging¶
Piqueserver can log events that happen to a text file:
[logging]
# set log level
# log levels in decending order: debug, info, warn, error, critical
loglevel = "info"
# the logfile to log to
# relative paths are resolved relative to the config directory; parent
# directories are created as necessary
# empty string disables logging
logfile = "./logs/log.txt"
# Write a new log file each day
rotate_daily = true
# enable profiling
profile = false
ssh¶
This section controls SSH “manhole” access to the server. This allows you access to a python shell. This is mainly useful for debugging. If you don’t know what you are doing, you should leave it disabled:
[ssh]
enabled = false
port = 32887
[ssh.users]
# user = password
# pairs for credentials allowed to login to the ssh server
# WARNING: keep these credentials secure since this gives console access to the server
# on which piqueserver is running!
user1 = "ssh_pass_change_this"
status_server¶
The status server is a built-in web server that displays information about the server and connected players:
[status_server]
enabled = true
# the port to listen on
port = 32886
# write an access log
logging = false
server_prefix¶
When the server sends messages to users, the message is prefixed with the characters in server_prefix.
user_blocks_only¶
Controls whether users can affect the map’s initial blocks.
logfile¶
The file where the server log is recorded. Relative paths are resolved relative
to the configuration directory. For example if the logfile is /logs/log.txt
,
this will be in the logs
subdirectory of the config directory.
balanced_teams¶
If 0, any permutation of teams is allowed. If 1 or greater, players are not
allowed to join a team if that would mean the difference in players count
between the two teams is more than the balanced_teams
value. Default 2.
login_retries¶
The number of /login attempts allowed before users are auto-kicked. Default 3.
irc¶
This section configures an IRC chatbot that reports server events in the given channel:
[irc]
enabled = false
# IRC login details
nickname = "piqueserver"
username = "piqueserver"
realname = "piqueserver"
server = "irc.quakenet.org"
port = 6667
# channel to join into
channel = "#piquserver-bots"
# password for the channel
password = ""
# prefixes irc users must use for bot to process as command or to send to game chat
commandprefix = "!"
chatprefix = "."
set_god_build¶
Put the player into god build mode automatically when entering god mode
time_announcements¶
Configure the times that announcements about the remaining time should be made. This value is a list of times remaining in seconds.
ip_getter¶
Optionally override the service used to fetch the server’s public ip address.
Eg. "https://api.ipify.org"
. If this is set to an empty string,
IP getting is disabled.
Note: this url must return solely the ip address in the response body.
release_notifications¶
Check github for new releases and notify admins if new releases are found. Default True.
everyone_is_admin¶
Set everyone_is_admin
to true to automatically log all players in as admin on
join. Possibly useful for testing purposes.
Supported Python environments¶
Piqueserver supports the following Versions of CPython: 3.7, 3.8, 3.9, 3.10 and 3.11
Migration from Python 2 to Python 3¶
To Migrate an existing installations over, follow the following steps:
- Make sure Python3.7+ is installed on your system:
python3 --version
- Make sure the Python3 version of pip is installed on your system:
pip3 --version
pip uninstall piqueserver
pip3 install --upgrade piqueserver
- Start up your server again and verify no errors are shown in the console
Possible issues with the migration¶
Python3 has changed many internals of the python language. Because of that, some subtle bugs might occur.
Old pyspades scripts will likely be broken by this change too. If this happens, just open an issue or chat with us and we will work with you to get it ported to the new version!
See also
Included Piqueserver Scripts¶
This is an Overview over the scripts that currently ship with piqueserver
Scripts¶
piqueserver.scripts.afk script¶
Kicks a player if inactive for too long.
piqueserver.scripts.aimbot2 script¶
Detects and reacts to possible aimbot users.
Commands¶
/accuracy <player>
shows player’s accuracy per weapon/hackinfo <player>
shows player’s accuracy, K/D ratio and how often their cross-hair snaps onto another players head admin only
Options¶
[aimbot]
collect_data = true # saves hits and shots of each weapon to a csv file
Code author: ?
piqueserver.scripts.airstrike2 script¶
Airstrikes. Boom!
Commands¶
/airstrike or /a
allows a player to call an airstike/givestrike <player>
gives a player the ability to call an airstike immediately admin only
Code author: hompy
piqueserver.scripts.antijerk script¶
Kicks jerks for ‘PRESS ALT-F4 FOR AIRSTRIKES’ and so on.
piqueserver.scripts.autohelp script¶
Helps Deuces automagically when they ask in the chat for help.
Code author: ?
piqueserver.game_modes.babel_script module¶
Original script by Yourself Anti grief by izzy Return intel dropped from platform bug fix by a_girl
Release thread: http://www.buildandshoot.com/viewtopic.php?t=2586
How to install and configure:
- Set game_mode to “piqueserver.game_mode.babel” in config.txt
- Add “piqueserver.scripts.babel_script” to scripts list in config.txt
- Set cap_limit to “10” in config
piqueserver.scripts.badmin script¶
Badmin is an bot admin.
It automates common admin tasks such as:
- Banning griefers
- Banning aimbotters
- Banning racists
Since it is automatic it won’t always get it right.
Commands¶
/badmin
shows which badmin options are enabled/disabled admin only/investigate <player>
shows a player’s grief score, K/D ratio and hit accuracy admin only
Note
It depends on the blockinfo.py (for grief detection), ratio.py (for k/d ratio), aimbot2.py (hit accuracy) scripts.
Code author: ?
piqueserver.scripts.blockinfo script¶
A tool for identifying griefers.
Note
“blockinfo” must be AFTER “votekick” in the config script list
Commands¶
/griefcheck or /gc <player> <minutes>
gives you when, how many and whos blocks a player destroyed admin only
piqueserver.scripts.daycycle script¶
Gives Ace of Spades a daycycle (using the fog).
Commands¶
/dayspeed <speed>
sets day speed admin only/dayspeed
gets day speed admin only/daytime <time>
sets day time admin only/daytime
gets day time
Code author: hompy
piqueserver.scripts.demolitionman script¶
Restocks the user when reloading / throwing a nade.
piqueserver.scripts.disco script¶
Ever wanted a disco in Ace of Spades?
piqueserver.scripts.flagreturn script¶
Makes the flag returnable in Quake-like fashion.
Code author: mat^2 & learn_more
piqueserver.scripts.geoip script¶
Gets a player’s location info using a geoip database. Location is formatted as a list of regions ordered by hierarchy (i.e. City, Region, Country)
Note
This script depends on geoip2
package and piqueserver --update-geoip
needs to be executed after installing the package.
Commands¶
/from
get active player’s location/from <player>
get player’s location info
Code author: ?
piqueserver.scripts.grownade script¶
Turns your grenades into magical kv6-growing seeds. Or beans!
Use /model <filename>
to load model files. These must be placed inside a
folder named kv6/
in the config directory. A full path would look like
this: ~/config/kv6/filename.kv6
. Then it can be loaded with /model
some_model
Wildcards and subfolders are allowed. Some examples:
/model building*
Loads all models that start with “building”, like “building1” and “buildingred”:
/model my_trees/*
Loads all models inside a folder named “my_trees”
When you have many models loaded, each grenade will pick a random one to grow.
To stop littering the map with random objects just type /model
.
Pivot¶
THE PIVOT POINT in kv6 files determines the first block to be placed. The rest of the model will then follow, growing around it.
The pivot point MUST be sitting on a block, or the model won’t load. Checking ‘Adjust pivots’ in the Tools menu in SLAB6 will show handy coordinates. To be sure, you can move the pivot to half of a block, e.g.: (4.50, 4.50, 8.50)
In a tree kv6, for example, the pivot point would lie on the lowest block of the tree trunk, so that it grows up and not into the ground.
Works best with 0.75 kv6 models.
You can adjust FLYING_MODELS and GROW_ON_WATER to allow growing in the air and on water, respectively. These are disabled by default so you can fly high and sprinkle tree-growing grenades without worrying about unseemly oddities.
Options¶
[grownade]
flying_models = False # if False grenades exploding in midair will be ignored
grow_on_water = False # if False grenades exploding in water will do nothing
Code author: hompy
piqueserver.scripts.map_extensions script¶
Provides extensions to the map metadata (e.g. water damage).
Code author: ?
piqueserver.scripts.mapmakingtools script¶
piqueserver.scripts.markers script¶
Pinpoint players and bookmark tunnels without making the enemy aware. Markers attempt to help teams communicate and so, cooperate.
Markers are just symbols built with blocks at the very top of the map, which only your team can see. They’ll show up on your teammates’ map and minimap, and can be brought up in a number of ways.
- Double-tapping the SNEAK key lets you quickly spot an enemy’s location.
- When your intel is stolen a marker is dropped where it just was, shadowing its position and eliminating “I forgot where it was” situations.
- Enemy positions are automatically revealed when the intel is captured, mimicking the old ‘radar’ reward.
- Say !tunnel in teamchat to make an arrow where you’re standing, instruct other players to do something for a change with !build, or meet up with someone else using !here.
Players can type /clear to get rid of markers on their own screen. Admins can disable or enable placing of new markers using /togglemarkers. /togglemarkers <player> toggles only that player’s ability to do so.
Any functionality can be disabled switching off SHADOW_INTEL, REVEAL_ENEMIES, VV_ENABLED and CHAT_MARKERS below.
Commands¶
/clear
clears all markers admin only/togglemarkers <player>
toggles a player’s ability to place markers admin only/markers
gives instructions
Code author: hompy
piqueserver.scripts.match script¶
Match script, useful for public matches. Features verbose announcements on IRC and a custom timer.
Commands¶
/timer
starts timer admin only/stoptimer
stops timer admin only/startrecord
starts a fresh records admin only/stoprecord
clears the current record admin only/saverecord
save record to a file admin only
piqueserver.scripts.medkit script¶
Gives a specified amount of medkits on spawn
Commands¶
/medkit or /m
utilizes available medkits to heal
Options¶
[medkit]
medkits = 1 # no. of medkits
medkit_heal_amount = 40 # how much hp. it gives
Code author: Booboorocks998 & mat^2
piqueserver.scripts.memcheck script¶
Runs the garbage collector at a given interval and displays any uncollected garbage found.
Code author: mat^2
piqueserver.scripts.minefield script¶
Minefield map extension.
Allows mappers to specify the map bounds, outside of which players will trip mines. Breaking blocks (when standing close to the field) also triggers a mine.
Warning
This script conflicts with smartnade
script.
Commands¶
/minedebug
toggles debug mode admin only
example extension from mapname.txt:
>>> extensions = {
... 'minefields' : [
... #this minefield defines the border:
... {
... 'border' : 1,
... 'left' : 59,
... 'top' : 154,
... 'right' : 451,
... 'bottom' : 355,
... },
... # this specifies an additional minefield (and shows a simpler
... # syntax)
... {
... 'area' : (183, 126, 224, 233), #top left
... 'height' : 60 # this specifies until which block mines are
... # enabled (so you can build over it)
... }
... ]
... }
Code author: learn_more (MIT LICENSE)
piqueserver.scripts.nointelonwalls script¶
Prevents taking intel through walls
Version 2(2017.12.25)
Code author: kmsi<kmsiapps@gmail.com>
piqueserver.scripts.nospadingwalls script¶
piqueserver.scripts.paint script¶
Lets you change the color of the block you are looking at. With block tool selected, pick a color, then hold down sneak key (<V> by default) to paint.
piqueserver.scripts.passreload script¶
Allows reloading config on the fly
piqueserver.scripts.protect script¶
Protects areas against block destroying/building.
Commands¶
/protect <area coordinates>
puts an area under protected status admin only/protect
clears all protected areas admin only
Code author: hompy
piqueserver.scripts.rampage script¶
Killing KILL_REQUIREMENT other players in under TIME_REQUIREMENT seconds sends you into a rampage lasting RAMPAGE_DURATION seconds. The rampage refills and drastically increases your weapons’ rate of fire.
By default this means 3 kills in under 8 seconds to activate. For reference, lines disappear from the killfeed 10 seconds after they appear.
Intended for use in frantic last team standing or free for all matches.
Code author: hompy
piqueserver.scripts.rangedamage script¶
Changes the damage values depending on distance.
Options¶
[rangedamange.rifle]
pct_per_block = 0 # percentage per block?
multiplier = 1
[rangedamange.smg]
pct_per_block = 0
multiplier = 1
[rangedamange.shotgun]
pct_per_block = 0
multiplier = 1
Code author: ?
piqueserver.scripts.rapid script¶
/rapid [player] will put the player in rapid mode, speeding up all tools including weapons.
RAPID_BLOCK_DELAY determines how fast block placement should be. Lowering this value is not recommended except for local use. Ping to the server is the effective lower limit: if this value is set to 0.1 (0.1 seconds = 100ms), users with ping above that won’t have the same advantage as the rest of the players.
Set ALWAYS_RAPID to TRUE to automatically get rapid when you login.
Code author: hompy
piqueserver.scripts.ratio script¶
Shows K/D ratio
Note
“ratio” must be AFTER “votekick” in the config script list
piqueserver.scripts.analyze script¶
Shows a detailed analysis of a players shots
Commands¶
/analyze or /an <target>
to show a detailed analysis of a players shots if they hit someone. Shows hit player, distance, dT in milliseconds (Delta Time- Time since previous shot that hit someone. Useful for detecting multiple bullet or rapid hacks), weapon, which body part it hit, and a basic counter that displays the number of hits of that type./analyze or /an
to disable it
Code author: a_girl
piqueserver.scripts.rollback script¶
Rollback rolls back the map to it’s original state by placing and removing changed blocks. This takes ages. Use with care.
Commands¶
/rollmap <map name>
changes the map to the given map in a rolling fashion admin only/rollmap <map name> <sector>
changes the sector of the current map to the given map’s sector in a rolling fashion admin only/rollback
starts a rollback on the current map admin only/rollbackcancel
cancel an on-going rollback admin only
Warning
/rollmap
will take a long time if number of differing blocks is too high.
piqueserver.scripts.runningman script¶
Links any two teammates so that they explode if they stray away from each other. An incredibly unnerving method of encouraging teamplay.
Enable by doing /runningman or by setting ENABLED_AT_START = True Linking is automatic at spawn and tries to find new partners every two deaths. Use /unlink [player] to toggle yourself or someone from being linked.
May not work well with squads.
Code author: hompy
piqueserver.scripts.savemap script¶
Adds a /savemap command to save the current state of the map. You can specify any name with an argument, without it the map will be saved with the ‘.saved’ suffix. With /rmsaved you can delete a ‘.saved’ version of this map.
Options¶
[savemap]
# automatically load the saved map on map load
load_saved_map = true
# automatically save map at shutdown
save_at_shutdown = false
# automatically save map at map rotation or server shutdown
always_save_map = false
piqueserver.scripts.smartnade script¶
Smartnade script
Warning
This script conflicts with minefield
script.
Code author: ?
piqueserver.scripts.spadenadefix script¶
Prevents spade-nade bug
version 2(2017.12.23)
Code author: kmsi<kmsiapps@gmail.com>
piqueserver.scripts.spawn_protect script¶
Protects spawned players for a specified amount of seconds.
piqueserver.scripts.spectatorcontrol script¶
Lets you set restrictions on spectators.
Original documentation:
This script will hopefully give server owners some control over what spectators do on there server. As of now since the release of v0.75, Goon Haven has had issues with spectators idling and using global chat to send information to a team so that they may know enemy positions or what the enemy is doing, etc. This script can block spectator chat as well as kick spectators after so much time as passed.
Additionally, server owners who also give out “guard” or “mini-mod” positions can add the right “specpower” to the group rights in commands.py to have the guards/minimods be immune to the spectator kick and chat restrictions.
Oh, and admins are also automatically immune to spectator kick and chat restrictions.
Hope you enjoy! Tocksman
Options¶
[spectator_control]
no_chat = false # determines whether spectators can chat or not in your server
kick = false # determines whether spectators will be kicked after remaining for so long
kick_time = "5min" # how long a spectator may remain before they are kicked
Code author: Tocksman (made for Goon Haven)
piqueserver.scripts.squad script¶
BF-like squad system.
Commands¶
/squad <key>
to join a squad/follow <player>
to spawn near a specific player
piqueserver.scripts.strongblock script¶
Blocks built by players are twice as hard to break.
- You can remove your own blocks as if they weren’t strong.
- Dirt-colored or buried blocks (those that turn into dirt) become normal blocks.
Code author: hompy
piqueserver.scripts.timedmute script¶
Allows muting players for a set amount of time.
Commands¶
/tm <player> <seconds> <reason>
mute a player for set amount of time admin only
Note
Default time 5 minutes, default reason None
piqueserver.scripts.trusted script¶
Adds the ability to ‘trust’ certain players, i.e. they cannot be votekicked or rubberbanded.
piqueserver.scripts.votekick script¶
Allows users to start votekicks
Commands¶
/votekick <player> <reason>
start votekick against a player/y
votes yes/togglevotekick or /tvk
toggles votekicks on/off globally/togglevotekick or /tvk <player>
toggles votekicks on/off for specific players/cancel
cancels a votekick
Options¶
[votekick]
# percentage of total number of players in the server required to vote to
# successfully votekick a player
percentage = 35
# duration that votekicked player will be banned for
ban_duration = "30min"
public_votes = true
Code author: James Hofmann a.k.a triplefox
piqueserver.scripts.votemap script¶
Allows players to vote for maps.
Commands¶
/votemap
initiates map voting/vote <map name>
vote for a map
[votemap]
public_votes = true
extension_time = "15min"
player_driven = false
autoschedule = false
percentage = 80
Code author: James Hofmann a.k.a triplefox (GPL LICENSE)
Included Game Modes¶
This is an Overview over the game modes that currently ship with piqueserver
Scripts¶
piqueserver.game_modes.arena gamemode¶
Arena, A game of team survival. The last team standing scores a point.
A map that uses arena needs to be modified to have a starting area for each team. A starting area is enclosed and has a gate on it. Each block of a gate must have the EXACT same color to work properly. Between each rounds, the gate is rebuilt. The gates are destroyed simultaneously at the start of each round, releasing the players onto the map. Players are free to switch weapons between rounds.
Spawn locations and gate locations MUST be present in the map metadata (map txt file) for arena to work properly.
The spawn location/s for the green team are set by using the data from the
arena_green_spawns
tuple in the extensions dictionary. Likewise, the blue
spawn/s is set with the arena_blue_spawns
key. arena_green_spawns
and
arena_blue_spawns
are tuples which contain tuples of spawn coordinates.
Spawn locations are chosen randomly.
Note
the script retains backwards compatibility With the old
arena_green_spawn
and arena_blue_spawn
The arena_max_spawn_distance
can be used to set MAX_SPAWN_DISTANCE
on a
map by map basis. See the comment by MAX_SPAWN_DISTANCE
for more information
The locations of gates is also determined in the map metadata. arena_gates
is a tuple of coordinates in the extension dictionary. Each gate needs only one
block to be specified (since each gate is made of a uniform color)
Sample extensions dictionary of an arena map with two gates: In this example there is one spawn location for blue and two spawn locations for green:
extensions = { 'arena': True, 'arena_blue_spawns' : ((128, 256, 60),),
'arena_green_spawns' : ((384, 256, 60), (123, 423, 51)), 'arena_gates':
((192, 236, 59), (320, 245, 60)) }
Code author: Yourself
piqueserver.game_modes.babel gamemode¶
Babel: reach the heavens by building a tower
Derived from onectf.py by Yourself
Release thread: http://www.buildandshoot.com/viewtopic.php?t=2586
piqueserver.game_modes.infiltration gamemode¶
Infiltration is an asymetric intel-based game mode where one team, the attackers, tries to infiltrate the defenders base and steal the intel. Defenders receive points for keeping the intel out of the attackers hands and attackers recieve points for capturing the intel.
Options¶
[infiltration]
# Attackers get attacker_score_multiplier points for taking and capturing
# the intel.
attacker_score_multiplier = 10
# Defenders gain 1 point for every defender_score_interval seconds that the
# intel remains untouched.
defender_score_interval = "30sec"
# The ratio of attackers to defenders. Be aware that setting this
# incorrectly might prevent players from joining
attacker_ratio = 1.6
Originally created by: TheGrandmaster / hompy
piqueserver.game_modes.onectf gamemode¶
One CTF: CTF with a single intel, placed in the center.
piqueserver.game_modes.push gamemode¶
Code author: danhezee, StackOverflow, izzy, Danke, noway421, IAmYourFriend
The concept¶
Each team spawns at a set location with the enemy intel. They must “push” the intel towards their control point, which is also at a set location. The only way to arrive there is by building bridges over the deadly water. Further introduction to the game mode: https://youtu.be/DdisPY6vDD0
Setting Up New Maps¶
Spawn and CP locations must be configured via extensions in the map’s map_name.txt metadata:
>>> extensions = {
... 'push': True,
... 'push_spawn_range' : 5,
... 'push_blue_spawn' : (91, 276, 59),
... 'push_blue_cp' : (91, 276, 59),
... 'push_green_spawn' : (78, 86, 59),
... 'push_green_cp' : (78, 86, 59),
... 'water_damage' : 100
... }
Additional (but optional) extensions, to mark each team’s build area and prevent the enemy from building there (and thereby helping the enemy). The build area is defined by x and y of upper left corner, followed by x and y of bottom right corner on the map:
'push_blue_build_area' : (64, 100, 243, 500),
'push_green_build_area' : (268, 100, 447, 500),
Commands¶
/r
Quickly respawn to refill blocks and ammo (if enabled)/resetintel <team>
Manually reset the blue or green team’s intel
Options¶
[push]
# Disallow removal of map blocks. This allows a larger variety of maps that
# rely on more fragile structures. It also prevents griefing (like removing
# the map blocks before and after your team's bridge).
protect_map_blocks = true
# Allow the usage of /r to quickly respawn. As players can't refill blocks at
# their base, they would have to suicide otherwise. This is illogical, messes
# up their kill-death ratio and gives them an undeserved punishing respawn time.
allow_respawn_command = true
# How long to wait to allow the command /r again
respawn_cmd_delay = "15sec"
# Players have to wait this amount after spawning before they can pick
# the intel up. This is to reduce the instant/careless intel pickups.
intel_pickup_delay = "3sec"
# How long can you remove your own last blocks
block_removal_delay = "15sec"
# Reset intel after it was dropped somewhere
reset_intel_after_drop = "3min"
# No building near cp within this block range (can be overwritten using
# map extension parameter "push_cp_protect_range")
default_cp_protect_range = 8
# Disable grenade damage within enemy spawn.
disable_grenades_at_spawn = false
piqueserver.game_modes.tow gamemode¶
Tug of War game mode, where you must progressively capture the enemy CPs in a straight line to win.
Maintainer: mat^2
Command line arguments¶
View of help output¶
$ piqueserver --help
usage: piqueserver [-h] [-c CONFIG_FILE] [-j JSON_PARAMETERS] [-d CONFIG_DIR]
[--copy-config] [--update-geoip]
piqueserver is an open-source Python server implementation for the voxel-based
game "Ace of Spades".
optional arguments:
-h, --help show this help message and exit
-c CONFIG_FILE, --config-file CONFIG_FILE
specify the config file - default is "config.json" in
the config dir
-j JSON_PARAMETERS, --json-parameters JSON_PARAMETERS
add extra json parameters (overrides the ones present
in the config file)
-d CONFIG_DIR, --config-dir CONFIG_DIR
specify the directory which contains maps, scripts,
etc (in correctly named subdirs) - default is
~/.config/piqueserver
--copy-config copies the default/example config dir to its default
location or as specified by "-d"
--update-geoip download the latest geoip database
Explanation¶
-h
or --help
¶
self explanatory - display help about running
-c
or --config-file
¶
Takes a parameter which is the path to the desired configuration file.
Defaults to config.json
is the configuration directory.
-d
or --config-dir
¶
Specifies the directory to use for its configuration. Defaults to
$XDG_CONFIG_HOME/piqueserver/
or $HOME/.config/piqueserver/
if
the former environment variable isn’t set. This directory is also used
by --copy-config
as the target directory for copying the example
configuration, as well as the base path when giving a relative path to
--config-file
.
--copy-config
¶
Copies the included example configuration directory to the default
configuration directory, or to the location specified by
--config-dir
. Will create the directory if it doesn’t exist, and
will not copy if the directory already exists to avoid overwriting
existing config.
-j
or --json-parameters
¶
Example: piqueserver -j '{"profile":true}'
Takes the json object and uses it to override fields from the json
configuration file. Useful for testing out a quick change where you
don’t want to edit config.json
.
--update-geoip
¶
Downloads the latest data file containing geoip data into
data/GeoLiteCity.dat
in the configuration directory. This data file
is required for the from
command to work in-game.
Running Piqueserver with Docker¶
Image¶
You can either use the published image on Docker Hub or build it locally.
# using published image
docker pull piqueserver/piqueserver:master
# build it locally
git clone https://github.com/piqueserver/piqueserver
cd piqueserver
docker build -t piqueserver/piqueserver:master .
Running¶
Get your config ready. It should have the following structure:
config/
├── config.toml
├── game_modes
│ └── README.md
├── logs
├── maps
│ ├── classicgen.txt
│ └── random.txt
├── README.md
└── scripts
└── README.md
If you don’t have it you can grab it from the repository here. After setting up the config directory you can run piqueserver using the following command.
# running
docker run -d \
-rm \
-v /path/to/config:/config \
-p 32887:32887/udp -p 32886:32886/tcp \
--name mypiqueserver \
piqueserver/piqueserver:master
# viewing logs
docker logs mypiqueserver
# killing the server
docker kill mypiqueserver
Note
-v
flag only accepts absolute paths.-p
flag’s syntax is as follows host_port:container_port
Example Linux Setup with Systemd¶
Overview¶
These instructions will give you a flexible and secure setup for Piqueserver that starts automatically at boot, restarts on crashes, and collects logs.
It also allows you to run as many instances as you want in parallel.
Instructions¶
Install latest piqueserver using pip or whatever other method you like.
# pip3 install piqueserver
Create a dedicated directory for piqueserver data. You can put this anywhere
you like. It is a good idea to put some identifier for your server, such as
ctf
in the folder name, in case you want to create more server configs in
the future.
# mkdir -p /var/lib/piqueserver/servername/
We want a seperate group to be able to restrict permissions in a more granular way
# groupadd --system piqueserver
Optionally join your own user to the piqueserver
group to be able to
edit files in the piqueserver directory freely.
# usermod -a -G piqueserver yourusername
We want to copy the default config directory over.
# piqueserver --copy-config -d /var/lib/piqueserver/servername
Edit a new file, /etc/systemd/system/piqueserver@.service
and insert
the following contents.
[Unit]
Description=Piqueserver
[Service]
ExecStart=/usr/local/bin/piqueserver -d /var/lib/piqueserver/%i
User=piqueserver
Group=piqueserver
Restart=always
# Security Sandbox Settings
Group=piqueserver
DynamicUser=true
# only allow access to the state folder, nothing else
ProtectHome=true
TemporaryFileSystem=/var:ro
PrivateDevices=true
StateDirectory=piqueserver/%i
# disallow any unusual syscalls
SystemCallFilter=@system-service
[Install]
WantedBy=network.target
You can now start, stop, and see the status of the process using systemctl.
# systemctl start piqueserver@servername
# systemctl stop piqueserver@servername
# systemctl status piqueserver@servername
You will probably want to start the server at boot. To do this, run:
# systemctl enable piqueserver@servername
To tail the logs, run
# journalctl -f -u piqueserver@servername
Porting scripts¶
Piqueserver still supports scripting just as PySnip did! However, since Piqueserver has had much refactoring and improvements since forking from PySnip, some scripts that work with PySnip, may not work immediately with Piqueserver. Never fear! The piqueserver team has avoided breaking changes regarding scripts as much as possible, and here are some details on some points that could be breaking changes.
Tip
Do reach out to the piqueserver team we can help you out!
Automated port to Python 3¶
Since Piqueserver doesn’t support Python 2 anymore we have to port the scripts to Python 3. Most of the porting can be automated with tools like 2to3. We can later fix issues related to py2->py3 as they arise.
Fix feature_server module imports¶
# OLD
from map import ...
from commands import ...
from scheduler import ...
# NEW
from piqueserver.map import ...
from piqueserver.commands import ...
from piqueserver.scheduler import ...
from piqueserver.map import ...
map.DEFAULT_LOAD_DIR
and other constants¶
This constant in feature_server/map.py
is no longer, along with potentially others. Now, if you wish to get the map directory, you can use something like:
import os
from piqueserver.config import config
map_dir = os.path.join(config.config_dir, 'maps')
Fix packet imports¶
pyspades (and PySnip) have various packet instances in pyspades.server
and those instances were used/shared by multiple scripts.
Which can get messy and cause bugs. In piqueserver those instances are no longer present and scripts have to create those instances themselves.
# OLD
from pyspades.server import grenade_packet, block_action, set_color
# NEW
from pyspades.contained import GrenadePacket, BlockAction, SetColor
# lazy fix: package level global like below
grenade_packet, block_action, set_color = GrenadePacket(), BlockAction(), SetColor()
# proper fix: create them wherever they get used
Debugging import errors¶
Import errors in scripts causes piqueserver to throw NotImplementedError
which is vague(sorry!).
For debugging those import errors use python(shell) or ipython they’ll point you to which exact import is causing issues.
In [1]: import buildandsplat
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
<ipython-input-1-01d8c693f582> in <module>
----> 1 import buildandsplat
~/piqueserver/piqueserver/game_modes/buildandsplat.py in <module>
25 from pyspades.common import Vertex3, make_color, get_color
26 from pyspades.constants import *
---> 27 from subprocess import add, admin, get_player, name
28 from pyspades import contained as loaders
29 from pyspades.weapon import WEAPONS
ImportError: cannot import name 'add' from 'subprocess' (/usr/local/lib/python3.7/subprocess.py)
Final¶
Try out the script and see if anything breaks. If the errors seem py2->py3 related refer to this cheatsheet. Piqueserver team has done a giant port of scripts in v0.1.1 it can be used as a reference. If you get stuck please reach out to the piqueserver team we are happy to help!
Contributing (developer)¶
This is the developer guide for contributing to piqueserver.
Requirements¶
Any code which does not follow the requirements below have chances of
not being accepted into the master
branch until modified to
comply with them. You may submit code which does not comply with the
requirements and leave for a maintainer to fix them, but it’s considered
bad practice.
- The EOL (End-of-line)
character for the file types below must be LF (\n)
- Python and Cython scripts (
.py
and.pyx
) - C and C++ scripts (
.c
,.cpp
,.h
) - Shell scrips (
.sh
,.bash
)
- Python and Cython scripts (
- The EOL (End-of-line)
character for the file types below must be CRLF (\r\n)
- Windows scripts (
.bat
,.ps1
)
- Windows scripts (
- All files must end with their respective EOL character, as mentioned above
- Use autopep8 to format python source files.
- Use clang-format to format C/C++ source files. We have a custom
.clang-format
file at the root of the repository.
Testing¶
Testing in piqueserver is performed with pytest
with tox
support.
Tox manages its own virtual environments, so if you have it installed on your
system, testing is as simple as running tox
, which will run all tests against
all supported python versions (skipping those not available on your system).
If you already are in your virtual env and wish to test something quickly,
pytest
directly may be useful:
# make sure the venv is setup and all deps are installed
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt -r dev-requirements.txt
# build the cython extensions inplace
# otherwise pytest has issues
python setup.py build_ext --inplace
# and test away!
pytest
# single file
pytest tests/piqueserver/test_server.py
Code Coverage¶
Code coverage is generated with coverage.py using a pytest
plugin.
# generate coverage data
pytest --cov=piqueserver --cov=pyspades
# build the report file
coverage html
# view at htmlcov/index.html
Work-flow recommendations¶
- Get yourself comfortable with
git
from command-line, it allows you to do things that some GUIs can’t - Follow the below instructions for commit summaries (a.k.a. the first line)
- No more than 70 characters of length
- Describe an action, in imperative form
- e.g.:
implement anti-cheating optimizations
- See also: Closing issues via commit messages
Finding history¶
Although piqueserver code is based on PySnip and does contain its commits, it’s not possible to see them by default in the GitHub web interface or gitk, due to a commit in the early days of piqueserver that made the imported files be treated as new ones.
To see the true history of a file, you must use an log visualizer that follows renames, such as:
gitk --follow *FILE*
git log --follow --pretty=oneline *OPTIONS*
Architecture¶
Overview¶
The piqueserver codebase is made up out of two main packages: pyspades
and
piqueserver
. The piqueserver
module used to be named feature_server
.
The original developers wanted to make the pyspades a generic AoS protocol and
server implementation which the feature_server
module then subclassed and
specialized.
However, the unclear division and two locations quickly lead to a large mess, and it is currently not possible to know for certain which module exactly contains certain functionality. In general, this is the rule of thumb:
pyspades
: Anything that involves sending and receiving of packets and acting on those, keeping game state.piqueserver
: Anything player-facing, for example commands, configuration, etc.
Note however the numerous exceptions to this. For example, parts of the command
logic are in pyspades
, while a lot of server validation logic is in
piqueserver
Classes¶
There are currently two classes which contain the bulk of the logic.
Connection
, and Protocol
. The Connection
class does not actually
represent a connection, it represents a player connected to the server and is
contained in the player.py
file in the relevant module. The Protocol
object is similar, but represents the server and is in the server.py
file.
Many classes and modules have descriptions you can view in this documentations or in the files themselves.
Extension Scripts¶
Piqueserver supports extension scripts aka “scripts” that modify it’s behaviour. The mechanism used to implement these is pretty ugly.
Each script defines an apply_script(protocol, connection, config)
function.
This function is called on script initialization with the protocol class, connection
class and the config dict. Scripts are intended to then dynamically subclass the
protocol and connection classes and return those, overriding methods where
needed:
def apply_script(protocol, connection, config):
class ScriptNameProtocol(protocol):
def my_overridden_function(self, arg):
...
return protocol.my_overridden_function(self, arg)
...
class ScriptNameConnection(connection):
...
return ScriptNameProtocol, ScriptNameConnection
The application of these scripts is performed in a loop, apply_script
always being
called with the classes returned by the last invocation. This way, the final class
created inherits from all extension classes.
This is a terrible idea for a number of reasons, but just the way things work currently:
- Extensions must meddle with the internals of piqueserver. This means that scripts are likely to break whenever any internals are changed, making substatial changes harder.
- It is impossible to load or unload scripts after starting the server
- There is no clear and defined API for scripts. This makes writing scripts unecessarily difficult and also increases breakage.
- Debugging this is very hard
Game mode scripts are identical to regular extension scripts in functionality. However,
they are required to define an attribute named game_mode
on the Protocol
class
that describes the base game mode, CTF_MODE
or TC_MODE
. This is required because
at a protocol level, AoS currently only supports those two game modes. Any other game
modes must be emulated using the functionality provided by these two game modes.
Startup and Initialization¶
Startup and initialization of the server is currently poorly defined. The phases are roughly as follows:
Server Initialization¶
Config loading¶
The config and command-line arguments are loaded first, because they are required to proceed further.
Module initialization¶
The asyncio and twisted reactors are initialized. The files defining the game
logic in piqueserver/
and pyspades/
are imported via
piqueserver.server
.
Script Loading¶
The way the script extension system works means that scripts can only be loaded
before the two main classes, Connection
and Protocol
, are instantiated.
In this phase, the scripts defined in the config are loaded. This consists of four sub-phases:
- All scripts defined under
scripts
in the config are loaded, either from the config directory, or fromsys.path
. apply_script
is called on all scripts, in the order that they are declared in the config.- If the game mode is not
"ctf"
or"tc"
for which the logic is built-in, the game mode is imported as a script. apply_script
is called on the game mode script
Protocol Initialization¶
The Protocol
class created in the previous step is instantiated, calling
it’s __init__
method. This does the following:
- Configure logging
- Read configuration such as map rotation, team names, time limits, win conditions
- Load the ban list
- Import and initialize auxilliary functionality like SSH, status server, banpublish/bansubscribe, command console.
- Initialize user configuration
- Resolve the filenames of the map rotation
- Create the
enet.Host
object, listening on the socket. - Create the
Team
andWorld
objects. - Call
protocol.on_advance(map_name)
with the name of the map that is about to be loaded. - Schedule future tasks such as the update check, ban vaccum, map loading, annoucements, game end, update loop and master server connection.
Config Validation¶
The configuration is validated for any errors or unused keys.
Event Loop Startup¶
Control is passed to the Twisted/AsyncIO event loop, which drives everything from here on out.
Map Loading¶
The map is loaded or generated in a background thread. This is done to prevent connections from timing out on slow hardware.
Once complete, protocol.on_map_change
, and Team.initialize()
are
called.
Map Change¶
Map change is triggered by protocol.advance_rotation
This:
- Calls
protocol.on_advance
with the next map. - If a message was specified, print it and wait 10 seconds.
- Load or generate the next map.
- Call
protocol.on_map_leave
- Call
map_info.on_map_leave
- Replace the loaded map with the new one.
- Call
Team.initialize
Game Mode Initialization¶
Games are defined by the game mode. They usually represent a period of time where two teams compete for points and end with one team winning or losing, or some other condition such as a time limit being hit.
There is currently no hook for when the game starts. However, existing modes
assume it starts with the on_map_change
call.
When a game ends, the game mode will call on_game_end
to notify any other
scripts and possibly trigger a map change.
Player Lifecycle¶
Players join and play the game in a number of phases and states:
Connection Start¶
An ENet connection handshake is performed. protocol.on_connect
is called
once complete.
This creates a new Connection
object, on which connection.on_connect
is
called. This decides if the player should be allowed to join based on
information such as the player count, IP or protocol version.
Map Transfer¶
The map is generated and sent to the player. A snapshot of current player state is saved, on top of which changes occurring during map transfer will be layered. A handshake is started to identify the client version and available protocol extensions.
On map transfer completion, connection.on_join
will be called.
Limbo¶
After map transfer, players are in the “Limbo” state. They are in this state
until the client sends an ExistingPlayer
packet containing the chosen name
and team ID.
Joined¶
Once a team is selected, connection.on_team_join
is called to validate the
team choice. connection.on_login
is then called to validate the chosen
name.
Spawned¶
When a player is about to be spawned, connection.on_spawn_location
is
called to allow overriding the position. connection.on_spawn
is called when
the spawn is performed.
Dead¶
When a player dies, connection.on_kill
is called.
Release Guide¶
Ensure we’re ready for release¶
- branch should be up to date
- github action builds should be passing
- test with a clean install on local machine if possible
- all the following should run without error (assuming Linux machine):
# make sure we're clean and up to date
git checkout master
git pull
git clean -xffd
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt -r dev-requirements.txt
# build and install
python setup.py install
python setup.py build_ext --inplace
# run the tests
tox
# ensure the server is runnable
piqueserver -d piqueserver/config
Notes before continuing¶
These next steps involve pushing the packages to pypi as we go. Probably a safer workflow would be to build the packages first, then update Git with the version changes, and finally push to pypi. There is also the test pypi instance to experiment with uploading packages if required.
Most important to remember is the step where we edit some files to bump the version info.
Build the sdist¶
Prerequisites: Linux computer, python3.7
(or greater), pip
(same
version as the python you’re using), twine
The source distribution is OS agnostic, so this is the easiest to start with.
- deactivate any venvs and ensure we’re back in a clean state on the correct branch:
git checkout master # or release branch if this is a bug fix on old supported version
git clean -xffd
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt -r dev-requirements.txt
- IMPORTANT: update
piqueserver/version.py
with the new version numbers (this should be the single source of version info for piqueserver). - build and upload the source distribution:
python setup.py sdist
twine upload dist/*
Build Linux binary wheels¶
Prerequisites: same as for sdist, plus docker
- make sure docker is running and you have a recent version of the pypa manylinux1 docker image
sudo docker pull quay.io/pypa/manylinux1_x86_64
- build and upload the linux binary wheels:
./scripts/build_wheels.sh
twine upload wheelhouse/*
Build Windows binary wheels¶
Use the download-wheels tool to fetch the wheels from github actions.
python download_wheels.py --ghtoken <your github token> -d winbuilds/
Update git¶
Technically this can happen once we’re sure this will be a release, but if done after building the packages, at least we know it’s all fine.
- add, commit, tag, and push the version changes:
git add -A
git commit -m "release version X"
git tag -a "v0.1.2"
git push
git push --tags
- merge master across to the release branch if required:
git checkout v0.1.x
git merge master
git push
- create and publish release notes on the pushed tag on GitHub
Celebrate!¶
🎉
piqueserver package¶
Module contents¶
Subpackages¶
piqueserver.core_commands package¶
Submodules¶
piqueserver.core_commands.game module¶
-
piqueserver.core_commands.game.
fog
(connection, *args)[source]¶ Set the fog color /fog red green blue (all values 0-255) /fog #aabbcc (hex representation of rgb) /fog #abc (short hex representation of rgb)
-
piqueserver.core_commands.game.
get_time_limit
(connection)[source]¶ Tell you the current time limit /time
-
piqueserver.core_commands.game.
global_chat
(connection, value=None)[source]¶ Enable or disable global chat /globalchat [on|off] Toggles if no arguments are given
-
piqueserver.core_commands.game.
lock
(connection, value)[source]¶ Make a specified team no longer joinable until it’s unlocked /lock <blue|green|spectator> New players will be placed in the spectator team even if it’s locked
-
piqueserver.core_commands.game.
set_balance
(connection, value)[source]¶ Turn automatic balancing on or off /setbalance <on|off>
-
piqueserver.core_commands.game.
set_time_limit
(connection, duration)[source]¶ Set this game time limit /timelimit <duration>
-
piqueserver.core_commands.game.
switch
(connection, player, team=None)[source]¶ Switch teams either for yourself or for a given player /switch [player] [team]
-
piqueserver.core_commands.game.
toggle_build
(connection, player=None)[source]¶ Toggle building for everyone in the server or for a given player /togglebuild [player]
-
piqueserver.core_commands.game.
toggle_kill
(connection, player=None)[source]¶ Toggle killing for everyone in the server or for a given player /togglekill [player]
piqueserver.core_commands.info module¶
-
piqueserver.core_commands.info.
help_command
(connection, command_name=None)[source]¶ Gives description and usage info for a command /help <command_name>
piqueserver.core_commands.map module¶
-
piqueserver.core_commands.map.
advance
(connection)[source]¶ Force the next map to be immediately loaded instead of waiting for the time limit to end /advancemap
-
piqueserver.core_commands.map.
change_planned_map
(connection, *pre_maps)[source]¶ Set the next map to be loaded after current game ends and inform everyone of it /map <mapname>
-
piqueserver.core_commands.map.
change_rotation
(connection, *pre_maps)[source]¶ Change the current map rotation and informs everyone on the server of it /rotation <map1> … <mapN>
-
piqueserver.core_commands.map.
load_map
(connection, map)[source]¶ Instantly switches map to the specified /loadmap <mapname>
-
piqueserver.core_commands.map.
mapname
(connection)[source]¶ Tell you what’s the name of the current map /mapname
-
piqueserver.core_commands.map.
revert_rotation
(connection)[source]¶ Invert the current map rotation /revertrotation
piqueserver.core_commands.moderation module¶
-
piqueserver.core_commands.moderation.
ban
(connection, value, *arg)[source]¶ Ban a given player forever or for a limited amount of time. /ban <player> [duration] [reason]
-
piqueserver.core_commands.moderation.
banip
(connection, ip, *arg)[source]¶ Ban an ip /banip <ip> [duration] [reason]
-
piqueserver.core_commands.moderation.
dban
(connection, value, *arg)[source]¶ Ban a given player for one day /dban <player> [reason]
-
piqueserver.core_commands.moderation.
get_ban_arguments
(connection, args)[source]¶ Parses duration and reason from arguments. It handles duration in two ways: interger mintues and human-friendly duration. It also handles cases where duration or reason are none. Note: It returns duration in seconds.
-
piqueserver.core_commands.moderation.
god
(connection, player=None)[source]¶ Go into god mode and inform everyone on the server of it /god [player]
-
piqueserver.core_commands.moderation.
god_build
(connection, player)[source]¶ Place blocks that can be destroyed only by players with godmode activated /godbuild [player]
-
piqueserver.core_commands.moderation.
godsilent
(connection, player=None)[source]¶ Silently go into god mode /godsilent [player]
-
piqueserver.core_commands.moderation.
hban
(connection, value, *arg)[source]¶ Ban a given player for an hour /hban <player> [reason]
-
piqueserver.core_commands.moderation.
invisible
(connection, player)[source]¶ Turn invisible /invisible [player]
-
piqueserver.core_commands.moderation.
ip
(connection, player)[source]¶ Get the IP of a user /ip [player]
-
piqueserver.core_commands.moderation.
kick
(connection, value, *arg)[source]¶ Kick a given player /kick <player> Player is the #ID of the player, or an unique part of their name
-
piqueserver.core_commands.moderation.
pban
(connection, value, *arg)[source]¶ Ban a given player permanently /pban <player> [reason]
-
piqueserver.core_commands.moderation.
say
(connection, *arg)[source]¶ Say something in chat as server message /say <text>
-
piqueserver.core_commands.moderation.
unmute
(connection, value)[source]¶ Unmute a player /unmute <player>
piqueserver.core_commands.movement module¶
-
piqueserver.core_commands.movement.
fly
(connection, player)[source]¶ Enable flight /fly [player] Hold control and press space ;)
-
piqueserver.core_commands.movement.
move
(connection, *args)[source]¶ Move yourself or a given player to the specified x/y/z coordinates or sector /move [player] <sector> or /move [player] <x> <y> <z> If you’re invisible, it will happen silently. If the z coordinate makes the player appear underground, put them at ground level instead. If the x/y/z coordinate makes the player appear outside of the world bounds, take the bound instead
You can only move other players if you are admin or have the move_others right
-
piqueserver.core_commands.movement.
move_silent
(connection, *args)[source]¶ Silently move yourself or a given player to the specified x/y/z coordinates or sector /moves [player] <sector> or /moves [player] <x> <y> <z> If the z coordinate makes the player appear underground, put them at ground level instead. If the x/y/z coordinate makes the player appear outside of the world bounds, take the bound instead
You can only move other players if you are admin or have the move_others right
-
piqueserver.core_commands.movement.
teleport
(connection, player1, player2=None, silent=False)[source]¶ Teleport yourself or a given player to another player /teleport [player] <target player>
-
piqueserver.core_commands.movement.
tpsilent
(connection, player1, player2=None)[source]¶ Silently teleport a player to another player /tpsilent [player] <target player>
piqueserver.core_commands.player module¶
-
piqueserver.core_commands.player.
client
(connection, player)[source]¶ Tell you information about your client or the client of a given player /client [player]
-
piqueserver.core_commands.player.
deaf
(connection, value=None)[source]¶ Make you or a given player no longer receive chat messages /deaf [player]
-
piqueserver.core_commands.player.
heal
(connection, player)[source]¶ Heal and refill yourself or a given player and inform everyone on the server of this action /heal [player]
-
piqueserver.core_commands.player.
intel
(connection)[source]¶ Inform you of who has the enemy intel /intel
piqueserver.core_commands.server module¶
-
piqueserver.core_commands.server.
scripts
(connection)[source]¶ Tell you which scripts are enabled on this server currently /scripts
-
piqueserver.core_commands.server.
server_info
(connection)[source]¶ Tell you the name of this server and its aos:// URI /server
-
piqueserver.core_commands.server.
server_name
(connection, *arg)[source]¶ Change the server name until it restarts /servername <new-name> Also affects the master list
piqueserver.core_commands.social module¶
Log in if you’re staff or a trusted member of this server /login <password> You will be kicked if a wrong password is given 3 times in a row
Send a private message to a given player /pm <player> <message>
Send a message to all admins currently online /admin <message>
Module contents¶
Submodules¶
piqueserver.banpublish module¶
-
class
piqueserver.banpublish.
PublishResource
(factory)[source]¶ Bases:
twisted.web.resource.Resource
-
getChild
(name, request)[source]¶ Retrieve a ‘child’ resource from me.
Implement this to create dynamic resource generation – resources which are always available may be registered with self.putChild().
This will not be called if the class-level variable ‘isLeaf’ is set in your subclass; instead, the ‘postpath’ attribute of the request will be left as a list of the remaining path elements.
For example, the URL /foo/bar/baz will normally be:
| site.resource.getChild('foo').getChild('bar').getChild('baz').
However, if the resource returned by ‘bar’ has isLeaf set to true, then the getChild call will never be made on it.
Parameters and return value have the same meaning and requirements as those defined by L{IResource.getChildWithDefault}.
-
piqueserver.bansubscribe module¶
piqueserver.commands module¶
-
class
piqueserver.commands.
CommandHelp
(description, usage, info)¶ Bases:
tuple
-
description
¶ Alias for field number 0
-
info
¶ Alias for field number 2
-
usage
¶ Alias for field number 1
-
-
piqueserver.commands.
add
(func: Callable) → None[source]¶ Function to add a command from scripts. Deprecated
-
piqueserver.commands.
add_rights
(user_type: str, command_name: str) → None[source]¶ Give the user type a new right
>>> add_rights("knights", "say_ni")
-
piqueserver.commands.
admin
(func: Callable) → Callable[source]¶ Shorthand for @restrict(“admin”). Mainly exists for backwards compatibility with pyspades scripts.
>>> @admin ... @command() ... def some_command(x): ... pass
-
piqueserver.commands.
command
(name=None, *aliases, admin_only=False) → Callable[[Callable], Callable][source]¶ Register a new command.
The command will be accessible as
/function_name
unless a name or alias is specified.>>> @command() ... def some_command(x): ... pass
Optional names and aliases:
>>> @command("name", "alias1", "alias2") ... def some_command(x): ... pass
-
piqueserver.commands.
format_command_error
(command_func: Callable, message: str, exception: Exception = None) → str[source]¶ format a help message for a given command
-
piqueserver.commands.
get_command_help
(command_func: Callable) → piqueserver.commands.CommandHelp[source]¶
-
piqueserver.commands.
get_player
(protocol, value: str, spectators=True)[source]¶ Get a player connection object by name or ID.
IDs are formatted as: “#12”
If no player with the specified name is found, it will try to find a player who’s name contains the string
-
piqueserver.commands.
get_rights
(user_type: str) → List[str][source]¶ Get a list of rights a specific user type has.
>>> add_rights("knights", "say_ni") >>> get_rights("knights") ["say_ni"] >>> get_rights("arthur") []
-
piqueserver.commands.
handle_command
(connection, command, parameters)[source]¶ Public facing function to run a command, given the connection, a command name, and a list of parameters.
Will log the command.
-
piqueserver.commands.
player_only
(func: Callable)[source]¶ This recorator restricts a command to only be runnable by players connected to the server, not via other places such as, say, the console.
>>> @command() ... @player_only ... def some_command(x): ... pass
-
piqueserver.commands.
restrict
(*user_types) → Callable[source]¶ restrict the command to only be used by a specific type of user
>>> @restrict("admin", "guard") ... @command() ... def some_command(x): ... pass
-
piqueserver.commands.
target_player
(func: Callable)[source]¶ - This decorator converts first argument of a command to a
piqueserver.FeatureConnection
. - It’s intended for commands which accept single argument for target player eg. /fly [player]. It implicitly uses invoker as target if no arguments are provided. It uses first argument are player name or id for targetting. It forces non-player invokers to provide player argument.
>>> @command() ... @target_player ... def fly(connection, target): ... target.fly = True ... pass
- This decorator converts first argument of a command to a
piqueserver.config module¶
-
class
piqueserver.config.
ConfigStore
[source]¶ Bases:
object
Configuration store that manages global configuration.
Usage example:
>>> config = ConfigStore() >>> config.load_from_dict({'key1': 'value1'})
>>> option1 = config.option('key1', default='nothing', ... validate=lambda x: len(x) > 0) >>> section1 = config.section('section1') >>> nested_option = section1.option('key1', default=0)
>>> print(nested_option.get()) >>> option1.set('hello')
>>> # underlying dictionary structure will look like >>> # { >>> # 'key1': 'hello', >>> # 'section1': { >>> # 'key1': 0 >>> # } >>> # }
-
check_unused
()[source]¶ Return the subset of the underlying dictionary that doesn’t have any corresponding registered options.
-
dump_to_file
(fobj, format_='TOML')[source]¶ Writes the current configuration to a file-like objection, with the format specified by
format_
.
-
load_from_file
(fobj, format_='TOML')[source]¶ Clear the current configuration and load new configuration from a file-like object in a supported format.
-
piqueserver.console module¶
-
class
piqueserver.console.
ConsoleInput
(protocol)[source]¶ Bases:
twisted.protocols.basic.LineReceiver
-
admin
= True¶
-
delimiter
= b'\n'¶
-
lineReceived
(line)[source]¶ Override this for when each line is received.
@param line: The line which was received with the delimiter removed. @type line: C{bytes}
-
name
= 'Console'¶
-
piqueserver.irc module¶
-
class
piqueserver.irc.
IRCBot
[source]¶ Bases:
twisted.words.protocols.irc.IRCClient
-
admin
¶
-
colors
¶
-
joined
(irc_channel)[source]¶ Called when I finish joining a channel.
channel has the starting character (C{‘#’}, C{’&’}, C{‘!’}, or C{‘+’}) intact.
-
left
(irc_channel)[source]¶ Called when I have left a channel.
channel has the starting character (C{‘#’}, C{’&’}, C{‘!’}, or C{‘+’}) intact.
-
name
= None¶
-
nickname
¶ str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.
-
ops
= None¶
-
rights
¶
-
unaliased_name
= None¶
-
userKicked
(kickee, irc_channel, kicker, message)[source]¶ Called when I observe someone else being kicked from a channel.
-
user_types
¶
-
voices
= None¶
-
-
class
piqueserver.irc.
IRCClientFactory
(server, config)[source]¶ Bases:
twisted.internet.protocol.ClientFactory
-
admin
= None¶
-
aliases
= None¶
-
bot
= None¶
-
buildProtocol
(address)[source]¶ Create an instance of a subclass of Protocol.
The returned instance will handle input on an incoming server connection, and an attribute “factory” pointing to the creating factory.
Alternatively, L{None} may be returned to immediately close the new connection.
Override this method to alter how Protocol instances get created.
@param addr: an object implementing L{IAddress}
-
clientConnectionFailed
(connector, reason)[source]¶ Called when a connection has failed to connect.
It may be useful to call connector.connect() - this will reconnect.
@type reason: L{twisted.python.failure.Failure}
-
clientConnectionLost
(connector, reason)[source]¶ Called when an established connection is lost.
It may be useful to call connector.connect() - this will reconnect.
@type reason: L{twisted.python.failure.Failure}
-
colors
= True¶
-
failed_reconnect_delay
= 60¶
-
lost_reconnect_delay
= 20¶
-
rights
= None¶
-
startedConnecting
(connector)[source]¶ Called when a connection has been started.
You can call connector.stopConnecting() to stop the connection attempt.
@param connector: a Connector object.
-
user_types
= None¶
-
piqueserver.map module¶
-
class
piqueserver.map.
Map
(rot_info: piqueserver.map.RotationInfo, load_dir: str)[source]¶ Bases:
object
-
piqueserver.map.
check_rotation
(maps: List[Union[str, RotationInfo]], load_dir: Optional[str] = None) → List[piqueserver.map.RotationInfo][source]¶ Checks if provided maps exist in maps dir. and returns an array of RotationInfo objects for those maps. Raises MapNotFound exception if maps are not found.
piqueserver.player module¶
-
class
piqueserver.player.
FeatureConnection
(*args, **kwargs)[source]¶ Bases:
pyspades.player.ServerConnection
-
on_animation_update
(jump: bool, crouch: bool, sneak: bool, sprint: bool) → Tuple[bool, bool, bool, bool][source]¶
-
on_chat
(value: str, global_message: bool) → Union[str, bool][source]¶ notifies when the server receives a chat message
return False to block sending the message
-
on_hit
(hit_amount: float, player: piqueserver.player.FeatureConnection, _type: int, grenade: pyspades.world.Grenade) → Optional[bool][source]¶
-
send_lines
(lines: List[str], key: str = 'unknown') → None[source]¶ Send a list of lines to the player.
‘key’ is a unique identifier for the lines being sent - for example, a message saying ‘3 medkits are ready!’ could use the key ‘medkits.ready’. The key is used to avoid sending two messages of the same variety at once, to protect the server against a vulnerability which exploits this function.
The key should always be specified when calling this function. The default value of ‘unknown’ exists simply for backwards compatibility.
-
piqueserver.run module¶
piqueserver.scheduler module¶
piqueserver.server module¶
pyspades - default/featured server
-
class
piqueserver.server.
FeatureProtocol
(interface: bytes, config_dict: Dict[str, Any])[source]¶ Bases:
pyspades.server.ServerProtocol
-
add_ban
(ip, reason, duration, name=None)[source]¶ Ban an ip with an optional reason and duration in seconds. If duration is None, ban is permanent.
-
advance_call
= None¶
-
advance_rotation
(message: Optional[str] = None) → twisted.internet.defer.Deferred[source]¶ Advances to the next map in the rotation. If message is provided it will send it to the chat, waits for 10 seconds and then advances.
Returns: Deferred that fires when the map has been loaded
-
balanced_teams
= None¶
-
ban_manager
= None¶
-
ban_publish
= None¶
-
bans
= None¶
-
broadcast_chat
(value, global_message=True, sender=None, team=None, irc=False)[source]¶ Send a chat message to many users
-
building
= True¶
-
command_antispam
= False¶
-
connection_class
¶ alias of
piqueserver.player.FeatureConnection
-
default_fog
= (128, 232, 255)¶
-
everyone_is_admin
= False¶
-
game_mode
= None¶
-
global_chat
= True¶
-
god_blocks
= None¶
-
identifier
= None¶
-
interface
= None¶
-
ip
= None¶
-
irc_relay
= None¶
-
killing
= True¶
-
last_time
= None¶
-
make_map
(rot_info: piqueserver.map.RotationInfo) → twisted.internet.defer.Deferred[source]¶ Creates and returns a Map object from rotation info in a new thread
Returns: Deferred that resolves to a Map
object.
-
map_info
= None¶
-
master
= False¶
-
master_reconnect_call
= None¶
-
planned_map
= None¶
-
player_memory
= None¶
-
receive_callback
(address: enet.Address, data: bytes) → int[source]¶ This hook receives the raw UDP data before it is processed by enet
-
remote_console
= None¶
-
set_map_rotation
(maps: List[str]) → None[source]¶ Over-writes the current map rotation with provided one.
FeatureProtocol.advance_rotation
still needs to be called to actually change the map,
-
spawns
= None¶
-
team_class
¶ alias of
FeatureTeam
-
time_announce_schedule
= None¶
-
timestamps
= None¶
-
user_blocks
= None¶
-
-
class
piqueserver.server.
FeatureTeam
(team_id: int, name: str, color: Tuple[int, int, int], spectator: bool, protocol: pyspades.protocol.BaseProtocol)[source]¶ Bases:
pyspades.team.Team
-
locked
= False¶
-
piqueserver.ssh module¶
piqueserver.statistics module¶
-
class
piqueserver.statistics.
StatsClient
[source]¶ Bases:
piqueserver.statistics.StatsProtocol
-
connectionMade
()[source]¶ Called when a connection is made.
This may be considered the initializer of the protocol, because it is called when the connection is completed. For clients, this is called once the connection to the server has been established; for servers, this is called after an accept() call stops blocking and a socket has been received. If you need to send any greeting or initial message, do it here.
-
login_defers
= None¶
-
server
= None¶
-
-
class
piqueserver.statistics.
StatsClientFactory
(name, password, callback)[source]¶ Bases:
twisted.internet.protocol.ReconnectingClientFactory
-
maxDelay
= 20¶
-
protocol
¶ alias of
StatsClient
-
-
class
piqueserver.statistics.
StatsFactory
(password)[source]¶ Bases:
twisted.internet.protocol.ServerFactory
-
protocol
¶ alias of
StatsServer
-
-
class
piqueserver.statistics.
StatsProtocol
[source]¶ Bases:
twisted.protocols.basic.Int16StringReceiver
-
class
piqueserver.statistics.
StatsServer
[source]¶ Bases:
piqueserver.statistics.StatsProtocol
-
connectionLost
(reason)[source]¶ Called when the connection is shut down.
Clear any circular references here, and any external references to this Protocol. The connection has been closed.
@type reason: L{twisted.python.failure.Failure}
-
connectionMade
()[source]¶ Called when a connection is made.
This may be considered the initializer of the protocol, because it is called when the connection is completed. For clients, this is called once the connection to the server has been established; for servers, this is called after an accept() call stops blocking and a socket has been received. If you need to send any greeting or initial message, do it here.
-
piqueserver.statusserver module¶
-
class
piqueserver.statusserver.
AccessLogger
(logger: logging.Logger, log_format: str)[source]¶ Bases:
aiohttp.abc.AbstractAccessLogger
piqueserver.version module¶
pyspades package¶
Module contents¶
pyspades - Ace of Spades network protocol implementations
Submodules¶
pyspades.bytes module¶
The ByteReader/Bytewriter classes are used to read and write various data types from and to byte-like objects. This is used e.g. to read the contents of packets.
-
class
pyspades.bytes.
ByteReader
(input_data, int start=0, int size=-1)¶ Bases:
object
Reads various data types from a bytes-like object
-
dataLeft
(self) → int¶ get the number of bytes left in the buffer
Returns: The number of bytes left Return type: int
-
read
(self, int bytecount=-1)¶ read a number of bytes
Parameters: bytecount (int, optional) – The number of bytes to read. If omitted, all bytes available are read Returns: bytecount
bytes of dataReturn type: bytes
-
readByte
(self, bool unsigned=False) → int¶ read one byte of data as integer
Parameters: unsigned (bool) – If true, interpret the byte as unsigned Returns: The value of the byte as int Return type: int
-
readFloat
(self, bool big_endian=True) → float¶ read four bytes of data as floating point number
Parameters: big_endian (bool, optional) – If true, interpret the bytes as big endian Returns: The value of the bytes as float Return type: float
-
readInt
(self, bool unsigned=False, bool big_endian=True) → long long¶ read four bytes of data as integer
Parameters: Returns: The value of the bytes as int
Return type:
-
readReader
(self, int size=-1) → ByteReader¶
-
readShort
(self, bool unsigned=False, bool big_endian=True) → int¶ read two bytes of data as integer
Parameters: Returns: The value of the bytes as int
Return type:
-
readString
(self, int size=-1) → bytes¶ read a string
Parameters: size (int) – If set, read size
bytes, else read all bytes availableReturns: The value of the bytes Return type: bytes
-
rewind
(self, int value)¶ move the position
bytecount
bytes backParameters: bytecount – number of bytes to move back
-
skipBytes
(self, int bytecount)¶ move the position
bytecount
bytes aheadParameters: bytecount – number of bytes to move ahead
-
-
class
pyspades.bytes.
ByteWriter
¶ Bases:
object
-
pad
(self, int bytecount)¶
-
rewind
(self, int bytecount)¶
-
tell
(self) → size_t¶
-
write
(self, data)¶
-
writeByte
(self, int value, bool unsigned=False)¶
-
writeFloat
(self, float value, bool big_endian=True)¶
-
writeInt
(self, long long value, bool unsigned=False, bool big_endian=True)¶
-
writeShort
(self, int value, bool unsigned=False, bool big_endian=True)¶
-
writeString
(self, value, int size=-1)¶
-
writeStringSize
(self, char *value, int size)¶
-
pyspades.collision module¶
pyspades.color module¶
pyspades.common module¶
-
class
pyspades.common.
Quaternion
(*arg)¶ Bases:
object
-
copy
(self)¶
-
get
(self)¶
-
get_matrix
(self)¶
-
inverse_transform_vector
(self, Vertex3 v) → Vertex3¶
-
multiply_scalar
(self, double k)¶
-
nlerp
(self, Quaternion q, double t) → Quaternion¶
-
normalize
(self)¶
-
set
(self, double w, double x, double y, double z)¶
-
set_angle_axis
(self, double radians, Vertex3 axis) → Quaternion¶
-
slerp
(self, Quaternion q, double t) → Quaternion¶
-
transform_vector
(self, Vertex3 v) → Vertex3¶
-
w
¶ ‘double’
Type: w
-
x
¶ ‘double’
Type: x
-
y
¶ ‘double’
Type: y
-
z
¶ ‘double’
Type: z
-
-
class
pyspades.common.
Vertex3
(is_ref=False, *arg)¶ Bases:
object
-
copy
(self)¶
-
cross
(self, Vertex3 A)¶
-
distance
(self, Vertex3 other)¶ calculate euclidean (straight line) distance between two
Vertex3
as points in 3d space. Equivalent to(a - b).length()
.
-
dot
(self, Vertex3 A)¶
-
get
(self)¶
-
get_rotation_to
(self, Vertex3 A) → Quaternion¶
-
is_zero
(self)¶
-
length
(self)¶
-
length_sqr
(self)¶ calculate the square length of the vertex3. This is a bit faster than getting the length, as it avoids the expensive
sqrt
call.
-
normal
(self)¶
-
normalize
(self)¶
-
perp_dot
(self, Vertex3 A)¶
-
rotate
(self, Vertex3 A)¶
-
set
(self, float x, float y, float z)¶
-
set_vector
(self, Vertex3 vector)¶
-
translate
(self, double x, double y, double z)¶
-
unrotate
(self, Vertex3 A)¶
-
x
¶
-
y
¶
-
z
¶
-
zero
(self)¶
-
-
pyspades.common.
coordinates
(data)¶
-
pyspades.common.
crc32
(data)¶
-
pyspades.common.
decode
(value)¶
-
pyspades.common.
encode
(value)¶
-
pyspades.common.
escape_control_codes
(untrusted_str)¶ escape all ascii control codes in a string note: this still leaves things like special unicode characters in place
-
pyspades.common.
get_color
(color)¶
-
pyspades.common.
make_color
(r, g, b)¶
-
pyspades.common.
prettify_timespan
(total, get_seconds=False)¶
-
pyspades.common.
to_coordinates
(x, y)¶
pyspades.constants module¶
pyspades.contained module¶
This module contains the definitions and registrations for the various packets used in the server
-
class
pyspades.contained.
BlockAction
¶ Bases:
pyspades.loaders.Loader
-
id
= 13¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
value
¶ ‘int’
Type: value
-
write
(self, ByteWriter writer)¶
-
x
¶ ‘int’
Type: x
-
y
¶ ‘int’
Type: y
-
z
¶ ‘int’
Type: z
-
-
class
pyspades.contained.
BlockLine
¶ Bases:
pyspades.loaders.Loader
-
id
= 14¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
x1
¶ ‘int’
Type: x1
-
x2
¶ ‘int’
Type: x2
-
y1
¶ ‘int’
Type: y1
-
y2
¶ ‘int’
Type: y2
-
z1
¶ ‘int’
Type: z1
-
z2
¶ ‘int’
Type: z2
-
-
class
pyspades.contained.
CTFState
¶ Bases:
pyspades.loaders.Loader
-
cap_limit
¶ ‘unsigned int’
Type: cap_limit
-
id
= 0¶
-
read
(self, ByteReader reader)¶
-
team1_base_x
¶ ‘float’
Type: team1_base_x
-
team1_base_y
¶ ‘float’
Type: team1_base_y
-
team1_base_z
¶ ‘float’
Type: team1_base_z
-
team1_carrier
¶ ‘unsigned int’
Type: team1_carrier
-
team1_flag_x
¶ ‘float’
Type: team1_flag_x
-
team1_flag_y
¶ ‘float’
Type: team1_flag_y
-
team1_flag_z
¶ ‘float’
Type: team1_flag_z
-
team1_has_intel
¶ ‘bool’
Type: team1_has_intel
-
team1_score
¶ ‘unsigned int’
Type: team1_score
-
team2_base_x
¶ ‘float’
Type: team2_base_x
-
team2_base_y
¶ ‘float’
Type: team2_base_y
-
team2_base_z
¶ ‘float’
Type: team2_base_z
-
team2_carrier
¶ ‘unsigned int’
Type: team2_carrier
-
team2_flag_x
¶ ‘float’
Type: team2_flag_x
-
team2_flag_y
¶ ‘float’
Type: team2_flag_y
-
team2_flag_z
¶ ‘float’
Type: team2_flag_z
-
team2_has_intel
¶ ‘bool’
Type: team2_has_intel
-
team2_score
¶ ‘unsigned int’
Type: team2_score
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
ChangeTeam
¶ Bases:
pyspades.loaders.Loader
-
id
= 29¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
team
¶ ‘int’
Type: team
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
ChangeWeapon
¶ Bases:
pyspades.loaders.Loader
-
id
= 30¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
weapon
¶ ‘int’
Type: weapon
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
ChatMessage
¶ Bases:
pyspades.loaders.Loader
-
chat_type
¶ ‘unsigned int’
Type: chat_type
-
id
= 17¶
-
player_id
¶ ‘unsigned int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
value
¶ object
Type: value
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
CreatePlayer
¶ Bases:
pyspades.loaders.Loader
-
id
= 12¶
-
name
¶ object
Type: name
-
player_id
¶ ‘unsigned int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
team
¶ ‘int’
Type: team
-
weapon
¶ ‘unsigned int’
Type: weapon
-
write
(self, ByteWriter writer)¶
-
x
¶ ‘float’
Type: x
-
y
¶ ‘float’
Type: y
-
z
¶ ‘float’
Type: z
-
-
class
pyspades.contained.
ExistingPlayer
¶ Bases:
pyspades.loaders.Loader
-
color
¶ ‘unsigned int’
Type: color
-
id
= 9¶
-
kills
¶ ‘int’
Type: kills
-
name
¶ object
Type: name
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
team
¶ ‘int’
Type: team
-
tool
¶ ‘int’
Type: tool
-
weapon
¶ ‘int’
Type: weapon
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
FogColor
¶ Bases:
pyspades.loaders.Loader
-
color
¶ ‘int’
Type: color
-
id
= 27¶
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
GrenadePacket
¶ Bases:
pyspades.loaders.Loader
-
id
= 6¶
-
player_id
¶ ‘int’
Type: player_id
-
position
¶ tuple
Type: position
-
read
(self, ByteReader reader)¶
-
value
¶ ‘float’
Type: value
-
velocity
¶ tuple
Type: velocity
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
HandShakeInit
¶ Bases:
pyspades.loaders.Loader
-
id
= 31¶
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
HandShakeReturn
¶ Bases:
pyspades.loaders.Loader
-
id
= 32¶
-
read
(self, ByteReader reader)¶
-
success
¶ ‘int’
Type: success
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
HitPacket
¶ Bases:
pyspades.loaders.Loader
-
id
= 5¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
value
¶ ‘int’
Type: value
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
InputData
¶ Bases:
pyspades.loaders.Loader
-
crouch
¶ ‘bool’
Type: crouch
-
down
¶ ‘bool’
Type: down
-
id
= 3¶
-
jump
¶ ‘bool’
Type: jump
-
left
¶ ‘bool’
Type: left
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
right
¶ ‘bool’
Type: right
-
sneak
¶ ‘bool’
Type: sneak
-
sprint
¶ ‘bool’
Type: sprint
-
up
¶ ‘bool’
Type: up
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
IntelCapture
¶ Bases:
pyspades.loaders.Loader
-
id
= 23¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
winning
¶ ‘bool’
Type: winning
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
IntelDrop
¶ Bases:
pyspades.loaders.Loader
-
id
= 25¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
x
¶ ‘float’
Type: x
-
y
¶ ‘float’
Type: y
-
z
¶ ‘float’
Type: z
-
-
class
pyspades.contained.
IntelPickup
¶ Bases:
pyspades.loaders.Loader
-
id
= 24¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
KillAction
¶ Bases:
pyspades.loaders.Loader
-
id
= 16¶
-
kill_type
¶ ‘int’
Type: kill_type
-
killer_id
¶ ‘int’
Type: killer_id
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
respawn_time
¶ ‘int’
Type: respawn_time
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
MapChunk
¶ Bases:
pyspades.loaders.Loader
-
data
¶ object
Type: data
-
id
= 19¶
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
MapStart
¶ Bases:
pyspades.loaders.Loader
-
id
= 18¶
-
read
(self, ByteReader reader)¶
-
size
¶ ‘unsigned int’
Type: size
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
MoveObject
¶ Bases:
pyspades.loaders.Loader
-
id
= 11¶
-
object_type
¶ ‘unsigned int’
Type: object_type
-
read
(self, ByteReader reader)¶
-
state
¶ ‘unsigned int’
Type: state
-
write
(self, ByteWriter writer)¶
-
x
¶ ‘float’
Type: x
-
y
¶ ‘float’
Type: y
-
z
¶ ‘float’
Type: z
-
-
class
pyspades.contained.
ObjectTerritory
¶ Bases:
pyspades.loaders.Loader
-
item
¶ object
Type: item
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
OrientationData
¶ Bases:
pyspades.loaders.Loader
-
id
= 1¶
-
read
(self, ByteReader reader)¶
-
set
(self, pos)¶
-
write
(self, ByteWriter writer)¶
-
x
¶ ‘float’
Type: x
-
y
¶ ‘float’
Type: y
-
z
¶ ‘float’
Type: z
-
-
class
pyspades.contained.
PlayerLeft
¶ Bases:
pyspades.loaders.Loader
-
id
= 20¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
PositionData
¶ Bases:
pyspades.loaders.Loader
-
id
= 0¶
-
read
(self, ByteReader reader)¶
-
set
(self, pos)¶
-
write
(self, ByteWriter writer)¶
-
x
¶ ‘float’
Type: x
-
y
¶ ‘float’
Type: y
-
z
¶ ‘float’
Type: z
-
-
class
pyspades.contained.
ProgressBar
¶ Bases:
pyspades.loaders.Loader
-
capturing_team
¶ ‘unsigned int’
Type: capturing_team
-
id
= 22¶
-
object_index
¶ ‘unsigned int’
Type: object_index
-
progress
¶ ‘float’
Type: progress
-
rate
¶ ‘int’
Type: rate
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
ProtocolExtensionInfo
¶ Bases:
pyspades.loaders.Loader
packet used to exchange the list of supported protocol extensions between server and client
extensions is a list of (extension_id, version) tuples
-
extensions
¶ list
Type: extensions
-
id
= 60¶
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
Restock
¶ Bases:
pyspades.loaders.Loader
-
id
= 26¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
SetColor
¶ Bases:
pyspades.loaders.Loader
-
id
= 8¶
-
player_id
¶ ‘unsigned int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
value
¶ ‘unsigned int’
Type: value
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
SetHP
¶ Bases:
pyspades.loaders.Loader
-
hp
¶ ‘int’
Type: hp
-
id
= 5¶
-
not_fall
¶ ‘int’
Type: not_fall
-
read
(self, ByteReader reader)¶
-
source_x
¶ ‘float’
Type: source_x
-
source_y
¶ ‘float’
Type: source_y
-
source_z
¶ ‘float’
Type: source_z
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
SetTool
¶ Bases:
pyspades.loaders.Loader
-
id
= 7¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
value
¶ ‘int’
Type: value
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
ShortPlayerData
¶ Bases:
pyspades.loaders.Loader
-
id
= 10¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
team
¶ ‘int’
Type: team
-
weapon
¶ ‘int’
Type: weapon
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
StateData
¶ Bases:
pyspades.loaders.Loader
-
fog_color
¶ tuple
Type: fog_color
-
id
= 15¶
-
player_id
¶ ‘int’
Type: player_id
-
read
(self, ByteReader reader)¶
-
state
¶ pyspades.loaders.Loader
Type: state
-
team1_color
¶ tuple
Type: team1_color
-
team1_name
¶ object
Type: team1_name
-
team2_color
¶ tuple
Type: team2_color
-
team2_name
¶ object
Type: team2_name
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
TCState
¶ Bases:
pyspades.loaders.Loader
-
id
= 1¶
-
read
(self, ByteReader reader)¶
-
set_entities
(self, items)¶
-
territories
¶ list
Type: territories
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
Territory
¶ Bases:
pyspades.loaders.Loader
-
read
(self, ByteReader reader)¶
-
state
¶ ‘unsigned int’
Type: state
-
write
(self, ByteWriter writer)¶
-
x
¶ ‘float’
Type: x
-
y
¶ ‘float’
Type: y
-
z
¶ ‘float’
Type: z
-
-
class
pyspades.contained.
TerritoryCapture
¶ Bases:
pyspades.loaders.Loader
-
id
= 21¶
-
object_index
¶ ‘unsigned int’
Type: object_index
-
read
(self, ByteReader reader)¶
-
state
¶ ‘unsigned int’
Type: state
-
winning
¶ ‘unsigned int’
Type: winning
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
VersionRequest
¶ Bases:
pyspades.loaders.Loader
-
id
= 33¶
-
read
(self, ByteReader reader)¶
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
VersionResponse
¶ Bases:
pyspades.loaders.Loader
-
client
¶ unicode
Type: client
-
id
= 34¶
-
os_info
¶ unicode
Type: os_info
-
read
(self, ByteReader reader)¶
-
version
¶ tuple
Type: version
-
write
(self, ByteWriter writer)¶
-
-
class
pyspades.contained.
WeaponInput
¶ Bases:
pyspades.loaders.Loader
-
id
= 4¶
-
player_id
¶ ‘int’
Type: player_id
-
primary
¶ ‘bool’
Type: primary
-
read
(self, ByteReader reader)¶
-
secondary
¶ ‘bool’
Type: secondary
-
write
(self, ByteWriter writer)¶
-
pyspades.entities module¶
-
class
pyspades.entities.
Base
(entity_id, protocol, *arg, **kw)[source]¶ Bases:
pyspades.entities.Entity
-
class
pyspades.entities.
Entity
(entity_id, protocol, *arg, **kw)[source]¶ Bases:
pyspades.common.Vertex3
-
team
= None¶
-
-
class
pyspades.entities.
Flag
(entity_id, protocol, *arg, **kw)[source]¶ Bases:
pyspades.entities.Entity
-
player
= None¶
-
-
class
pyspades.entities.
Territory
(*arg, **kw)[source]¶ Bases:
pyspades.entities.Flag
-
capturing_team
= None¶
-
finish_call
= None¶
-
get_progress
(set=False)[source]¶ Return progress (between 0 and 1 - 0 is full blue control, 1 is full green control) and optionally set the current progress.
-
players
= None¶
-
progress
= 0.0¶
-
rate
= 0¶
-
rate_value
= 0.0¶
-
start
= None¶
-
pyspades.loaders module¶
pyspades.mapgenerator module¶
The map generator is responsible for generating the map bytes that get sent to the client on connect
-
class
pyspades.mapgenerator.
ProgressiveMapGenerator
(map_, parent=False)[source]¶ Bases:
object
Progressively generates the stream of bytes sent to the client for map downloads.
It supports two modes. In the default parent=False mode, reading is normal.
In the
parent=True
mode a child generator is created withget_child
to actually read the data. This is presumably done so that the work of map generation is not duplicated for each client if several connect at the same time.-
all_data
= b''¶
-
data
= b''¶
-
done
= False¶
-
pos
= 0¶
-
pyspades.mapmaker module¶
-
class
pyspades.mapmaker.
BiomeMap
(biomes, width=32, height=32)¶ Bases:
object
A tilemap containing biome data for a HeightMap.
-
biomes
¶ list
Type: biomes
-
create_heightmap
(self)¶ Return a HeightMap with unfinished color data and a list of gradients. When finished with post-processing, use hmap.rewrite_gradient_fill(gradients).
-
get_repeat
(self, int x, int y)¶ This allows the algorithm to tile at the edges.
-
gradients
¶ list
Type: gradients
-
height
¶ ‘int’
Type: height
-
jitter
(self)¶
-
noise
(self)¶
-
point_flood
(self, points)¶ Each tuple of (x,y,biome) in the “points” list is round-robined through a flooding algorithm. The algorithm uses one queue for each flood, so that the flooding is as even as possible.
-
random_points
(self, qty, biome, x=0, y=0, w=None, h=None)¶ Generate some points for point_flood()
-
rect_of_point
(self, x, y)¶
-
set_repeat
(self, int x, int y, val)¶ This allows the algorithm to tile at the edges.
-
theight
¶ ‘int’
Type: theight
-
tmap
¶ list
Type: tmap
-
twidth
¶ ‘int’
Type: twidth
-
width
¶ ‘int’
Type: width
-
-
class
pyspades.mapmaker.
Gradient
¶ Bases:
object
-
array
¶
-
hsb
¶ Linear interpolation of (0-360,0-100,0-100) HSB values as used in GIMP.
-
rgb
¶ Linear interpolation of (0-255) RGB values.
-
set_step_hsb
¶
-
set_step_rgb
¶
-
-
class
pyspades.mapmaker.
HeightMap
(height)¶ Bases:
object
-
add_repeat
(self, int x, int y, double val)¶
-
blend_heightmaps
(self, HeightMap alphamap, HeightMap HeightMap)¶ Blend according to two HeightMaps: one as an alpha-mask, the other contains desired heights
-
cmap
¶ object
Type: cmap
-
dipping
(self)¶ Adds a “dipping” feel to the map.
-
fill_col
(self, int col)¶
-
get
(self, int x, int y) → double¶
-
get_col
(self, int x, int y) → int¶
-
get_col_repeat
(self, int x, int y) → int¶
-
get_repeat
(self, int x, int y) → double¶ This allows the algorithm to tile at the edges.
-
height
¶ ‘int’
Type: height
-
hmap
¶ object
Type: hmap
-
jitter_colors
(self, double amount)¶ Image jittering filter. Amount is max pixels distance to jitter.
-
jitter_heights
(self, double amount)¶ Image jittering filter. Amount is max pixels distance to jitter.
-
level_against_heightmap
(self, HeightMap other, double height)¶ Use another HeightMap as an alpha-mask to force values to a specific height
-
line_add
(self, int x, int y, int x2, int y2, int radius, double depth)¶
-
line_set
(self, int x, int y, int x2, int y2, int radius, double height)¶
-
midpoint_displace
(self, double jittervalue, double spanscalingmultiplier, int skip=0)¶ Midpoint displacement with the diamond-square algorithm.
-
mult_repeat
(self, int x, int y, double mult)¶
-
offset_z
(self, double qty)¶
-
paint_gradient_fill
(self, gradient)¶ Surface the map with a single gradient.
-
peaking
(self)¶ Adds a “peaking” feel to the map.
-
rect_color
(self, int x, int y, int w, int h, int col)¶
-
rect_noise
(self, int x, int y, int w, int h, double jitter, double midpoint)¶
-
rect_solid
(self, int x, int y, int w, int h, double z)¶
-
rescale_z
(self, double multiple)¶
-
rewrite_gradient_fill
(self, list gradients)¶ Given a cmap of int-indexed gradient definitions, rewrite them as surface color definitions.
-
rgb_noise_colors
(self, low, high)¶ Add noise to the heightmap colors.
-
rolling
(self)¶ Adds a “rolling” feel to the map.
-
seed
(self, double jitter, double midpoint)¶
-
set
(self, int x, int y, double val)¶
-
set_col_repeat
(self, int x, int y, int val)¶
-
set_repeat
(self, int x, int y, double val)¶ This allows the algorithm to tile at the edges.
-
smooth_colors
(self)¶ Average the color of each pixel to add smoothness.
-
smoothing
(self)¶ Does some simple averaging to bring down the noise level.
-
truncate
(self)¶ Truncates the HeightMap to a valid (0-1) range. Do this before painting or writing to voxels to avoid crashing.
-
width
¶ ‘int’
Type: width
-
write_vxl
(self)¶
-
-
pyspades.mapmaker.
generate_classic
(seed)¶
-
pyspades.mapmaker.
get_b
(int color) → int¶
-
pyspades.mapmaker.
get_g
(int color) → int¶
-
pyspades.mapmaker.
get_r
(int color) → int¶
-
pyspades.mapmaker.
make_color
(int r, int g, int b) → int¶
pyspades.master module¶
Implementation of the 0,75 master server protocol
-
class
pyspades.master.
AddServer
[source]¶ Bases:
pyspades.loaders.Loader
The AddServer packet sent to the master server
-
count
¶
-
game_mode
¶
-
id
= 4¶
-
map
¶
-
max_players
¶
-
name
¶
-
port
¶
-
-
class
pyspades.master.
MasterConnection
(protocol, peer)[source]¶ Bases:
pyspades.protocol.BaseConnection
-
connected
= False¶
-
disconnect_callback
= None¶
-
pyspades.packet module¶
-
pyspades.packet.
call_packet_handler
(self, loader)¶
-
pyspades.packet.
load_client_packet
(data)¶
-
pyspades.packet.
load_server_packet
(data)¶
-
pyspades.packet.
register_packet
(loader=None, server=True, client=True, extension=None)¶ register a packet
>>> @register_packet() ... class SomePacket(Loader): ... pass
Optionally can be used as function too, but this is discouraged unless you need to do this (the default pyspades loaders need this, as they are defined in C++ code):
>>> class AnotherPacket(Loader): ... pass ... >>> register_packet(AnotherPacket, server=False)
Additionally you can specify if only the server or client can send this packet. This is only useful in a few rare cases, so these are set to
True
by default.Parameters: Raises: KeyError
– If the packet’s ID has already been registered
-
pyspades.packet.
register_packet_handler
(loader)¶
pyspades.player module¶
-
class
pyspades.player.
ServerConnection
(*arg, **kw)[source]¶ Bases:
pyspades.protocol.BaseConnection
-
address
= None¶
-
blocks
= None¶
-
client_string
¶
-
color
= (112, 112, 112)¶
-
filter_animation_data
= False¶
-
filter_visibility_data
= False¶
-
filter_weapon_input
= False¶
-
freeze_animation
= False¶
-
grenades
= None¶
-
hp
= None¶
-
is_valid_position
(x: float, y: float, z: float, distance: None = None) → bool¶
-
kills
= 0¶
-
last_block
= None¶
-
last_block_destroy
= None¶
-
last_position_update
= None¶
-
last_refill
= None¶
-
loader_received
(loader: enet.Packet) → None[source]¶ called when a loader i.e. packet is received. calls the packet handler registered with @register_packet_handler
-
local
= False¶
-
map_data
= None¶
-
map_packets_sent
= 0¶
-
name
= None¶
-
on_line_build_start
()[source]¶ called when the player has pressed the mouse button to start line-building
-
player_id
= None¶
-
rapid_hack_detect
= False¶
-
respawn_time
= None¶
-
rubberband_distance
= 10¶
-
saved_loaders
= None¶
-
send_chat_error
(message)[source]¶ Send a error message. This gets displayed as a red popup with sound for OpenSpades/Betterspades clients
-
send_chat_notice
(message)[source]¶ Send a notice. This gets displayed as a popup for OpenSpades/Betterspades clients
-
send_chat_status
(message)[source]¶ Send a status message. This gets displayed in the center of the screen for OpenSpades/Betterspades clients
-
send_chat_warning
(message)[source]¶ Send a warning message. This gets displayed as a yellow popup with sound for OpenSpades/BetterSpades clients
-
set_hp
(value: Union[int, float], hit_by: Optional[ServerConnection] = None, kill_type: int = 0, hit_indicator: Optional[Tuple[float, float, float]] = None, grenade: Optional[pyspades.world.Grenade] = None) → None[source]¶
-
spawn_call
= None¶
-
speedhack_detect
= False¶
-
team
= None¶
-
timers
= None¶
-
tool
= None¶
-
weapon
= None¶
-
weapon_object
= None¶
-
world_object
= None¶
-
pyspades.protocol module¶
-
class
pyspades.protocol.
BaseConnection
(protocol, peer)[source]¶ Bases:
object
-
disconnected
= False¶
-
latency
¶
-
timeout_call
= None¶
-
pyspades.server module¶
-
class
pyspades.server.
ServerProtocol
(*arg, **kw)[source]¶ Bases:
pyspades.protocol.BaseProtocol
-
blue_team
¶ alias to team_1 for backwards-compatibility
-
broadcast_chat_error
(message, team=None)[source]¶ Send a warning message. This gets displayed as a red popup with sound for OpenSpades clients
-
broadcast_chat_notice
(message, team=None)[source]¶ Send a warning message. This gets displayed as a popup for OpenSpades clients
-
broadcast_chat_status
(message, team=None)[source]¶ Send a warning message. This gets displayed as a message in the status area at the top of the screen, where events such as intel pickups are also displayed.
-
broadcast_chat_warning
(message, team=None)[source]¶ Send a warning message. This gets displayed as a yellow popup with sound for OpenSpades clients
-
broadcast_contained
(contained, unsequenced=False, sender=None, team=None, save=False, rule=None)[source]¶ send a Contained
Loader
to all or a selection of connected playersParameters: - contained – the
Loader
object to send - unsequenced – set the enet
UNSEQUENCED
flag on this packet - sender – if set to a connection object, do not send this packet to that player, as they are the sender.
- team – if set to a team, only send the packet to that team
- save – if the player has not downloaded the map yet, save this packet and send it when the map transfer has completed
- rule – if set to a callable, this function is called with the player as parameter to determine if a given player should receive the packet
- contained – the
-
connection_class
¶ alias of
pyspades.player.ServerConnection
-
connections
= None¶
-
fog_color
= (128, 232, 255)¶
-
friendly_fire
= False¶
-
friendly_fire_time
= 2¶
-
game_mode
= 0¶
-
get_name
(name)[source]¶ Sanitizes
name
and modifies it so that it doesn’t collide with other names connected to the server.Returns the fixed name.
-
green_team
¶ alias to team_2 for backwards-compatibility
-
map
= None¶
-
master
= False¶
-
master_connection
= None¶
-
max_players
= 32¶
-
max_score
= 10¶
-
melee_damage
= 100¶
-
name
= 'pyspades server'¶
-
player_ids
= None¶
-
refill_interval
= 20¶
-
reset_game
(player=None, territory=None)[source]¶ reset the score of the game
player is the player which should be awarded the necessary captures to end the game
-
respawn_time
= 5¶
-
respawn_waves
= False¶
-
server_prefix
= '[*] '¶
-
spade_teamkills_on_grief
= False¶
-
spectator_name
= 'Spectator'¶
-
spectator_team
¶ alias to team_spectator for backwards-compatibility
-
speedhack_detect
= True¶
-
team1_color
= (0, 0, 196)¶
-
team1_name
= 'Blue'¶
-
team2_color
= (0, 196, 0)¶
-
team2_name
= 'Green'¶
-
team_class
¶ alias of
pyspades.team.Team
-
version
= 3¶
-
winning_player
= None¶
-
world
= None¶
-
pyspades.team module¶
pyspades.tools module¶
pyspades.types module¶
A few useful types used around the place.
IDPool is used to distribute the IDs given out by the Server
AttributeSet is used for testing if various settings are active
MultikeyDict is used to make player names accessible by both id and name
-
class
pyspades.types.
AttributeSet
[source]¶ Bases:
set
set with attribute access, i.e.
>>> foo = AttributeSet(("eggs", )) >>> foo.eggs True >>> foo.spam False
Also supports adding and removing elements
>>> foo.bar = True >>> 'bar' in foo True >>> foo.bar = False >>> 'bar' in foo False
This works as a quick shorthand for membership testing.
-
class
pyspades.types.
IDPool
(start=0)[source]¶ Bases:
object
Manage pool of IDs
>>> p = IDPool(start=10) >>> p.pop() 10 >>> p.pop() 11 >>> p.pop() 12 >>> p.put_back(11) >>> p.pop() 11
pyspades.vxl module¶
-
class
pyspades.vxl.
Generator
(VXLData data)¶ Bases:
object
-
done
¶ ‘bool’
Type: done
-
get_data
(self, int columns=2)¶
-
-
class
pyspades.vxl.
VXLData
(fp=None)¶ Bases:
object
-
build_point
(self, int x, int y, int z, tuple color) → bool¶
-
check_node
(self, int x, int y, int z, bool destroy=False) → int¶
-
copy
(self)¶
-
count_land
(self, int x1, y1, x2, y2)¶
-
destroy_point
(self, int x, int y, int z)¶
-
generate
(self)¶
-
get_color
(self, int x, int y, int z)¶
-
get_generator
(self)¶
-
get_height
(self, int x, int y) → int¶
-
get_neighbors
(self, int x, int y, int z) → list¶
-
get_overview
(self, int z=-1, bool rgba=False)¶
-
get_point
(self, int x, int y, int z)¶
-
get_random_point
(self, int x1, int y1, int x2, int y2) → tuple¶
-
get_safe_coords
(self, int x, int y, int z) → tuple¶ given (x, y, z) coords, return the closest set of coords on the map that is within the bounds of the map
-
get_solid
(self, int x, int y, int z)¶
-
get_z
(self, int x, int y, int start=0) → int¶ Returns the first z coordinate that is solid beginning from
start
and moving down. Useful for getting the coordinate for where something should be after being dropped.
-
has_neighbors
(self, int x, int y, int z) → bool¶
-
is_surface
(self, int x, int y, int z) → bool¶
-
is_valid_position
(self, int x, int y, int z)¶ return if the value is a valid position within the bounds of the map
-
load_vxl
(self, c_data=None)¶
-
remove_point
(self, int x, int y, int z)¶
-
set_column_fast
(self, int x, int y, int z_start, int z_end, int z_color_end, int color) → bool¶ Set a column’s solidity, but only color a limited amount from the top.
-
set_overview
(self, data_str, int z)¶
-
set_point
(self, int x, int y, int z, tuple color)¶
-
update_shadows
(self)¶
-
-
pyspades.vxl.
make_color
(int r, int g, int b, int a=255) → int¶
pyspades.weapon module¶
-
class
pyspades.weapon.
BaseWeapon
(reload_callback: Callable)[source]¶ Bases:
object
-
ammo
= None¶
-
damage
= None¶
-
delay
= 0.0¶
-
id
= None¶
-
next_shot
= 0¶
-
reload_time
= 0.0¶
-
reloading
= False¶
-
shoot
= False¶
-
shoot_time
= None¶
-
slow_reload
= False¶
-
start
= None¶
-
stock
= None¶
-
-
class
pyspades.weapon.
Rifle
(reload_callback: Callable)[source]¶ Bases:
pyspades.weapon.BaseWeapon
-
ammo
= 10¶
-
damage
= {0: 49, 1: 100, 2: 33, 3: 33}¶
-
delay
= 0.5¶
-
id
= 0¶
-
name
= 'Rifle'¶
-
reload_time
= 2.5¶
-
slow_reload
= False¶
-
stock
= 50¶
-
pyspades.world module¶
-
class
pyspades.world.
Character
¶ Bases:
pyspades.world.Object
Represents the position, orientation and velocity of the player object in the world
-
airborne
¶
-
can_see
(self, float x, float y, float z) → int¶ return if the player can see a given coordinate. This only considers the map voxels, not any other objects
-
cast_ray
(self, length=32.0)¶ cast a ray
length
number of blocks in the direction the player is facing, If a voxel is hit, return it’s coordinates, otherwiseNone
-
crouch
¶
-
dead
¶
-
down
¶
-
fall_callback
¶ object
Type: fall_callback
-
initialize
(self, Vertex3 position, Vertex3 orientation, fall_callback=None)¶
-
jump
¶
-
left
¶
-
orientation
¶ pyspades.common.Vertex3
Type: orientation
-
position
¶ pyspades.common.Vertex3
Type: position
-
primary_fire
¶
-
right
¶
-
secondary_fire
¶
-
set_animation
(self, jump, crouch, sneak, sprint)¶ set all of the player’s movement statuses: jump, crouch, sneak and sprint
-
set_crouch
(self, bool value)¶ set if the player is crouching
-
set_dead
(self, value)¶ set the player’s alive status. Also resets mouse buttons, movement stats and keys
-
set_orientation
(self, x, y, z)¶ set the current orientation of the Player
-
set_position
(self, x, y, z, reset=False)¶ set the current position of the player. If
reset=True
is passed, reset velocity, keys, mouse buttons and movement status as well
-
set_walk
(self, up, down, left, right)¶ set the current status of the movement buttons
-
set_weapon
(self, is_primary)¶ set the primary weapon of the player
-
sneak
¶
-
sprint
¶
-
up
¶
-
validate_hit
(self, Character other, part, float aim_tolerance, float dist_tolerance)¶ check if a given hit is within a given tolerance of hitting another player. This is primarily used to prevent players from shooting at things they aren’t facing at
-
velocity
¶ pyspades.common.Vertex3
Type: velocity
-
wade
¶
-
-
class
pyspades.world.
Grenade
¶ Bases:
pyspades.world.Object
-
callback
¶ object
Type: callback
-
fuse
¶ ‘float’
Type: fuse
-
get_damage
(self, Vertex3 player_position) → double¶ Calculate the damage given to a player standing at
player_position
. Also performs a check to see if the player is behind cover.
-
get_next_collision
(self, double dt)¶ calculate the position of the grenade ahead of time.
Returns: the ETA and the location of the next collision Return type: eta, x, y, z
-
initialize
(self, double fuse, Vertex3 position, Vertex3 orientation, Vertex3 velocity, callback=None)¶
-
position
¶ pyspades.common.Vertex3
Type: position
-
team
¶ object
Type: team
-
velocity
¶ pyspades.common.Vertex3
Type: velocity
-
-
class
pyspades.world.
Object
(world, *arg, **kw)¶ Bases:
object
an object in present in the World
-
delete
(self)¶ remove this object from the World
-
initialize
(self, *arg, **kw)¶ hook called on Object creation
Arguments passed to
__init__
will be passed here too.
-
name
¶ object
Type: name
-
world
¶ pyspades.world.World
Type: world
-
-
class
pyspades.world.
World
¶ Bases:
object
controls the map of the World and the Objects inside of it
-
create_object
(self, klass, *arg, **kw)¶
-
delete_object
(self, Object item)¶
-
map
¶ pyspades.vxl.VXLData
Type: map
-
objects
¶ list
Type: objects
-
time
¶ ‘float’
Type: time
-
update
(self, double dt)¶
-
-
pyspades.world.
cube_line
(x1, y1, z1, x2, y2, z2)¶ create a cube line from one point to another with the same algorithm as the client uses
Contributing, Reporting Bugs and Requesting Features¶
In which ways I can contribute?¶
If you come across any issues, or have feature suggestions you would like to see in piqueserver, please inform us in our Issue Tracker.
Tip
Before reporting your problem or submitting a suggestion, search the Issue Tracker for similar issues.
Reporting bugs¶
When reporting bugs, please be as clear and detailed as possible. This way, we can work faster by saving time that would otherwise be spent asking questions and waiting between responses.
Common relevant information include:
- Operating System (Windows, Mac OS X, GNU/Linux distro)
- piqueserver version
- Expected behaviour and what happened instead
- Your console output containing the error
Submitting code changes in piqueserver¶
You can search inside these docs for information that might be relevant to your desired code changes. If you can’t find any, feel free to reach to us in chat ;).
Be sure to also check our Developer guidelines
Network ports¶
Piqueserver needs a few firewall ports open for various things.
The game server¶
The port the actual gameplay is on - this needs to be allowed at the bare minimum for players to connect to the game.
- Default: 32887
- Config variable:
port
- Protocol: udp
Status server¶
This is for the webpage which displays info about the server.
- Default: 32886
- Config variable:
status_server.port
- Protocol: tcp
Banpublish¶
For making the banlist public.
- Default: 32885
- Config variable:
banpublish.port
- Protocol: tcp
SSH¶
Some ssh server for remotely connecting to the server.
- Default: 32887
- Config variable:
ssh.port
- Protocol: tcp
List of somewhat relevant pyspades forks¶
What was happening with pyspades after development halted? Forks. This is the page to consolidate them
- https://github.com/NateShoffner/PySnip/commits/master?after=Y3Vyc29yOtCU%2B4Ixgp7EB1rhkBOVh9rZiwNxKzY5 - the last commit from pyspades, the first commit from pysnip
- https://github.com/infogulch/pyspades-events - event system proposal for pyspades. not compatible with anything, is outdated too. Mirror here: https://github.com/Ericson2314/pysnip/tree/evented (see infogulch:evented for the upstream of that mirror)
- https://github.com/Lensman/pysnip - a google code mirror, with basicbot.py added (proof https://github.com/infogulch/pyspades/compare/BnS…iamgreaser:lensman?diff=split&name=lensman&w=1
- https://github.com/cmr/pyspades - a mirror without any new commits
- https://bitbucket.org/mari_kiri/pyckaxe/ - not pyspades, but someone’s else implementation of AoS protocol
- https://github.com/10se1ucgo/PySnip1.0 - aos 1.0 implementation on top of pysnip
- https://github.com/infogulch/pyspades - the main source of extra contribution
- https://github.com/Ericson2314/pysnip - some extra interesting additions here and there, mostly cosmetic?
- https://github.com/iamgreaser/pysnip/compare/BnS…iamgreaser:minit - changes of the minit.nu server. A lot of changes with cryptic history.
- https://github.com/infogulch/pyspades/pull/290 - essentially discontinued powerthirst
- https://github.com/infogulch/pyspades/compare/BnS…iamgreaser:BnS?w=1 - the boiled down powerthirst shebang
Note
iamgreaser’s BnS branch includes some extra powerthirst changes. The ‘prestine’ (kinda) BnS branch is only infogulch’s one
things worth checking: bots from infogulch
Technical details¶
- (TODO) Technical details: aimbot detection
- Technical details: AoS 0.75 protocol
External tools¶
- aos-to-address by noway421 - Convert AoS URIs to their respective IP addresses
Note
The PySpades wiki has some legacy information that might be helpful.