11. API - Events¶
The events module defines the Events
class, which provides methods for
querying events in the Minecraft world, and the BlockHitEvent
,
PlayerPosEvent
, ChatPostEvent
, and IdleEvent
classes
which represent the various event types.
Note
All items in this module are available from the picraft
namespace
without having to import picraft.events
directly.
The following items are defined in the module:
11.1. Events¶
-
class
picraft.events.
Events
(connection, poll_gap=0.1, include_idle=False)[source]¶ This class implements the
events
attribute.There are two ways of responding to picraft’s events: the first is to
poll()
for them manually, and process each event in the resulting list:>>> for event in world.events.poll(): ... print(repr(event)) ... <BlockHitEvent pos=1,1,1 face="y+" player=1>, <PlayerPosEvent old_pos=0.2,1.0,0.7 new_pos=0.3,1.0,0.7 player=1>
The second is to “tag” functions as event handlers with the decorators provided and then call the
main_loop()
function which will handle polling the server for you, and call all the relevant functions as needed:@world.events.on_block_hit(pos=Vector(1,1,1)) def hit_block(event): print('You hit the block at %s' % event.pos) world.events.main_loop()
By default, only block hit events will be tracked. This is because it is the only type of event that the Minecraft server provides information about itself, and thus the only type of event that can be processed relatively efficiently. If you wish to track player positions, assign a set of player ids to the
track_players
attribute. If you wish to include idle events (which fire when nothing else is produced in response topoll()
) then setinclude_idle
toTrue
.Note
If you are using a Raspberry Juice server, chat post events are also tracked by default. Chat post events are only supported with Raspberry Juice servers; Minecraft Pi edition doesn’t support chat post events.
Finally, the
poll_gap
attribute specifies how long to pause during each iteration ofmain_loop()
to permit event handlers some time to interact with the server. Setting this to 0 will provide the fastest response to events, but will result in event handlers having to fight with event polling for access to the server.-
clear
()[source]¶ Forget all pending events that have not yet been retrieved with
poll()
.This method is used to clear the list of events that have occurred since the last call to
poll()
without retrieving them. This is useful for ensuring that events subsequently retrieved definitely occurred after the call toclear()
.
-
has_handlers
(cls)[source]¶ Decorator for registering a class as containing picraft event handlers.
If you are writing a class which contains methods that you wish to use as event handlers for picraft events, you must decorate the class with
@has_handlers
. This will ensure that picraft tracks instances of the class and dispatches events to each instance that exists when the event occurs.For example:
from picraft import World, Block, Vector, X, Y, Z world = World() @world.events.has_handlers class HitMe(object): def __init__(self, pos): self.pos = pos self.been_hit = False world.blocks[self.pos] = Block('diamond_block') @world.events.on_block_hit() def was_i_hit(self, event): if event.pos == self.pos: self.been_hit = True print('Block at %s was hit' % str(self.pos)) p = world.player.tile_pos block1 = HitMe(p + 2*X) block2 = HitMe(p + 2*Z) world.events.main_loop()
Class-based handlers are an advanced feature and have some notable limitations. For instance, in the example above the
on_block_hit
handler couldn’t be declared with the block’s position because this was only known at instance creation time, not at class creation time (which was when the handler was registered).Furthermore, class-based handlers must be regular instance methods (those which accept the instance, self, as the first argument); they cannot be class methods or static methods.
Note
The
@has_handlers
decorator takes no arguments and shouldn’t be called, unlike event handler decorators.
-
main_loop
()[source]¶ Starts the event polling loop when using the decorator style of event handling (see
on_block_hit()
).This method will not return, so be sure that you have specified all your event handlers before calling it. The event loop can only be broken by an unhandled exception, or by closing the world’s connection (in the latter case the resulting
ConnectionClosed
exception will be suppressed as it is assumed that you want to end the script cleanly).
-
on_block_hit
(thread=False, multi=True, pos=None, face=None)[source]¶ Decorator for registering a function/method as a block hit handler.
This decorator is used to mark a function as an event handler which will be called for any events indicating a block has been hit while
main_loop()
is executing. The function will be called with the correspondingBlockHitEvent
as the only argument.The pos parameter can be used to specify a vector or sequence of vectors (including a
vector_range
); in this case the event handler will only be called for block hits on matching vectors.The face parameter can be used to specify a face or sequence of faces for which the handler will be called.
For example, to specify that one handler should be called for hits on the top of any blocks, and another should be called only for hits on any face of block at the origin one could use the following code:
from picraft import World, Vector world = World() @world.events.on_block_hit(pos=Vector(0, 0, 0)) def origin_hit(event): world.say('You hit the block at the origin') @world.events.on_block_hit(face="y+") def top_hit(event): world.say('You hit the top of a block at %d,%d,%d' % event.pos) world.events.main_loop()
The thread parameter (which defaults to
False
) can be used to specify that the handler should be executed in its own background thread, in parallel with other handlers.Finally, the multi parameter (which only applies when thread is
True
) specifies whether multi-threaded handlers should be allowed to execute in parallel. WhenTrue
(the default), threaded handlers execute as many times as activated in parallel. WhenFalse
, a single instance of a threaded handler is allowed to execute at any given time; simultaneous activations are ignored (but not queued, as with unthreaded handlers).
-
on_chat_post
(thread=False, multi=True, message=None)[source]¶ Decorator for registering a function/method as a chat event handler.
This decorator is used to mark a function as an event handler which will be called for events indicating a chat message was posted to the world while
main_loop()
is executing. The function will be called with the correspondingChatPostEvent
as the only argument.Note
Only the Raspberry Juice server generates chat events; Minecraft Pi Edition does not support this event type.
The message parameter can be used to specify a string or regular expression; in this case the event handler will only be called for chat messages which match this value. For example:
import re from picraft import World, Vector world = World() @world.events.on_chat_post(message="hello world") def echo(event): world.say("Hello player %d!" % event.player.player_id) @world.events.on_chat_post(message=re.compile(r"teleport_me \d+,\d+,\d+")) def teleport(event): x, y, z = event.message[len("teleport_me "):].split(",") event.player.pos = Vector(int(x), int(y), int(z)) world.events.main_loop()
The thread parameter (which defaults to
False
) can be used to specify that the handler should be executed in its own background thread, in parallel with other handlers.Finally, the multi parameter (which only applies when thread is
True
) specifies whether multi-threaded handlers should be allowed to execute in parallel. WhenTrue
(the default), threaded handlers execute as many times as activated in parallel. WhenFalse
, a single instance of a threaded handler is allowed to execute at any given time; simultaneous activations are ignored (but not queued, as with unthreaded handlers).
-
on_idle
(thread=False, multi=True)[source]¶ Decorator for registering a function/method as an idle handler.
This decorator is used to mark a function as an event handler which will be called when no other event handlers have been called in an iteration of
main_loop()
. The function will be called with the correspondingIdleEvent
as the only argument.Note that idle events will only be generated if
include_idle
is set toTrue
.
-
on_player_pos
(thread=False, multi=True, old_pos=None, new_pos=None)[source]¶ Decorator for registering a function/method as a position change handler.
This decorator is used to mark a function as an event handler which will be called for any events indicating that a player’s position has changed while
main_loop()
is executing. The function will be called with the correspondingPlayerPosEvent
as the only argument.The old_pos and new_pos parameters can be used to specify vectors or sequences of vectors (including a
vector_range
) that the player position events must match in order to activate the associated handler. For example, to fire a handler every time any player enters or walks over blocks within (-10, 0, -10) to (10, 0, 10):from picraft import World, Vector, vector_range world = World() world.events.track_players = world.players from_pos = Vector(-10, 0, -10) to_pos = Vector(10, 0, 10) @world.events.on_player_pos(new_pos=vector_range(from_pos, to_pos + 1)) def in_box(event): world.say('Player %d stepped in the box' % event.player.player_id) world.events.main_loop()
Various effects can be achieved by combining old_pos and new_pos filters. For example, one could detect when a player crosses a boundary in a particular direction, or decide when a player enters or leaves a particular area.
Note that only players specified in
track_players
will generate player position events.
-
poll
()[source]¶ Return a list of all events that have occurred since the last call to
poll()
.For example:
>>> w = World() >>> w.events.track_players = w.players >>> w.events.include_idle = True >>> w.events.poll() [<PlayerPosEvent old_pos=0.2,1.0,0.7 new_pos=0.3,1.0,0.7 player=1>, <BlockHitEvent pos=1,1,1 face="x+" player=1>, <BlockHitEvent pos=1,1,1 face="x+" player=1>] >>> w.events.poll() [<IdleEvent>]
-
process
()[source]¶ Poll the server for events and call any relevant event handlers registered with
on_block_hit()
.This method is called repeatedly the event handler loop implemented by
main_loop()
; developers should only call this method when implementing their own event loop manually, or when their (presumably non-threaded) event handler is engaged in a long operation and they wish to permit events to be processed in the meantime.
-
include_idle
¶ If
True
, generate an idle event when no other events would be generated bypoll()
. This attribute defaults toFalse
.
-
poll_gap
¶ The length of time (in seconds) to pause during
main_loop()
.This property specifies the length of time to wait at the end of each iteration of
main_loop()
. By default this is 0.1 seconds.The purpose of the pause is to give event handlers executing in the background time to communicate with the Minecraft server. Setting this to 0.0 will result in faster response to events, but also starves threaded event handlers of time to communicate with the server, resulting in “choppy” performance.
-
track_players
¶ The set of player ids for which movement should be tracked.
By default the
poll()
method will not produce player position events (PlayerPosEvent
). Producing these events requires extra interactions with the Minecraft server (one for each player tracked) which slow down response to block hit events.If you wish to track player positions, set this attribute to the set of player ids you wish to track and their positions will be stored. The next time
poll()
is called it will query the positions for all specified players and fire player position events if they have changed.Given that the
players
attribute represents a dictionary mapping player ids to players, if you wish to track all players you can simply do:>>> world.events.track_players = world.players
-
11.2. BlockHitEvent¶
-
class
picraft.events.
BlockHitEvent
(pos, face, player)[source]¶ Event representing a block being hit by a player.
This tuple derivative represents the event resulting from a player striking a block with their sword in the Minecraft world. Users will not normally need to construct instances of this class, rather they are constructed and returned by calls to
poll()
.Note
Please note that the block hit event only registers when the player right clicks with the sword. For some reason, left clicks do not count.
-
face
¶ A string indicating which side of the block was struck. This can be one of six values: ‘x+’, ‘x-‘, ‘y+’, ‘y-‘, ‘z+’, or ‘z-‘. The value indicates the axis, and direction along that axis, that the side faces:
-
11.3. PlayerPosEvent¶
-
class
picraft.events.
PlayerPosEvent
(old_pos, new_pos, player)[source]¶ Event representing a player moving.
This tuple derivative represents the event resulting from a player moving within the Minecraft world. Users will not normally need to construct instances of this class, rather they are constructed and returned by calls to
poll()
.-
old_pos
¶ A
Vector
indicating the location of the player prior to this event. The location includes decimal places (it is not the tile-position, but the actual position).
-
11.4. ChatPostEvent¶
-
class
picraft.events.
ChatPostEvent
(message, player)[source]¶ Event representing a chat post.
This tuple derivative represents the event resulting from a chat message being posted in the Minecraft world. Users will not normally need to construct instances of this class, rather they are constructed and returned by calls to
poll()
.Note
Chat events are only generated by the Raspberry Juice server, not by Minecraft Pi edition.
-
message
¶ The message that was posted to the world.
-
11.5. IdleEvent¶
-
class
picraft.events.
IdleEvent
[source]¶ Event that fires in the event that no other events have occurred since the last poll. This is only used if
Events.include_idle
isTrue
.