Skip to content

JKornev/q3net

Repository files navigation

q3net

Python library, emulator of Quake 3 connection

Live demo: @qv3k_bot - q3 client with telegram bot interface

Requirements

Features

  • Stable quake3 connection (vanilla, osp, e+, a bit of cpma)
  • Connected and connection-less communication with a server
  • Protocols 68 and 71
  • Supports sv_pure 1
  • Supports proxy connection (qwfwd)
  • Player customization
  • Other stuff

Installation

Q3net library is available in the PyPi repository

python -m pip install q3net

Then just include it into your project

import q3net

You can also copy q3net manually to your project or add it as a git submodule

cd <your project>
git submodule add https://github.com/JKornev/q3net.git q3net
git add .
git commit -m "q3net included to a project"
python -m pip install q3huff2

How to

Query information from the server without opening a full game connection

import q3net
# query server info and status
connection = q3net.connection("localhost", 27960)
print(connection.request(q3net.get_info_request()).data)
print(connection.request(q3net.get_status_request()).data)
connection.terminate()

Open a connection with the server

import q3net
# open a connection with a server
connection = q3net.connection("localhost", 27960)
connection.connect()
# welcome other players
connection.request(q3net.say_request("hi!"))
connection.disconnect()
# gracefully destroy connection object
connection.terminate()

Keep in mind when you create a q3net.connection object it internally creates a separated worker thread. Therefore to avoid app freezes and thread leaks you need to terminate each q3net.connection object by calling method q3net.connection.terminate() in the end.

Another example shows handling connection events

import q3net, time

class handler(q3net.events_handler):
    def event_connected(self, gamestate, host, port, server_id):
        print(f"Connected to {host}:{port} id:{srv_id}")

    def event_disconnected(self, gamestate, reason):
        print(f"Disconnected, reason : {reason}")

    def event_packet(self, gamestate, packet):
        pass # frequent event, no need spam

    def event_command(self, gamestate, sequence, command):
        print(f"Command {sequence} : {command}")

    def event_configstring(self, gamestate, index, value):
        print(f"ConfigString {index} : {value}")

connection = q3net.connection("localhost", 27960, handler=handler())
connection.connect()
time.sleep(5.0) # give it work a bit
connection.disconnect()
connection.terminate()

q3net.events_handler class handles connection events from different thread (connection worker) therefore you have to worry about syncronization if you want to communicate with a main thread that opened a connection.

Other more detailed examples in \examples folder: