Eiffel Media API
Overview Cluster Class Classes Index      Previous Next      Top Features

em.network.multiplayer

Class EM_NET_CLIENT


Direct ancestors

EM_NET_BASE

Creation

Features

Invariants

indexing

description

This is the client side of the client-server implementation of the multiplayer framework.

This is a client that has the ability to join an EM_NET_SERVER.

date

$Date: 2005/10/24 11:07:22 $

revision

$Revision: 1.43 $

class

EM_NET_CLIENT [TYPES -> EM_NET_OBJECT_TYPES create make_and_initialize_factory end]

inherit

EM_NET_BASE

create

make (a_port: INTEGER)

-- Initialize a network client.

-- (From EM_NET_BASE)

require
port_is_valid: a_port >= 0 and a_port <= 65535
ensure then
protocol_created: protocol /= Void
object_types_created: object_types /= Void
objects_created: objects /= Void
object_types_created: object_types /= Void
connections_created: connections /= Void
dynamic_connection_list_created: dynamic_connection_list /= Void
timeout_event_created: timeout_event /= Void
groups_created: groups /= Void
id_manager_created: id_manager /= Void
event_2pc_id_manager_created: event_2pc_id_manager /= Void

feature -- Initialisation

make (a_port: INTEGER)

-- Initialize a network client.

-- (From EM_NET_BASE)

require
port_is_valid: a_port >= 0 and a_port <= 65535
ensure then
protocol_created: protocol /= Void
object_types_created: object_types /= Void
objects_created: objects /= Void
object_types_created: object_types /= Void
connections_created: connections /= Void
dynamic_connection_list_created: dynamic_connection_list /= Void
timeout_event_created: timeout_event /= Void
groups_created: groups /= Void
id_manager_created: id_manager /= Void
event_2pc_id_manager_created: event_2pc_id_manager /= Void

feature -- Initialization

make_udp_socket

-- Init

-- (From EM_UDP_SOCKET)

ensure
data_received_event_created: data_received_event /= Void

feature -- Access

network_subsystem: EM_NETWORK_SUBSYSTEM

-- EiffelMedia network subsystem is

-- (From EM_SHARED_SUBSYSTEMS)

ensure
network_subsystem_not_void: Result /= void
last_packet: EM_UDP_PACKET

-- Last received packet

-- (From EM_UDP_SOCKET)

port: INTEGER

-- Local socket port

-- (From EM_SOCKET)

timer: EM_TIME

-- Returns reference to the singleton

-- (From EM_TIME_SINGLETON)

ensure
time_not_void: Result /= Void

feature -- Status setting

close

-- Close the UDP socket.

-- (From EM_SOCKET)

require
network_enabled: Network_subsystem.is_enabled
open: is_open
ensure
closed: not is_open
open

-- Open UDP Socket on a_port.

-- (From EM_SOCKET)

require
network_enabled: Network_subsystem.is_enabled
closed: not is_open
port_set: 1024 < port and port < 65536
ensure then
open: is_open

feature -- Element change

set_net_fps (a_net_fps_value: INTEGER)

-- Set net_fps to a_net_fps_value.

-- (From EM_NET_BASE)

require
positive_net_fps_value: a_net_fps_value > 0
ensure
net_fps_set: net_fps = a_net_fps_value
set_port (a_port: INTEGER)

-- Set port to a_port.

-- (From EM_SOCKET)

require
a_port_in_range: 1024 < a_port and a_port < 65536
ensure
port_set: port = a_port
subscribe_by_event (an_event: EM_NET_EVENT_OBJECT; a_procedure: PROCEDURE [ANY, TUPLE])

-- Subscribe a_procedure to an_event.

-- (From EM_NET_EVENT_PROCESSOR)

subscribe_by_type_id (an_event_type_id: INTEGER; a_procedure: PROCEDURE [ANY, TUPLE])

-- Subscribe a_procedure to an event with an_event_type_id.

-- (From EM_NET_EVENT_PROCESSOR)

unsubscribe_by_event (an_event: EM_NET_OBJECT; a_procedure: PROCEDURE [ANY, TUPLE])

-- Unsubscribe a_procedure from an_event.

-- (From EM_NET_EVENT_PROCESSOR)

unsubscribe_by_type_id (an_event_type_id: INTEGER; a_procedure: PROCEDURE [ANY, TUPLE])

-- Unsubscribe a_procedure from an event with an_event_type_id.

-- (From EM_NET_EVENT_PROCESSOR)

feature -- Basic operations

add_timed_procedure (a_procedure: PROCEDURE[ANY,TUPLE]; a_time_offset_in_ms: INTEGER)

-- Add a_procedure which will be called in TIME_OFFSET miliseconds from "now" in the same thread!
-- Use the feature "process" to call all procedures whose time is up.
-- You could use EM_TIME_SINGLETON for global timing: The EM_EVENT_LOOP will call "process" each loop once.
-- You can also use the EM_EVENT_LOOP to have a per scene executeion.

-- (From EM_DELAYED_PROCEDURES)

require
a_procedure /=Voida_time_offset_in_ms >= 0
process_timed_procedures_in_same_thread

-- executes all stored procedures whose time is up...
-- Make sure you don't add procedures which use a lot of computation time. Only small, short
-- procedures are appropriate. Otherwise use add_timed_callback which runs functions in a different thread
-- to avoid a laggy reaction to other events.

-- (From EM_DELAYED_PROCEDURES)

send (a_packet: EM_UDP_PACKET)

-- Send a_packet to its destination.

-- (From EM_UDP_SOCKET)

require
open: is_open
send_direct (a_destination: EM_INET_SOCKET_ADDRESS; a_string: STRING)

-- Send a_string to a_destination.

-- (From EM_UDP_SOCKET)

wipe_out_all_timed_procedures

-- clear the whole "delayed procedure call" list (procedures added with add_procedure, executed with execute)

-- (From EM_DELAYED_PROCEDURES)

feature -- Events

data_received_event: EM_EVENT_TYPE [TUPLE[EM_UDP_PACKET]]

-- Handle a received packet.

-- (From EM_UDP_SOCKET)

join_timeout_event: EM_EVENT_TYPE[TUPLE[]]

-- Event that is called if the clients join request timeouted

send_failed_event: EM_EVENT_TYPE [TUPLE [INTEGER]]

-- Send failed event.
-- Passed parameter is the error code: Em_error_resolve_ip or Em_error_send_failed

-- (From EM_UDP_SOCKET)

feature -- Connection handling

create_connection (a_socket_address: EM_INET_SOCKET_ADDRESS)

-- Create a connection and monitor it for timeouts.

-- (From EM_NET_BASE)

require
a_socket_address_not_void: a_socket_address /= Void
create_static_connection (a_socket_address: EM_INET_SOCKET_ADDRESS)

-- Create a connection and don't monitor it for timeouts.
-- Use this for broadcasts and other cases where you have mainly outgoing traffic.

-- (From EM_NET_BASE)

require
a_socket_address_not_void: a_socket_address /= Void
delete_connection (a_connection: EM_NET_CONNECTION)

-- Delete a_connection.

-- (From EM_NET_BASE)

require
a_connection_not_void: a_connection /= Void
ensure
connection_removed: not connections.has_item (a_connection)
connection_from_dynamic_list_removed: not dynamic_connection_list.has (a_connection)
join

-- Join to the server.
-- Subscribe to EM_NET_JOIN_RESPONSE in advance of calling join to get
-- notfied if the join attempt was successful.
-- Subscribe to join_timeout_event to get notified if the server was not reachable.

require
server_not_void: server /= Void
last_created_connection: EM_NET_CONNECTION

-- Last created connection

-- (From EM_NET_BASE)

leave

-- Leave the server properly.

ensure
disconnected: not is_connected

feature -- Setters

set_are_timed_procedures_paused (a_value: BOOLEAN)

-- Set are_timed_procedures_paused to a_value
-- Use this to pause the procedure callbacks. This is really usefull if you want to pause a game!
-- However, this will not pause functions added with add_timed_callback.

-- (From EM_DELAYED_PROCEDURES)

ensure
are_timed_procedures_paused_set: are_timed_procedures_paused = a_value
set_nickname (a_nickname: STRING)

-- Set nickname to a_nickname.

require
a_nickname_not_void: a_nickname /= Void
ensure
nickname_set: nickname = a_nickname
set_server_address (a_server: EM_INET_SOCKET_ADDRESS)

-- Set server_address to a_server.

feature {EM_NET_2PC_EVENT_OBJECT} -- Two phase commit

enable_2pc_timed_resend (an_event: EM_NET_2PC_EVENT_OBJECT)

-- Enable timed resend of an_event.

-- (From EM_NET_BASE)

require
event_not_void: an_event /= Void
on_2pc_ack (an_ack: EM_NET_2PC_ACK)

-- Handle client ACK messages.

-- (From EM_NET_BASE)

require
ack_not_void: an_ack /= Void
ensure
event_not_pending_for_connection: not pending_2pc_acks.has (an_ack.event_id) or else not pending_2pc_acks.item (an_ack.event_id).second.has (an_ack.updating_connection)
pending_2pc_acks: DS_HASH_TABLE[EM_PAIR[EM_NET_2PC_EVENT_OBJECT,DS_LINKED_LIST[EM_NET_CONNECTION]],INTEGER]

-- List of pending 2PC events
-- The key of the hashtable is the event_id.
-- The value of the hashtable is the EVENT itself and the list of connections whose ACKs are not received yet.

-- (From EM_NET_BASE)

resend_2pc (an_event: EM_NET_2PC_EVENT_OBJECT)

-- Send an_event to clients that have not sent an acknowledgement yet.

-- (From EM_NET_BASE)

require
event_not_void: an_event /= Void

feature {EM_NET_GROUP} -- Internal object management implementation

add_object_internal (an_object: EM_NET_OBJECT)

-- Add an_object to the list of synchronized objects.

-- (From EM_NET_BASE)

require
object_not_void: an_object /= Void
object_not_yet_added: not has_object (an_object)
ensure
object_added: has_object(an_object)
remove_object_internal (an_object: EM_NET_OBJECT)

-- Remove an_object from the list of synchronized objects.

-- (From EM_NET_BASE)

require
object_not_void: an_object /= Void
has_object: has_object(an_object)
ensure
object_removed: not has_object (an_object)

feature -- Group management

create_group (a_group_name: STRING)

-- Create a new group with a_group_name and make it available in last_created_group.
-- a_group_name must be unique.

-- (From EM_NET_BASE)

require
group_not_exist: not group_exists_by_name (a_group_name)
group (a_group_name: STRING): EM_NET_GROUP

-- Group with group_name

-- (From EM_NET_BASE)

require
group_name_not_void: a_group_name /= Void
group_exists_by_name: group_exists_by_name (a_group_name)
group_exists (a_group: EM_NET_GROUP): BOOLEAN

-- Does a_group exist?

-- (From EM_NET_BASE)

require
group_not_void: a_group /= Void
group_exists_by_name (a_group_name: STRING): BOOLEAN

-- Does group with a_group_name exist?

-- (From EM_NET_BASE)

require
group_name_not_void: a_group_name /= Void
last_created_group: EM_NET_GROUP

-- Last group that was created by create_group

-- (From EM_NET_BASE)

remove_group (a_group: EM_NET_GROUP)

-- Remove a_group.

-- (From EM_NET_BASE)

require
group_exists: group_exists(a_group)
ensure
group_deleted: not group_exists(a_group)
remove_group_by_name (a_group_name: STRING)

-- Remove group with a_group_name.

-- (From EM_NET_BASE)

require
group_exists_by_name: group_exists_by_name(a_group_name)
ensure
group_deleted: not group_exists_by_name(a_group_name)
set_standard_group (a_group_name: STRING)

-- Set standard_group to the group with a_group_name.

-- (From EM_NET_BASE)

require
group_name_not_void: a_group_name /= Void
group_exists_by_name: group_exists_by_name (a_group_name)
ensure
standard_group_set: standard_group = group(a_group_name)
standard_group:EM_NET_GROUP

-- Standard group
-- Many convenience features use this group

-- (From EM_NET_BASE)

feature -- Object management

add_object (an_object: EM_NET_OBJECT)

-- Add an_object to the standard group.

-- (From EM_NET_BASE)

require
an_object_not_void: an_object /= Void
ensure
added_to_standard_group: standard_group.has_object (an_object)
has_object (an_object: EM_NET_OBJECT) : BOOLEAN

-- Does the standard group contain an_object?

-- (From EM_NET_BASE)

require
an_object_not_void: an_object /= Void
remove_object (an_object: EM_NET_OBJECT)

-- Remove an_object from the standard group.

-- (From EM_NET_BASE)

require
an_object_not_void: an_object /= Void
standard_group_has_object: standard_group.has_object (an_object)
ensure
removed_from_standard_group: not standard_group.has_object (an_object)

feature -- Time synchronisation

disable_time_sync

-- Disable time synchronisation.

-- (From EM_NET_BASE)

enable_time_sync

-- Enable time synchronisation.

-- (From EM_NET_BASE)

is_time_sync_enabled: BOOLEAN

-- Is time synchronisation enabled?

-- (From EM_NET_BASE)

set_time_sync_group (a_group: EM_NET_GROUP)

-- Set time_sync_group to a_group.

-- (From EM_NET_BASE)

require
a_group_not_void: a_group /= Void
ensure
protocol_group_updated: protocol.time_sync_group = time_sync_group
time: INTEGER

-- Time in milliseconds!

-- (From EM_NET_BASE)

time_sync_group: EM_NET_GROUP

-- Group used for time synchronisation

-- (From EM_NET_BASE)

feature -- Event handling

publish (an_event: EM_NET_EVENT_OBJECT)

-- Publish an_event to the standard group.

-- (From EM_NET_BASE)

require
an_event_not_void: an_event /= Void
timeout_event: EM_EVENT_TYPE[TUPLE[EM_NET_CONNECTION]]

-- Event that is called if a connection timeout occurs

-- (From EM_NET_BASE)

feature -- Network

disable_auto_transmit

-- Disable auto transmission.

-- (From EM_NET_BASE)

require
ensure
auto_transmit_disabled: not is_auto_transmit_enabled
enable_auto_transmit

-- Enable auto transmission of packets.
-- The mechanism tries to send packets with a frequency of net_fps.

-- (From EM_NET_BASE)

require
not_enabled: not is_auto_transmit_enabled
ensure
auto_transmit_enabled: is_auto_transmit_enabled
send_update_to_server

-- Send updated objects for each group to clients.

-- (From EM_NET_BASE)

feature -- Publishing

local_publish (an_event: EM_NET_EVENT_OBJECT)

-- Publish an_event to the event queue.

-- (From EM_NET_EVENT_PROCESSOR)

feature -- Status information

address: EM_INET_SOCKET_ADDRESS

-- Address where the current client can be reached

game_identifier: STRING

-- Game identifier

-- (From EM_NET_BASE)

is_auto_transmit_enabled: BOOLEAN

-- Is auto transmit enabled?
-- Use this to automate the sending of outgoing data.
-- This relies on the net_fps frequency.

-- (From EM_NET_BASE)

is_connected: BOOLEAN

-- Is the client connected to server?

net_fps: INTEGER

-- Network updates per second

-- (From EM_NET_BASE)

nickname: STRING

-- Clients nickname

object_types: TYPES

-- Object types which can be used in this implementation

-- (From EM_NET_BASE)

server: EM_INET_SOCKET_ADDRESS

-- Server socket address

feature {EM_NET_GROUP} -- Group implementation

groups: DS_HASH_TABLE[EM_NET_GROUP, STRING]

-- List of groups

-- (From EM_NET_BASE)

objects: DS_HASH_TABLE[EM_NET_OBJECT,INTEGER]

-- List of objects which are synchronized over the network

-- (From EM_NET_BASE)

updating_connection: EM_NET_CONNECTION

-- Connection which sent the last update

-- (From EM_NET_BASE)

feature -- ID management

event_2pc_id_manager: EM_NET_OBJECT_ID_MANAGER

-- ID manager for events

-- (From EM_NET_BASE)

id_manager: EM_NET_OBJECT_ID_MANAGER

-- ID manager for net objects

-- (From EM_NET_BASE)

net_object_factory: EM_NET_OBJECT_FACTORY

-- Object creation factory

-- (From EM_NET_BASE)

feature -- Status

is_open: BOOLEAN

-- Is socket open?

-- (From EM_SOCKET)

feature -- Attributes

are_timed_procedures_paused: BOOLEAN

-- Are timed prcedures paused?

-- (From EM_DELAYED_PROCEDURES)

feature {EM_SOCKETS} -- Implementation

handle_data_received

-- Handle data reveived event.

-- (From EM_SOCKET)

handle_send_failed (an_error: INTEGER)

-- Handle send failed.

-- (From EM_UDP_SOCKET)

net2_socket_id: INTEGER

-- Socket id of Net2

-- (From EM_SOCKET)

feature {NONE} -- Implementation

pause_start_ticks: INTEGER

-- pause started ticks
-- Used to compute a timedifference to implement pause mechanism.

-- (From EM_DELAYED_PROCEDURES)

procedure_list: DS_LINKED_LIST[EM_PAIR[PROCEDURE[ANY,TUPLE],INTEGER]]

-- list of procedures

-- (From EM_DELAYED_PROCEDURES)

invariant

-- From EM_NET_BASE
event_container_correct: event_container = objects.item (object_types.em_net_event_container_object)

-- From ANY
reflexive_equality: standard_is_equal (Current)
reflexive_conformance: conforms_to (Current)

end