Skip to content

Commit

Permalink
Update README.md and setup.py for v0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
biqqles committed Sep 13, 2020
1 parent d9c724a commit a85aa01
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 47 deletions.
106 changes: 60 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
flair achieves this through a combination of hooking user input, reading process memory and window interaction using the Win32 API, and an understanding of Freelancer's static data provided by [flint](https://github.com/biqqles/flint). Through these means flair allows the game's state to be inspected in real-time. It also allows the game client to be augmented, for example adding clipboard access to the game's chat box or implementing a custom command line interface.

### Installation
flair is on PyPI:
flair is on [PyPI](https://pypi.org/project/fl-flair/):

```
python -m pip install fl-flair
pip install fl-flair
```

Alternatively you can install straight from this repository:

```sh
python -m pip install https://github.com/biqqles/flair/archive/master.zip
pip install https://github.com/biqqles/flair/archive/master.zip -U
```

Built wheels are also available under [Releases](https://github.com/biqqles/flair/releases), as is a changelog. flair requires Python 3.6 or higher.
Expand All @@ -23,20 +23,23 @@ flair must be run with administrator privileges. This is required for it to be a

flair includes a testing mode. To access it run `python -m flair <path_to_freelancer>`. In this mode flair will load all built-in augmentations, print all events, and begin polling and printing the state of the game to the terminal. More on all of those later.

To use flair in your own programs, simply create an instance of `flair.FreelancerState`. This will begin polling the game (by default every 1 second). The polling frequency only affects when events are emitted - in most cases accesses to FreelancerState will cause the immediate state of the game to be read.

### State and events
Basic usage of flair relies on two main principles:

- a state object, which allows access to the game's state in real time
- a simple events system inspired by Qt's signals and slots mechanism
- a [state object](#freelancerstate), which allows access to the game's state in real time (`flair.state`)
- a simple [events system](#events) inspired by Qt's signals and slots mechanism (`flair.events`)

To use flair in your own programs, first call `flair.set_install_dir` to bind flair to the Freelancer installation it is to hook. This creates a `FreelancerState` instance at `flair.state`. This will automatically begin polling the game (by default every 1 second). The polling frequency only affects when events are emitted - accesses to `FreelancerState` will cause the immediate state of the game to be read (in most cases).

The API for the hook itself is also of course available for cases not covered by the builtin `FreelancerState`, like creating [augmentations](#augmentations).
If you want to do more than read the state of the game and receive events, you should use the hook directly. An example of this situation is creating augmentations [augmentations](#augmentations).

All these concepts are discussed in detail below.

## API
### FreelancerState
As mentioned earlier, simply create an instance of `flair.FreelancerState` to get access to the game state. Its constructor takes one argument, the path to the game's folder. This object has the following methods and properties:
### `FreelancerState`
> Source: [flair/inspect/state.py](flair/inspect/state.py)
As mentioned earlier, `flair.FreelancerState` allows various parameters of the game's state to be accessed. Instances of this class have the following methods and properties:

|Methods |Type |Notes |
|:-------------------|:----------------|:----------------------------------------------------------------------------------------|
Expand All @@ -57,34 +60,38 @@ As mentioned earlier, simply create an instance of `flair.FreelancerState` to ge
|**`pos`** |`Optional[PosVector]`|The position vector of the active character if there is one, otherwise None |
|**`docked`** |`Optional[bool]` |Whether the active character is presently docked at a base if there is one, otherwise None|

Source: [flair/inspect/state.py](flair/inspect/state.py)
A `FreelancerState` instance at `flair.state` will be created when you call `flair.set_install_dir`. You should not normally need to initialise `FreelancerState` yourself. If for some reason you wanted to hook two instances of Freelancer running simultaneously, you should use two different Python processes.


### Events
> Source: [flair/inspect/events.py](flair/inspect/events.py)
Events are used by "connecting" them to functions (or vice-versa). flair automatically "emits" these events when necessary. For example `flair.events.message_sent.connect(lambda message: print(message))` causes that lambda to be called every time flair emits the `message_sent` signal, thereby printing the contents of the message to the terminal.

The connected function should take a keyword argument with the name specified in the schema column.

|Event |Emitted when | Parameter(s) |
|Event |Emitted when | Parameter schema |
|:---------------------------|:----------------------------------|:--------------------------------------------------------------|
|**`character_changed`** |New character loaded |`name`=new character name |
|**`account_changed`** |Active (registry) account changed |`account`=new account code |
|**`system_changed`** |New system entered |`system`=New system display name |
|**`docked`** |Docked base (respawn point) changed|`base`=new base display name |
|**`character_changed`** |New character loaded |`name`: new character name |
|**`account_changed`** |Active (registry) account changed |`account`: new account code |
|**`system_changed`** |New system entered |`system`: New system display name |
|**`docked`** |Docked base (respawn point) changed|`base`: new base display name |
|**`undocked`** |Undocked from base |N/A |
|**`credits_changed`** |Credit balance changed |`balance`=new credit balance |
|**`message_sent`** |New message sent by player |`message`=message text |
|**`chat_box_opened`** |Chat box opened |`message`=message text |
|**`chat_box_closed`** |Chat box closed |`message_sent`=whether message sent |
|**`credits_changed`** |Credit balance changed |`balance`: new credit balance |
|**`message_sent`** |New message sent by player |`message`: message text |
|**`chat_box_opened`** |Chat box opened |`message`: message text |
|**`chat_box_closed`** |Chat box closed |`message_sent`: whether message sent |
|**`freelancer_started`** |Freelancer process launched |N/A |
|**`freelancer_stopped`** |Freelancer process closed |N/A |
|**`switched_to_foreground`**|Freelancer switched to foreground |N/A |
|**`switched_to_background`**|Freelancer switched to background |N/A |

Source: [flair/inspect/events.py](flair/inspect/events.py)

### Hook
[`flair/hook`](flair/hook) contains the lower-level code for hooking into the game. You will likely only need to use this directly if you wish to go beyond simply using `FreelancerState` and the events system. It is separated into the following modules:
[`flair/hook`](flair/hook) contains the hook itself. It is separated into the following modules:

#### Input
Source: [flair/hook/input](flair/hook/input)
> Source: [flair/hook/input](flair/hook/input)
##### `bind_hotkey(combination, function)`
Adds a hotkey which is only active when Freelancer is in the foreground.
Expand Down Expand Up @@ -121,16 +128,19 @@ Handle the user closing the chat box. Emits the `chat_box_closed` signal.

##### `collect_chat_box_events(event)`
Handle a keyboard event while the chat box is open.
# Todo: handle arrow keys, copy and paste
Todo: handle arrow keys, copy and paste

##### `get_chat_box_contents()`
Return (our best guess at) the current contents of the chat box. If it is closed, returns a blank string.

##### `get_chat_box_open_hotkey()`
Return the hotkey configured to open the chat box.


#### Process
Source: [flair/hook/process](flair/hook/process)##### `get_process() -> <built-in function HANDLE>`
> Source: [flair/hook/process](flair/hook/process)
##### `get_process() -> <built-in function HANDLE>`
Return a handle to Freelancer's process.

##### `read_memory(process, address, datatype, buffer_size=128)`
Expand Down Expand Up @@ -177,8 +187,11 @@ Read whether a character is loaded (whether in SP or MP).
##### `get_docked(process) -> bool`
Read whether the active character is docked.


#### Window
Source: [flair/hook/window](flair/hook/window)##### `get_hwnd() -> int`
> Source: [flair/hook/window](flair/hook/window)
##### `get_hwnd() -> int`
Returns a non-zero window handle to Freelancer if a window exists, otherwise, returns zero.

##### `is_present() -> bool`
Expand All @@ -191,11 +204,16 @@ Reports whether Freelancer is in the foreground and accepting input.
Return the screen coordinates for the contents ("client"; excludes window decorations) of a Freelancer window.

##### `make_borderless()`
Remove the borders and titlebar from the game running in windowed mode.
Todo: Windowed mode seems to cut off the bottom of the game. This is something that will need worked around.
Remove the borders and titlebar from the game while running in windowed mode.

##### `make_foreground()`
Bring Freelancer's window into the foreground and make it the active window.


#### Storage
Source: [flair/hook/storage](flair/hook/storage)##### `get_active_account_name() -> str`
> Source: [flair/hook/storage](flair/hook/storage)
##### `get_active_account_name() -> str`
Returns the currently active account's code ("name") from the registry.
Note that Freelancer reads the account from the registry at the time of server connect.

Expand All @@ -206,36 +224,32 @@ Get the name of a key from its VK (virtual key) code.
Get Freelancer's current key map as defined in UserKeyMap.ini, in a format understood by the `keyboard`
module.

##### `tail_chat_log()`
(Discovery only)
Get the last message recorded in DSAce.log

##### `get_launcher_accounts() -> Dict[str, Tuple[str, str]]`
(Discovery only)
Parse launcheraccounts.xml to a dictionary of tuples of the form {code: (name, description)}.

### Augmentations
"Augmentations" are modules that augment the game client. flair includes several such built-in example modules.
> Source: [flair/augment](flair/augment)
To create an augmentation, subclass `flair.augment.Augmentation`. Simply override the methods `load()` and `unload()`. These are run when augmentations are "loaded" into the game client and "unloaded" respectively. Connect up the events you need to use and add any other setup here.
"Augmentations" are modules that augment the game client. flair includes several such examples built-in.

Source: [flair/augment](flair/augment)
To create an augmentation, subclass `flair.augment.Augmentation`. Simply override the methods `load()` and `unload()`. These are run when augmentations are "loaded" into the game client and "unloaded" respectively. Connect up the events you need to use and add any other setup in these methods.

#### Clipboard
Adds clipboard access to the chat box. Use Ctrl+Shift+C to copy the contents of the chat box and Ctrl+Shift+V to paste text to it.

#### CLI
Adds a basic command-line interface to the game.
If you are on a vanilla server you will need to type commands into the console (press ↑ in the chat box). This is not necessary on a server running FLHook as it will recognise them as commands and not send them to other players. Output is returned in chat, again through the console.

- `date`: print the local date and time
- `sector`: print the current sector and system
- `eval`: evaluate the given expression with Python
- `quit`: quit the game
- `help`: show this help message
The following commands are implemented:

- `..date`: print the local date and time
- `..sector`: print the current sector and system
- `..eval`: evaluate the given expression with Python
- `..quit`: quit the game
- `..help`: show this help message

:warning: This augmentation is of limited use on servers without FLHook. If you are on a vanilla server you will need to type commands into the console (press ↑ in the chat box), otherwise they will be sent to other players. Additionally, running commands while a channel other than local (e.g. a group or PM) is selected as the default will result in messages being sent to a random player. FLHook's presence allows both of these issues to be mitigated.

#### Screenshot
Adds proper screenshot functionality to the game, similar to that found in games like *World of Warcraft*. Screenshots are automatically named with a timestamp and the system name and saved to `My Games/Freelancer/Screenshots` with the character name as the directory. Screenshots are taken using Ctrl+PrintScreen.
Adds proper screenshot functionality to the game, similar to that found in games like *World of Warcraft*. Screenshots are automatically named with a timestamp and the system name and saved to `My Games/Freelancer/Screenshots` with the character name as the directory. Screenshots are taken using `Ctrl+PrintScreen`.

### To do
- Reimplementing Wizou's multiplayer code
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

setup(
name='fl-flair',
version='0.2',
version='0.3',
author='biqqles',
author_email='[email protected]',
description='A novel client-side hook for Freelancer',
Expand Down

0 comments on commit a85aa01

Please sign in to comment.