libsl 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/README.md +50 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/_packets.rb +10346 -0
- data/lib/agent.rb +119 -0
- data/lib/client.rb +57 -0
- data/lib/dsl.rb +54 -0
- data/lib/events.rb +59 -0
- data/lib/libsl.rb +14 -0
- data/lib/network.rb +305 -0
- data/lib/packet.rb +279 -0
- data/lib/types.rb +490 -0
- data/libsl.gemspec +30 -0
- data/test/tc_packet.rb +99 -0
- data/test/tc_types.rb +342 -0
- data/test/ts_all.rb +2 -0
- metadata +101 -0
data/lib/agent.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module LibSL
|
4
|
+
class AgentManager
|
5
|
+
attr_accessor :client
|
6
|
+
attr_reader :position, :look_at, :region_handle, :region_name
|
7
|
+
|
8
|
+
# New AgentManager
|
9
|
+
# @param [Client] client The client
|
10
|
+
def initialize(client)
|
11
|
+
@client = client
|
12
|
+
@position = LLVector3.new(0, 0, 0)
|
13
|
+
@look_at = LLVector3.new(0, 0, 0)
|
14
|
+
@region_handle = LLU64.new(0)
|
15
|
+
@region_name = ""
|
16
|
+
init_handlers
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# Complete a transfer to a sim (e.g. after login or teleport)
|
21
|
+
# @param [Simulator] sim The sim you have been transfered to
|
22
|
+
def move_to_sim(simulator)
|
23
|
+
|
24
|
+
# EventManager.register_handler(EventHandler.new(Proc.new do |type|
|
25
|
+
# EventMachine::add_periodic_timer(2) do
|
26
|
+
# packet = AgentUpdatePacket.new({
|
27
|
+
# :AgentData => {
|
28
|
+
# :AgentID => @client.network_manager.agent_id,
|
29
|
+
# :SessionID => @client.network_manager.session_id,
|
30
|
+
# :BodyRotation => LLQuaternion.new(1, 1, 1),
|
31
|
+
# :HeadRotation => LLQuaternion.new(1, 1, 1),
|
32
|
+
# :State => LLU8.new(0),
|
33
|
+
# :CameraCenter => @position,
|
34
|
+
# :CameraAtAxis => LLVector3.new(),
|
35
|
+
# :CameraLeftAxis => LLVector3.new(),
|
36
|
+
# :CameraUpAxis => LLVector3.new(),
|
37
|
+
# :Far => LLF32.new(64),
|
38
|
+
# :ControlFlags => LLU32.new(0),
|
39
|
+
# :Flags => LLU8.new(0)
|
40
|
+
# }
|
41
|
+
# })
|
42
|
+
# @client.network_manager.send_packet packet, true
|
43
|
+
# end
|
44
|
+
# end, :movement_complete))
|
45
|
+
|
46
|
+
packet = CompleteAgentMovementPacket.new({
|
47
|
+
:AgentData => {
|
48
|
+
:AgentID => @client.network_manager.agent_id,
|
49
|
+
:SessionID => @client.network_manager.session_id,
|
50
|
+
:CircuitCode => @client.network_manager.circuit_code
|
51
|
+
}
|
52
|
+
})
|
53
|
+
simulator.send_packet(packet)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Send a chat message to the simulator
|
57
|
+
# @param [Symbol] type The chat type (:normal, :whisper or :shout)
|
58
|
+
# @param [Integer] channel (optional) should be 0 (public)
|
59
|
+
# or >0 (for scripts listening on that channel)
|
60
|
+
def chat(message, type=:normal, channel=0)
|
61
|
+
type = case type
|
62
|
+
when :whisper then 0
|
63
|
+
when :shout then 2
|
64
|
+
else 1
|
65
|
+
end
|
66
|
+
throw "Channel has to be >=0, #{channel} given!" if channel < 0
|
67
|
+
packet = ChatFromViewerPacket.new({
|
68
|
+
:AgentData => {
|
69
|
+
:AgentID => @client.network_manager.agent_id,
|
70
|
+
:SessionID => @client.network_manager.session_id
|
71
|
+
},
|
72
|
+
:ChatData => {
|
73
|
+
:Message => message,
|
74
|
+
:Type => type,
|
75
|
+
:Channel => channel
|
76
|
+
}
|
77
|
+
})
|
78
|
+
@client.network_manager.send_packet packet
|
79
|
+
end
|
80
|
+
|
81
|
+
# Send an instant message to another agent
|
82
|
+
# @param [String] message the message to send
|
83
|
+
# @param [LLUUID] to The recepients id
|
84
|
+
def im(message, to)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Send Linden$ to another agent
|
88
|
+
# @param [Integer] amount The amount of L$ to send
|
89
|
+
# @param [LLUUID] to The recepient
|
90
|
+
def send_money(amount, to)
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def init_handlers()
|
96
|
+
handler = EventHandler.new(Proc.new do |type, packet, sim|
|
97
|
+
@position = packet.Data.Position
|
98
|
+
@look_at = packet.Data.LookAt
|
99
|
+
@region_handle = packet.Data.RegionHandle
|
100
|
+
sim.send_packet(RegionHandshakeReplyPacket.new({
|
101
|
+
:AgentData => {
|
102
|
+
:AgentID => @client.network_manager.agent_id,
|
103
|
+
:SessionID => @client.network_manager.session_id
|
104
|
+
},
|
105
|
+
:RegionInfo => {
|
106
|
+
:Flags => LLU32.new(0)
|
107
|
+
}
|
108
|
+
}))
|
109
|
+
EventManager.fire_event :movement_complete, sim
|
110
|
+
end, :AgentMovementCompletePacket_Received)
|
111
|
+
EventManager.register_handler(handler)
|
112
|
+
|
113
|
+
handler = EventHandler.new(Proc.new do |type, packet, sim|
|
114
|
+
@region_name = packet.RegionInfo.SimName.data
|
115
|
+
end, :RegionHandshakePacket_Received)
|
116
|
+
EventManager.register_handler(handler)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/client.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
%w{ types packet events agent network dsl }.each { |file|
|
6
|
+
require File.expand_path File.join(File.dirname(__FILE__), file)
|
7
|
+
}
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'eventmachine'
|
11
|
+
|
12
|
+
module LibSL
|
13
|
+
class Client
|
14
|
+
attr_accessor :event_manager, :network_manager, :agent_manager
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
@is_setup = false
|
18
|
+
#@event_manager = EventManager.new self
|
19
|
+
@network_manager = NetworkManager.new self
|
20
|
+
@agent_manager = AgentManager.new self
|
21
|
+
end
|
22
|
+
|
23
|
+
def login()
|
24
|
+
@network_manager.login @firstname, @lastname, @password, @start_location, @grid
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup(firstname, lastname, password, start='last', grid=:agni)
|
28
|
+
@firstname = firstname
|
29
|
+
@lastname = lastname
|
30
|
+
@password = password
|
31
|
+
@start_location = start
|
32
|
+
@grid = grid
|
33
|
+
@is_setup = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def setup?()
|
37
|
+
@is_setup
|
38
|
+
end
|
39
|
+
|
40
|
+
def run()
|
41
|
+
login
|
42
|
+
rescue LoginError => e
|
43
|
+
puts "[ERROR] #{e.message}"
|
44
|
+
EventMachine::stop_event_loop()
|
45
|
+
end
|
46
|
+
|
47
|
+
def stop()
|
48
|
+
EventManager::fire_event(:stopping)
|
49
|
+
@network_manager.logout
|
50
|
+
# Wait for all sims to disconnect
|
51
|
+
EventMachine::add_timer(5) {
|
52
|
+
EventManager::fire_event(:stopped)
|
53
|
+
EventMachine::stop_event_loop()
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/dsl.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
module LibSL
|
3
|
+
module DSL
|
4
|
+
# Client getter
|
5
|
+
def client
|
6
|
+
@client ||= Client.new
|
7
|
+
end
|
8
|
+
module_function :client
|
9
|
+
|
10
|
+
# Setup the client
|
11
|
+
# @param [String] firstname Avatar firstname or account username
|
12
|
+
# @param [String] lastname (optional) Account lastname. Or 'Resident' if a username
|
13
|
+
# is given
|
14
|
+
# @param [String] password Password
|
15
|
+
# @param [String] start (optional) The starting location to connect to. 'last' or 'home' or [REGION NAME]&[X]&[Y]
|
16
|
+
# @param [Symbol] grid (optional) The grid to connect to (:agni for Main grid or :aditi for beta grid)
|
17
|
+
def setup(firstname, lastname, password, start='last', grid=:agni)
|
18
|
+
client.setup firstname, lastname, password, start, grid
|
19
|
+
end
|
20
|
+
|
21
|
+
# Handle the :ready event (syntactic sugar)
|
22
|
+
# @param [Proc] cb (optional) An optional Proc that is called when the event is fired
|
23
|
+
# @yield [Symbol] Event type
|
24
|
+
# @yield [*args] Event specific arguments
|
25
|
+
def when_ready(cb=nil, &block)
|
26
|
+
handle(:ready, cb, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def when_stopping(cb=nil, &block)
|
30
|
+
handle(:stopping, cb, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def when_stopped(cb=nil, &block)
|
34
|
+
handle(:stopped, cb, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Handle the event type given a Proc cb or a block
|
38
|
+
# @param [Symbol] type The event type
|
39
|
+
def handle(type, cb=nil, &block)
|
40
|
+
cb ||= Proc.new
|
41
|
+
EventManager::register_handler EventHandler.new(Proc.new, type)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Send packet
|
45
|
+
# @param [Packet] packet
|
46
|
+
def send_packet(packet, reliable=false)
|
47
|
+
client.network_manager.send_packet(packet, reliable)
|
48
|
+
end
|
49
|
+
|
50
|
+
def shutdown
|
51
|
+
client.stop
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/events.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
module LibSL
|
3
|
+
class EventHandler
|
4
|
+
attr_accessor :types
|
5
|
+
|
6
|
+
# New event handler
|
7
|
+
# @param [Proc] handler Called to handle an event when it is fired
|
8
|
+
# @param [Symbol/Array] type (optional) The type(s) of event to handle
|
9
|
+
def initialize(handler, type=:all)
|
10
|
+
@handler = handler
|
11
|
+
@types = [*type]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Check if this handler can handle one specific event
|
15
|
+
# @param [Symbol] type Event type
|
16
|
+
def accept?(type)
|
17
|
+
if @types.include? :all
|
18
|
+
return true
|
19
|
+
elsif @types.include? type
|
20
|
+
return true
|
21
|
+
else
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Handle the event
|
27
|
+
# @param [Symbol] type Event type
|
28
|
+
# @param [args] args (optional) Arguments passed to the handler
|
29
|
+
def handle(type, *args)
|
30
|
+
@handler.call(type, *args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class EventManager
|
35
|
+
def self.handlers
|
36
|
+
@@handlers ||= []
|
37
|
+
@@handlers
|
38
|
+
end
|
39
|
+
|
40
|
+
# Register an event handler if it does not already exist
|
41
|
+
# @param [EventHandler] handler The handler
|
42
|
+
def self.register_handler(handler)
|
43
|
+
handlers << handler unless handlers.include? handler
|
44
|
+
end
|
45
|
+
|
46
|
+
# Removes an event handler
|
47
|
+
# @param [EventHandler] handler The handler
|
48
|
+
def self.remove_handler(handler)
|
49
|
+
handlers.delete handler
|
50
|
+
end
|
51
|
+
|
52
|
+
# Fires an event that will be handled by registered handlers
|
53
|
+
# @param [Symbol] type Event type
|
54
|
+
# @param [args] args (optional) Arguments passed to the handlers
|
55
|
+
def self.fire_event(type, *args)
|
56
|
+
handlers.each { |h| h.handle(type, *args) if h.accept?(type) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/libsl.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), "client"
|
2
|
+
|
3
|
+
include LibSL
|
4
|
+
include LibSL::DSL
|
5
|
+
|
6
|
+
at_exit do
|
7
|
+
unless client.setup?
|
8
|
+
throw "You need to setup the client!"
|
9
|
+
end
|
10
|
+
|
11
|
+
trap(:INT) {client.stop}
|
12
|
+
trap(:TERM) {client.stop}
|
13
|
+
EventMachine::run { client.run }
|
14
|
+
end
|
data/lib/network.rb
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
require 'xmlrpc/client'
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'observer'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'eventmachine'
|
6
|
+
|
7
|
+
module LibSL
|
8
|
+
class CircuitHandler < EventMachine::Connection
|
9
|
+
# Handles the connection (or circuit in SL)
|
10
|
+
# @param [Simulator] sim The simulator this connection is managed for
|
11
|
+
def initialize(sim)
|
12
|
+
@sim = sim
|
13
|
+
end
|
14
|
+
|
15
|
+
# Called when data is received from the circuit
|
16
|
+
# @param [String] data The received data
|
17
|
+
def receive_data(data)
|
18
|
+
packet = Packet::decode(data)
|
19
|
+
@sim.packet_received packet
|
20
|
+
end
|
21
|
+
|
22
|
+
def unbind
|
23
|
+
EventManager::fire_event :disconnected, @sim
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Simulator
|
28
|
+
attr_accessor :client, :packets_sent_reliably, :packets_received_reliably, :connected
|
29
|
+
attr_reader :connect_packet_ack_handler
|
30
|
+
|
31
|
+
# Manages the connection to a Simulator
|
32
|
+
# @param [Client] client The client
|
33
|
+
# @param [String] ip The simulator ip
|
34
|
+
# @param [Integer] port The simulator port
|
35
|
+
# @param [LLU32] circuit_code The circuit code
|
36
|
+
# @param [LLUUID] session_id The current session id
|
37
|
+
# @param [LLUUID] agent_id The id of the agent that logs into the sim
|
38
|
+
def initialize(client, ip, port, circuit_code, session_id, agent_id)
|
39
|
+
@client = client
|
40
|
+
@connected = false
|
41
|
+
@sim_ip = ip
|
42
|
+
@sim_port = port
|
43
|
+
@circuit_code = circuit_code
|
44
|
+
@session_id = session_id
|
45
|
+
@agent_id = agent_id
|
46
|
+
@sequence_number = 0
|
47
|
+
@connection = EventMachine::open_datagram_socket "0.0.0.0", 0, CircuitHandler, self
|
48
|
+
@packets_sent_reliably = {}
|
49
|
+
@packets_received_reliably = {}
|
50
|
+
|
51
|
+
# Start ack timers
|
52
|
+
@ack_timer = EventMachine::add_periodic_timer(1) do
|
53
|
+
send_acks
|
54
|
+
end
|
55
|
+
@resend_timer = EventMachine::add_periodic_timer 2 do
|
56
|
+
@packets_sent_reliably.each { |sequence_num, packet|
|
57
|
+
if packet.resent_count < 3
|
58
|
+
send_packet(packet, false, true)
|
59
|
+
else
|
60
|
+
@packets_sent_reliably.delete sequence_num
|
61
|
+
end
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Open the connection to the simulator
|
67
|
+
def connect(move_to=true)
|
68
|
+
|
69
|
+
# First PacketAck means connection is established
|
70
|
+
@connect_packet_ack_handler = EventHandler.new(Proc.new do |type, packet, sim|
|
71
|
+
EventManager::remove_handler(sim.connect_packet_ack_handler)
|
72
|
+
# Add ping handler
|
73
|
+
EventManager::register_handler(EventHandler.new(Proc.new do |type, packet, sim|
|
74
|
+
packet = CompletePingCheckPacket.new({
|
75
|
+
:PingID => {
|
76
|
+
:PingID => packet.PingID.PingID
|
77
|
+
}
|
78
|
+
})
|
79
|
+
send_packet packet
|
80
|
+
end, :StartPingCheckPacket_Received))
|
81
|
+
connected = true
|
82
|
+
sim.client.agent_manager.move_to_sim(sim) if move_to
|
83
|
+
end, :PacketAckPacket_Received)
|
84
|
+
EventManager::register_handler(@connect_packet_ack_handler)
|
85
|
+
|
86
|
+
packet = UseCircuitCodePacket.new({
|
87
|
+
:CircuitCode => {
|
88
|
+
:Code => @circuit_code,
|
89
|
+
:SessionID => @session_id,
|
90
|
+
:ID => @agent_id
|
91
|
+
}
|
92
|
+
})
|
93
|
+
send_packet packet, true
|
94
|
+
end
|
95
|
+
|
96
|
+
# Check whether we are connected to the sim
|
97
|
+
def connected?
|
98
|
+
@connected
|
99
|
+
end
|
100
|
+
|
101
|
+
def connected=(val)
|
102
|
+
@connected = val
|
103
|
+
type = val ? :connected : :disconnected
|
104
|
+
EventManager::fire_event(type, self)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Disconnect from the sim
|
108
|
+
def disconnect
|
109
|
+
send_acks
|
110
|
+
#send_packet CloseCircuitPacket.new
|
111
|
+
self.connected = false
|
112
|
+
@connection.close_connection_after_writing
|
113
|
+
end
|
114
|
+
|
115
|
+
# Send a packet to the simulator
|
116
|
+
# @param [Packet] packet The packet to send to the sim
|
117
|
+
# @param [Bool] reliable Whether to send the packet reliably
|
118
|
+
# @param [Bool] resend Whether the packet has already been sent and should
|
119
|
+
# be resent
|
120
|
+
def send_packet(packet, reliable=false, resend=false)
|
121
|
+
# If we resend a packet we keep the flags as they were
|
122
|
+
packet.resent_flag = resend
|
123
|
+
packet.resent_count += 1 if resend
|
124
|
+
unless resend
|
125
|
+
@sequence_number += 1
|
126
|
+
packet.reliable_flag = reliable
|
127
|
+
packet.sequence_number = @sequence_number
|
128
|
+
end
|
129
|
+
|
130
|
+
# Add packet to the reliably sent packets map
|
131
|
+
@packets_sent_reliably[packet.sequence_number] = packet if packet.reliable_flag
|
132
|
+
|
133
|
+
append_acks packet
|
134
|
+
data = packet.encode()
|
135
|
+
@connection.send_datagram data, @sim_ip, @sim_port
|
136
|
+
end
|
137
|
+
|
138
|
+
# Called when a packet is received from the simulator
|
139
|
+
# @param [Packet] packet The received packet
|
140
|
+
def packet_received(packet)
|
141
|
+
@packets_received_reliably[packet.sequence_number.number] = packet if packet.reliable_flag
|
142
|
+
type = (packet.class.name.split("::")[-1] + "_Received").to_sym
|
143
|
+
EventManager::fire_event(:PacketReceived, packet, self)
|
144
|
+
EventManager::fire_event(type, packet, self)
|
145
|
+
end
|
146
|
+
|
147
|
+
def append_acks(packet)
|
148
|
+
return if @packets_received_reliably.length == 0
|
149
|
+
packet.acks = @packets_received_reliably.keys
|
150
|
+
packet.acks_flag = true
|
151
|
+
end
|
152
|
+
|
153
|
+
def send_acks()
|
154
|
+
return if @packets_received_reliably.length == 0
|
155
|
+
packet = PacketAckPacket.new
|
156
|
+
@packets_received_reliably.keys.each do |seq|
|
157
|
+
packet.Packets.add.ID = LLU32.new(seq)
|
158
|
+
@packets_received_reliably.delete seq
|
159
|
+
end
|
160
|
+
send_packet packet
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class LoginError < StandardError; end
|
165
|
+
class SessionNotTimedoutError < LoginError; end
|
166
|
+
class RequiredUpdateError < LoginError; end
|
167
|
+
class OptionalUpdateError < LoginError; end
|
168
|
+
class LoginFailureError < LoginError; end
|
169
|
+
class AccountBannedError < LoginError; end
|
170
|
+
|
171
|
+
class NetworkManager
|
172
|
+
|
173
|
+
GRIDS = {
|
174
|
+
:agni => "https://login.agni.lindenlab.com/cgi-bin/login.cgi",
|
175
|
+
:aditi => "https://login.aditi.lindenlab.com/cgi-bin/login.cgi"
|
176
|
+
}
|
177
|
+
|
178
|
+
attr_accessor :client, :sims
|
179
|
+
attr_reader :first_name, :last_name, :circuit_code, :sims,
|
180
|
+
:session_id, :secure_session_id, :agent_id, :message_of_the_day,
|
181
|
+
:ready_handler
|
182
|
+
|
183
|
+
# Initialize the network manager
|
184
|
+
# @param [Client] client The client
|
185
|
+
def initialize(client)
|
186
|
+
@client = client
|
187
|
+
@sims = []
|
188
|
+
end
|
189
|
+
|
190
|
+
# Login to the grid
|
191
|
+
# @param [String] first Avatar firstname or account username
|
192
|
+
# @param [String] last (optional) Avatar lastname or "Resident"
|
193
|
+
# @param [String] pass The password
|
194
|
+
# @param [String] start (optional) The starting location to connect to
|
195
|
+
# @param [Symbol] grid (optional) The grid to connect to (:agni or :aditi)
|
196
|
+
def login(first, last, pass, start="last", grid=:agni)
|
197
|
+
client = XMLRPC::Client.new2(GRIDS[grid])
|
198
|
+
client.http_header_extra = {"Content-Type" => "text/xml"}
|
199
|
+
|
200
|
+
os = "Win"
|
201
|
+
os = "Mac" if RUBY_PLATFORM.downcase.include?("darwin")
|
202
|
+
os = "Lin" if RUBY_PLATFORM.downcase.include?("linux")
|
203
|
+
|
204
|
+
res = client.call("login_to_simulator", {
|
205
|
+
"first" => first,
|
206
|
+
"last" => last,
|
207
|
+
"passwd" => "$1$" + Digest::MD5.hexdigest(pass),
|
208
|
+
"start" => start,
|
209
|
+
"channel" => "libsl",
|
210
|
+
"version" => "1.0",
|
211
|
+
"platform" => os,
|
212
|
+
"mac" => 6.times.map{sprintf("%02x", rand(255))}.join(":"),
|
213
|
+
"options" => [],
|
214
|
+
"id0" => LLUUID.new.to_s,
|
215
|
+
"agree_to_tos" => "true",
|
216
|
+
"read_critical" => "true",
|
217
|
+
"viewer_digest" => "00000000-0000-0000-0000-000000000000"})
|
218
|
+
|
219
|
+
unless res["login"] == "true"
|
220
|
+
case res["reason"]
|
221
|
+
when "presence" then raise SessionNotTimedoutError, res["message"]
|
222
|
+
when "update" then raise RequiredUpdateError, res["message"]
|
223
|
+
when "optional" then raise OptionalUpdateError, res["message"]
|
224
|
+
when "key" then raise LoginFailureError, res["message"]
|
225
|
+
when "ban" then raise AccountBannedError, res["message"]
|
226
|
+
else raise LoginError, res["message"]
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
@circuit_code = LLU32.new(res["circuit_code"])
|
231
|
+
@session_id = LLUUID.new res["session_id"]
|
232
|
+
@secure_session_id = LLUUID.new res["secure_session_id"]
|
233
|
+
@agent_id = LLUUID.new res["agent_id"]
|
234
|
+
@first_name = res["first_name"]
|
235
|
+
@last_name = res["last_name"]
|
236
|
+
@message_of_the_day = res["message"]
|
237
|
+
setup_handlers
|
238
|
+
connect_to_simulator res["sim_ip"], res["sim_port"]
|
239
|
+
end
|
240
|
+
|
241
|
+
# Logout the client and disconnect from each connected simulator
|
242
|
+
def logout
|
243
|
+
EventManager::register_handler(EventHandler.new(Proc.new do |type, sim|
|
244
|
+
sim.client.network_manager.sims.delete sim
|
245
|
+
end, :disconnected))
|
246
|
+
|
247
|
+
EventManager::register_handler(EventHandler.new(Proc.new do |type, packet, sim|
|
248
|
+
sim.client.network_manager.sims.each { |sim|
|
249
|
+
sim.disconnect
|
250
|
+
}
|
251
|
+
EventManager::fire_event(:logout)
|
252
|
+
end, :LogoutReplyPacket_Received))
|
253
|
+
packet = LogoutRequestPacket.new({
|
254
|
+
:AgentData => {
|
255
|
+
:AgentID => @agent_id,
|
256
|
+
:SessionID => @session_id
|
257
|
+
}
|
258
|
+
})
|
259
|
+
send_packet packet, true
|
260
|
+
end
|
261
|
+
|
262
|
+
def setup_handlers()
|
263
|
+
# PacketAck handler
|
264
|
+
EventManager::register_handler(EventHandler.new(Proc.new do |type, packet, sim|
|
265
|
+
packet.Packets.each{|b| sim.packets_sent_reliably.delete(b.ID.value)}
|
266
|
+
end, :PacketAckPacket_Received))
|
267
|
+
# Handle acks on received packets
|
268
|
+
EventManager::register_handler(EventHandler.new(Proc.new do |type, packet, sim|
|
269
|
+
packet.acks.each{|ack| sim.packets_sent_reliably.delete(ack)}
|
270
|
+
end, :PacketReceived))
|
271
|
+
# Ready handler
|
272
|
+
@ready_handler = EventManager::register_handler(EventHandler.new(Proc.new do |type, sim|
|
273
|
+
EventManager::remove_handler(sim.client.network_manager.ready_handler)
|
274
|
+
EventManager::fire_event(:ready, sim.client)
|
275
|
+
end, :movement_complete))
|
276
|
+
end
|
277
|
+
|
278
|
+
# Connects to a simulator
|
279
|
+
# @param [String] ip The simulator ip
|
280
|
+
# @param [Integer] port The simulator port
|
281
|
+
def connect_to_simulator(ip, port)
|
282
|
+
@sims << Simulator.new(@client, ip, port, @circuit_code, @session_id, @agent_id)
|
283
|
+
@sims.last.connect
|
284
|
+
@active_sim = @sims.last
|
285
|
+
end
|
286
|
+
|
287
|
+
# Activates a simulator as the main simulator
|
288
|
+
# @param [Simulator] sim The simulator to activate
|
289
|
+
def activate_simulator(sim)
|
290
|
+
@sims << sim unless @sims.include? sim
|
291
|
+
sim.connect unless sim.connected?
|
292
|
+
@active_sim = sim
|
293
|
+
AgentManager.move_to_sim sim
|
294
|
+
end
|
295
|
+
|
296
|
+
# Send a packet to a specific simulator
|
297
|
+
# @param [Packet] packet The packet to send
|
298
|
+
# @param [Bool] reliable (optional) Whether to send the packet reliably
|
299
|
+
# @param [Simulator] sim (optional) The sim to send the packet to (or the active sim)
|
300
|
+
def send_packet(packet, reliable=false, sim=nil)
|
301
|
+
sim = @active_sim if sim.nil?
|
302
|
+
@active_sim.send_packet packet, reliable
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|