libsl 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|