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 data
Return 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:
  • unsigned (bool) – If true, interpret the bytes as unsigned
  • big_endian (bool, optional) – If true, interpret the bytes as big endian
Returns:

The value of the bytes as int

Return type:

int

readReader(self, int size=-1) → ByteReader
readShort(self, bool unsigned=False, bool big_endian=True) → int

read two bytes of data as integer

Parameters:
  • unsigned (bool) – If true, interpret the bytes as unsigned
  • big_endian (bool, optional) – If true, interpret the bytes as big endian
Returns:

The value of the bytes as int

Return type:

int

readString(self, int size=-1) → bytes

read a string

Parameters:size (int) – If set, read size bytes, else read all bytes available
Returns:The value of the bytes
Return type:bytes
rewind(self, int value)

move the position bytecount bytes back

Parameters:bytecount – number of bytes to move back
seek(self, size_t pos)

move to a position in the buffer

Parameters:pos (int) – position to seek to
skipBytes(self, int bytecount)

move the position bytecount bytes ahead

Parameters:bytecount – number of bytes to move ahead
tell(self) → size_t

get the current position in the buffer

Returns:The current position in bytes
Return type:int
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)
exception pyspades.bytes.NoDataLeft

Bases: Exception

pyspades.collision module

pyspades.collision.collision_3d(x1, y1, z1, x2, y2, z2, distance=3)[source]
pyspades.collision.distance_3d(xyz1, xyz2)[source]
pyspades.collision.distance_3d_vector(vector1, vector2)[source]
pyspades.collision.vector_collision(vec1, vec2, distance=3)[source]

pyspades.color module

pyspades.color.hsb_to_rgb(hue: float, sat: float, bri: float) → Tuple[float, float, float][source]
pyspades.color.interpolate_hsb(xyz1: Tuple[float, float, float], xyz2: Tuple[float, float, float], t: float) → Tuple[float, float, float][source]
pyspades.color.interpolate_rgb(xyz1, xyz2, t)[source]
pyspades.color.rgb_distance(xyz1, xyz2)[source]
pyspades.color.wrap(minimum: float, maximum: float, value: float) → float[source]

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)
class pyspades.contained.WeaponReload

Bases: pyspades.loaders.Loader

clip_ammo

‘int’

Type:clip_ammo
id = 28
player_id

‘int’

Type:player_id
read(self, ByteReader reader)
reserve_ammo

‘int’

Type:reserve_ammo
write(self, ByteWriter writer)
class pyspades.contained.WorldUpdate

Bases: pyspades.loaders.Loader

id = 2
items

list

Type:items
read(self, ByteReader reader)
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
update()[source]
class pyspades.entities.Flag(entity_id, protocol, *arg, **kw)[source]

Bases: pyspades.entities.Entity

player = None
update()[source]
class pyspades.entities.Territory(*arg, **kw)[source]

Bases: pyspades.entities.Flag

add_player(player)[source]
capturing_team = None
finish()[source]
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.

get_spawn_location()[source]
players = None
progress = 0.0
rate = 0
rate_value = 0.0
remove_player(player)[source]
send_progress()[source]
start = None
update_rate()[source]

pyspades.loaders module

class pyspades.loaders.Loader(ByteReader reader=None)

Bases: object

generate(self) → ByteWriter
read(self, ByteReader reader)
write(self, ByteWriter writer)

pyspades.mapgenerator module

The map generator is responsible for generating the map bytes that get sent to the client on connect

class pyspades.mapgenerator.MapGeneratorChild(generator)[source]

Bases: object

data_left()[source]

return True if any data is left

get_size()[source]

get the size of the parent map generator

pos = 0
read(size)[source]

read size bytes from the parent map generator, if possible

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 with get_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''
data_left()[source]

return True if any data is left

done = False
get_child()[source]

return a new child generator

get_size()[source]

get the map size, for display of the loading bar on the client

pos = 0
read(size)[source]

read size bytes from the map generator

pyspades.mapmaker module

class pyspades.mapmaker.Biome

Bases: object

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
read(self, ByteReader reader)[source]
write(self, ByteWriter writer)[source]
class pyspades.master.MasterConnection(protocol, peer)[source]

Bases: pyspades.protocol.BaseConnection

connected = False
disconnect_callback = None
on_connect()[source]
on_disconnect()[source]
send_server()[source]
set_count(value)[source]
pyspades.master.get_master_connection(protocol)[source]

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:
  • server (bool, optional) – This packet can be sent by the server. True by default.
  • client (bool, optional) – This packet can be sent by the client. True by default
  • extension (int, optional) – The extension id this packet belongs to, if any
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

add_score(score)[source]
address = None
blocks = None
capture_flag()[source]
check_refill()[source]
check_speedhack(x: float, y: float, z: float, distance: None = None) → bool[source]
client_string
color = (112, 112, 112)
continue_map_transfer() → None[source]
drop_flag() → None[source]
filter_animation_data = False
filter_visibility_data = False
filter_weapon_input = False
freeze_animation = False
get_location()[source]
get_respawn_time() → float[source]
get_spawn_location() → Tuple[int, int, int][source]
grenade_exploded(grenade: pyspades.world.Grenade) → None[source]
grenades = None
hit(value, by=None, kill_type=0)[source]
hp = None
is_location_free(x, y, z)[source]
is_valid_position(x: float, y: float, z: float, distance: None = None) → bool
kill(by: None = None, kill_type: int = 0, grenade: None = None) → None[source]
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_animation_update(jump, crouch, sneak, sprint)[source]
on_block_action_recieved(contained: pyspades.contained.BlockAction) → None[source]
on_block_build(x, y, z)[source]
on_block_build_attempt(x, y, z)[source]
on_block_destroy(x, y, z, mode)[source]
on_block_line_recieved(contained)[source]
on_block_removed(x, y, z)[source]
on_chat(value, global_message)[source]
on_chat_message_recieved(contained: pyspades.contained.ChatMessage) → None[source]
on_chat_sent(value: str, global_message: bool) → None[source]
on_color_change_recieved(contained: pyspades.contained.SetColor) → None[source]
on_color_set(color: Tuple[int, int, int]) → None[source]
on_color_set_attempt(color: Tuple[int, int, int]) → None[source]
on_command(command, parameters)[source]
on_connect() → None[source]
on_disconnect() → None[source]
on_ext_info_received(contained: pyspades.contained.ProtocolExtensionInfo) → None[source]
on_fall(damage)[source]
on_flag_capture()[source]
on_flag_drop()[source]
on_flag_take()[source]
on_fog_color_recieved(contained)[source]
on_grenade(time_left)[source]
on_grenade_recieved(contained: pyspades.contained.GrenadePacket) → None[source]
on_grenade_thrown(grenade: pyspades.world.Grenade) → None[source]
on_hack_attempt(reason)[source]
on_handshake_recieved(contained: pyspades.contained.HandShakeReturn) → None[source]
on_hit(hit_amount, hit_player, kill_type, grenade)[source]
on_hit_recieved(contained)[source]
on_input_data_recieved(contained: pyspades.contained.InputData) → None[source]
on_join()[source]
on_kill(killer, kill_type, grenade)[source]
on_line_build(points)[source]
on_line_build_attempt(points)[source]
on_line_build_start()[source]

called when the player has pressed the mouse button to start line-building

on_login(name)[source]
on_new_player_recieved(contained: pyspades.contained.ExistingPlayer) → None[source]
on_orientation_update(x: float, y: float, z: float) → None[source]
on_orientation_update_recieved(contained: pyspades.contained.OrientationData) → None[source]
on_position_update() → None[source]
on_position_update_recieved(contained: pyspades.contained.PositionData) → None[source]
on_refill()[source]
on_reload_recieved(contained) → None[source]
on_reset()[source]
on_secondary_fire_set(secondary)[source]
on_shoot_set(fire: int) → None[source]
on_spawn(pos: Tuple[float, float, float]) → None[source]
on_spawn_location(pos: Tuple[float, float, float]) → None[source]
on_team_change_recieved(contained)[source]
on_team_changed(old_team: pyspades.team.Team) → None[source]
on_team_join(team)[source]
on_tool_change_recieved(contained: pyspades.contained.SetTool) → None[source]
on_tool_changed(tool: int) → None[source]
on_tool_set_attempt(tool: int) → None[source]
on_unvalidated_hit(hit_amount, hit_player, kill_type, grenade)[source]
on_version_info_recieved(contained: pyspades.contained.VersionResponse) → None[source]
on_walk_update(up: bool, down: bool, left: bool, right: bool) → None[source]
on_weapon_change_recieved(contained)[source]
on_weapon_input_recieved(contained: pyspades.contained.WeaponInput) → None[source]
on_weapon_set(value)[source]
player_id = None
rapid_hack_detect = False
refill(local: bool = False) → None[source]
reset() → None[source]
respawn() → None[source]
respawn_time = None
rubberband_distance = 10
saved_loaders = None
send_chat(value: str, global_message: bool = False, custom_type: int = 0) → None[source]
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

send_data(data)[source]
send_map(data: Optional[pyspades.mapgenerator.ProgressiveMapGenerator] = None) → None[source]
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]
set_location(location=None)[source]
set_location_safe(location, center=True)[source]
set_team(team)[source]
set_weapon(weapon: int, local: bool = False, no_kill: bool = False) → None[source]
spawn(pos: None = None) → None[source]
spawn_call = None
speedhack_detect = False
take_flag()[source]
team = None
timers = None
tool = None
weapon = None
weapon_object = None
world_object = None
pyspades.player.check_nan(*values) → bool[source]
pyspades.player.parse_command(value: str) → Tuple[str, Sequence[str]][source]

pyspades.protocol module

class pyspades.protocol.BaseConnection(protocol, peer)[source]

Bases: object

disconnect(data=0)[source]
disconnected = False
latency
loader_received(loader)[source]
on_connect()[source]
on_disconnect()[source]
send_contained(contained, sequence=False)[source]
timed_out()[source]
timeout_call = None
class pyspades.protocol.BaseProtocol(port=None, interface=b'*', update_interval=0.016666666666666666)[source]

Bases: object

check_client()[source]
connect(connection_class, host, port, version, channel_count=1, timeout=5.0)[source]
connection_class

alias of BaseConnection

data_received(peer, packet)[source]
is_client = False
max_connections = 33
on_connect(peer)[source]
on_disconnect(peer)[source]
remove_peer(peer)[source]
update()[source]

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(message, global_message=None, sender=None, team=None)[source]
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 players

Parameters:
  • 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
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_cp_entities()[source]
get_fog_color()[source]
get_mode_mode()[source]
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.

get_player_count()[source]
get_random_location(force_land=True, zone=(0, 0, 512, 512))[source]
got_master_connection(connection)[source]
green_team

alias to team_2 for backwards-compatibility

map = None
master = False
master_connection = None
master_disconnected(client=None)[source]
max_players = 32
max_score = 10
melee_damage = 100
name = 'pyspades server'
on_base_spawn(x, y, z, base, entity_id)[source]
on_cp_capture(cp)[source]
on_flag_spawn(x, y, z, flag, entity_id)[source]
on_game_end()[source]
on_map_change(map_)[source]
on_update_entity(entity)[source]
on_world_update()[source]
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

reset_tc()[source]
respawn_time = 5
respawn_waves = False
send_chat(*args, **kwargs)[source]

Deprecated: see broadcast_chat

send_contained(*args, **kwargs)[source]

Deprecated: see broadcast_contained

server_prefix = '[*] '
set_fog_color(color)[source]
set_map(map_obj)[source]
set_master()[source]
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

update()[source]
update_entities()[source]
update_master()[source]
update_network()[source]
version = 3
winning_player = None
world = None

pyspades.team module

class pyspades.team.Team(team_id: int, name: str, color: Tuple[int, int, int], spectator: bool, protocol: pyspades.protocol.BaseProtocol)[source]

Bases: object

base = None
count() → int[source]
flag = None
get_entities()[source]
get_entity_location(entity_id: int) → Tuple[int, int, int][source]
get_players() → None[source]
get_random_location(force_land: bool = False) → Tuple[int, int, int][source]
initialize() → None[source]
kills = None
name = None
other = None
protocol = None
score = None
set_base() → pyspades.entities.Base[source]
set_flag() → pyspades.entities.Flag[source]

pyspades.tools module

pyspades.tools.get_server_details(value)[source]
pyspades.tools.make_server_identifier(ip: ipaddress.IPv4Address, port: int = 32887) → str[source]

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
pop()[source]
put_back(id)[source]
class pyspades.types.RateLimiter(event_count: int, seconds: float)[source]

Bases: object

sliding window rate limiter

Triggers if more than a certain number of events happen in a certain amount of time

above_limit() → bool[source]
get_events() → list[source]
record_event(timestamp: float) → None[source]

record an event at the given timestamp

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
get_ammo(no_max: bool = False) → int[source]
get_damage(value, position1, position2) → int[source]
id = None
is_empty(tolerance=10) → bool[source]
next_shot = 0
on_reload() → None[source]
reload() → None[source]
reload_time = 0.0
reloading = False
reset() → None[source]
restock() → None[source]
set_shoot(value: bool) → None[source]
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
class pyspades.weapon.SMG(reload_callback: Callable)[source]

Bases: pyspades.weapon.BaseWeapon

ammo = 30
damage = {0: 29, 1: 75, 2: 18, 3: 18}
delay = 0.11
id = 1
name = 'SMG'
reload_time = 2.5
slow_reload = False
stock = 120
class pyspades.weapon.Shotgun(reload_callback: Callable)[source]

Bases: pyspades.weapon.BaseWeapon

ammo = 6
damage = {0: 27, 1: 37, 2: 16, 3: 16}
delay = 1.0
id = 2
name = 'Shotgun'
reload_time = 0.5
slow_reload = True
stock = 48

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, otherwise None

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