libsl 0.0.2 → 0.0.3

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/HISTORY ADDED
@@ -0,0 +1,23 @@
1
+ Release history
2
+ ===============
3
+
4
+ Version 0.0.3
5
+ -------------
6
+
7
+ * Instant messaging
8
+ * Teleport
9
+ * Directory searching
10
+ * Logging
11
+
12
+ Version 0.0.2
13
+ -------------
14
+
15
+ * Fixed Gemspec
16
+ * Fixed Rakefile
17
+
18
+ Version 0.0.1
19
+ -------------
20
+
21
+ * Working Login
22
+ * Networking
23
+ * Event system
data/LICENSE ADDED
@@ -0,0 +1,281 @@
1
+ .
2
+
3
+ GNU GENERAL PUBLIC LICENSE
4
+ Version 2, June 1991
5
+
6
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
7
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
8
+ Everyone is permitted to copy and distribute verbatim copies
9
+ of this license document, but changing it is not allowed.
10
+
11
+ Preamble
12
+
13
+ The licenses for most software are designed to take away your
14
+ freedom to share and change it. By contrast, the GNU General Public
15
+ License is intended to guarantee your freedom to share and change free
16
+ software--to make sure the software is free for all its users. This
17
+ General Public License applies to most of the Free Software
18
+ Foundation's software and to any other program whose authors commit to
19
+ using it. (Some other Free Software Foundation software is covered by
20
+ the GNU Lesser General Public License instead.) You can apply it to
21
+ your programs, too.
22
+
23
+ When we speak of free software, we are referring to freedom, not
24
+ price. Our General Public Licenses are designed to make sure that you
25
+ have the freedom to distribute copies of free software (and charge for
26
+ this service if you wish), that you receive source code or can get it
27
+ if you want it, that you can change the software or use pieces of it
28
+ in new free programs; and that you know you can do these things.
29
+
30
+ To protect your rights, we need to make restrictions that forbid
31
+ anyone to deny you these rights or to ask you to surrender the rights.
32
+ These restrictions translate to certain responsibilities for you if you
33
+ distribute copies of the software, or if you modify it.
34
+
35
+ For example, if you distribute copies of such a program, whether
36
+ gratis or for a fee, you must give the recipients all the rights that
37
+ you have. You must make sure that they, too, receive or can get the
38
+ source code. And you must show them these terms so they know their
39
+ rights.
40
+
41
+ We protect your rights with two steps: (1) copyright the software, and
42
+ (2) offer you this license which gives you legal permission to copy,
43
+ distribute and/or modify the software.
44
+
45
+ Also, for each author's protection and ours, we want to make certain
46
+ that everyone understands that there is no warranty for this free
47
+ software. If the software is modified by someone else and passed on, we
48
+ want its recipients to know that what they have is not the original, so
49
+ that any problems introduced by others will not reflect on the original
50
+ authors' reputations.
51
+
52
+ Finally, any free program is threatened constantly by software
53
+ patents. We wish to avoid the danger that redistributors of a free
54
+ program will individually obtain patent licenses, in effect making the
55
+ program proprietary. To prevent this, we have made it clear that any
56
+ patent must be licensed for everyone's free use or not licensed at all.
57
+
58
+ The precise terms and conditions for copying, distribution and
59
+ modification follow.
60
+
61
+ GNU GENERAL PUBLIC LICENSE
62
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
63
+
64
+ 0. This License applies to any program or other work which contains
65
+ a notice placed by the copyright holder saying it may be distributed
66
+ under the terms of this General Public License. The "Program", below,
67
+ refers to any such program or work, and a "work based on the Program"
68
+ means either the Program or any derivative work under copyright law:
69
+ that is to say, a work containing the Program or a portion of it,
70
+ either verbatim or with modifications and/or translated into another
71
+ language. (Hereinafter, translation is included without limitation in
72
+ the term "modification".) Each licensee is addressed as "you".
73
+
74
+ Activities other than copying, distribution and modification are not
75
+ covered by this License; they are outside its scope. The act of
76
+ running the Program is not restricted, and the output from the Program
77
+ is covered only if its contents constitute a work based on the
78
+ Program (independent of having been made by running the Program).
79
+ Whether that is true depends on what the Program does.
80
+
81
+ 1. You may copy and distribute verbatim copies of the Program's
82
+ source code as you receive it, in any medium, provided that you
83
+ conspicuously and appropriately publish on each copy an appropriate
84
+ copyright notice and disclaimer of warranty; keep intact all the
85
+ notices that refer to this License and to the absence of any warranty;
86
+ and give any other recipients of the Program a copy of this License
87
+ along with the Program.
88
+
89
+ You may charge a fee for the physical act of transferring a copy, and
90
+ you may at your option offer warranty protection in exchange for a fee.
91
+
92
+ 2. You may modify your copy or copies of the Program or any portion
93
+ of it, thus forming a work based on the Program, and copy and
94
+ distribute such modifications or work under the terms of Section 1
95
+ above, provided that you also meet all of these conditions:
96
+
97
+ a) You must cause the modified files to carry prominent notices
98
+ stating that you changed the files and the date of any change.
99
+
100
+ b) You must cause any work that you distribute or publish, that in
101
+ whole or in part contains or is derived from the Program or any
102
+ part thereof, to be licensed as a whole at no charge to all third
103
+ parties under the terms of this License.
104
+
105
+ c) If the modified program normally reads commands interactively
106
+ when run, you must cause it, when started running for such
107
+ interactive use in the most ordinary way, to print or display an
108
+ announcement including an appropriate copyright notice and a
109
+ notice that there is no warranty (or else, saying that you provide
110
+ a warranty) and that users may redistribute the program under
111
+ these conditions, and telling the user how to view a copy of this
112
+ License. (Exception: if the Program itself is interactive but
113
+ does not normally print such an announcement, your work based on
114
+ the Program is not required to print an announcement.)
115
+
116
+ These requirements apply to the modified work as a whole. If
117
+ identifiable sections of that work are not derived from the Program,
118
+ and can be reasonably considered independent and separate works in
119
+ themselves, then this License, and its terms, do not apply to those
120
+ sections when you distribute them as separate works. But when you
121
+ distribute the same sections as part of a whole which is a work based
122
+ on the Program, the distribution of the whole must be on the terms of
123
+ this License, whose permissions for other licensees extend to the
124
+ entire whole, and thus to each and every part regardless of who wrote it.
125
+
126
+ Thus, it is not the intent of this section to claim rights or contest
127
+ your rights to work written entirely by you; rather, the intent is to
128
+ exercise the right to control the distribution of derivative or
129
+ collective works based on the Program.
130
+
131
+ In addition, mere aggregation of another work not based on the Program
132
+ with the Program (or with a work based on the Program) on a volume of
133
+ a storage or distribution medium does not bring the other work under
134
+ the scope of this License.
135
+
136
+ 3. You may copy and distribute the Program (or a work based on it,
137
+ under Section 2) in object code or executable form under the terms of
138
+ Sections 1 and 2 above provided that you also do one of the following:
139
+
140
+ a) Accompany it with the complete corresponding machine-readable
141
+ source code, which must be distributed under the terms of Sections
142
+ 1 and 2 above on a medium customarily used for software interchange; or,
143
+
144
+ b) Accompany it with a written offer, valid for at least three
145
+ years, to give any third party, for a charge no more than your
146
+ cost of physically performing source distribution, a complete
147
+ machine-readable copy of the corresponding source code, to be
148
+ distributed under the terms of Sections 1 and 2 above on a medium
149
+ customarily used for software interchange; or,
150
+
151
+ c) Accompany it with the information you received as to the offer
152
+ to distribute corresponding source code. (This alternative is
153
+ allowed only for noncommercial distribution and only if you
154
+ received the program in object code or executable form with such
155
+ an offer, in accord with Subsection b above.)
156
+
157
+ The source code for a work means the preferred form of the work for
158
+ making modifications to it. For an executable work, complete source
159
+ code means all the source code for all modules it contains, plus any
160
+ associated interface definition files, plus the scripts used to
161
+ control compilation and installation of the executable. However, as a
162
+ special exception, the source code distributed need not include
163
+ anything that is normally distributed (in either source or binary
164
+ form) with the major components (compiler, kernel, and so on) of the
165
+ operating system on which the executable runs, unless that component
166
+ itself accompanies the executable.
167
+
168
+ If distribution of executable or object code is made by offering
169
+ access to copy from a designated place, then offering equivalent
170
+ access to copy the source code from the same place counts as
171
+ distribution of the source code, even though third parties are not
172
+ compelled to copy the source along with the object code.
173
+
174
+ 4. You may not copy, modify, sublicense, or distribute the Program
175
+ except as expressly provided under this License. Any attempt
176
+ otherwise to copy, modify, sublicense or distribute the Program is
177
+ void, and will automatically terminate your rights under this License.
178
+ However, parties who have received copies, or rights, from you under
179
+ this License will not have their licenses terminated so long as such
180
+ parties remain in full compliance.
181
+
182
+ 5. You are not required to accept this License, since you have not
183
+ signed it. However, nothing else grants you permission to modify or
184
+ distribute the Program or its derivative works. These actions are
185
+ prohibited by law if you do not accept this License. Therefore, by
186
+ modifying or distributing the Program (or any work based on the
187
+ Program), you indicate your acceptance of this License to do so, and
188
+ all its terms and conditions for copying, distributing or modifying
189
+ the Program or works based on it.
190
+
191
+ 6. Each time you redistribute the Program (or any work based on the
192
+ Program), the recipient automatically receives a license from the
193
+ original licensor to copy, distribute or modify the Program subject to
194
+ these terms and conditions. You may not impose any further
195
+ restrictions on the recipients' exercise of the rights granted herein.
196
+ You are not responsible for enforcing compliance by third parties to
197
+ this License.
198
+
199
+ 7. If, as a consequence of a court judgment or allegation of patent
200
+ infringement or for any other reason (not limited to patent issues),
201
+ conditions are imposed on you (whether by court order, agreement or
202
+ otherwise) that contradict the conditions of this License, they do not
203
+ excuse you from the conditions of this License. If you cannot
204
+ distribute so as to satisfy simultaneously your obligations under this
205
+ License and any other pertinent obligations, then as a consequence you
206
+ may not distribute the Program at all. For example, if a patent
207
+ license would not permit royalty-free redistribution of the Program by
208
+ all those who receive copies directly or indirectly through you, then
209
+ the only way you could satisfy both it and this License would be to
210
+ refrain entirely from distribution of the Program.
211
+
212
+ If any portion of this section is held invalid or unenforceable under
213
+ any particular circumstance, the balance of the section is intended to
214
+ apply and the section as a whole is intended to apply in other
215
+ circumstances.
216
+
217
+ It is not the purpose of this section to induce you to infringe any
218
+ patents or other property right claims or to contest validity of any
219
+ such claims; this section has the sole purpose of protecting the
220
+ integrity of the free software distribution system, which is
221
+ implemented by public license practices. Many people have made
222
+ generous contributions to the wide range of software distributed
223
+ through that system in reliance on consistent application of that
224
+ system; it is up to the author/donor to decide if he or she is willing
225
+ to distribute software through any other system and a licensee cannot
226
+ impose that choice.
227
+
228
+ This section is intended to make thoroughly clear what is believed to
229
+ be a consequence of the rest of this License.
230
+
231
+ 8. If the distribution and/or use of the Program is restricted in
232
+ certain countries either by patents or by copyrighted interfaces, the
233
+ original copyright holder who places the Program under this License
234
+ may add an explicit geographical distribution limitation excluding
235
+ those countries, so that distribution is permitted only in or among
236
+ countries not thus excluded. In such case, this License incorporates
237
+ the limitation as if written in the body of this License.
238
+
239
+ 9. The Free Software Foundation may publish revised and/or new versions
240
+ of the General Public License from time to time. Such new versions will
241
+ be similar in spirit to the present version, but may differ in detail to
242
+ address new problems or concerns.
243
+
244
+ Each version is given a distinguishing version number. If the Program
245
+ specifies a version number of this License which applies to it and "any
246
+ later version", you have the option of following the terms and conditions
247
+ either of that version or of any later version published by the Free
248
+ Software Foundation. If the Program does not specify a version number of
249
+ this License, you may choose any version ever published by the Free Software
250
+ Foundation.
251
+
252
+ 10. If you wish to incorporate parts of the Program into other free
253
+ programs whose distribution conditions are different, write to the author
254
+ to ask for permission. For software which is copyrighted by the Free
255
+ Software Foundation, write to the Free Software Foundation; we sometimes
256
+ make exceptions for this. Our decision will be guided by the two goals
257
+ of preserving the free status of all derivatives of our free software and
258
+ of promoting the sharing and reuse of software generally.
259
+
260
+ NO WARRANTY
261
+
262
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
263
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
264
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
265
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
266
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
267
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
268
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
269
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
270
+ REPAIR OR CORRECTION.
271
+
272
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
273
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
274
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
275
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
276
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
277
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
278
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
279
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
280
+ POSSIBILITY OF SUCH DAMAGES.
281
+
data/Rakefile CHANGED
@@ -36,6 +36,9 @@ task :inc_version do
36
36
  else
37
37
  version[1] += 1
38
38
  end
39
+ puts "Increment version to: #{version.join(".")}?"
40
+ prompt = $stdin.gets.chomp
41
+ version = prompt.split(".") unless prompt == ""
39
42
  File.open('VERSION', "w") { |f| f.write version.join(".") }
40
43
  system "git add VERSION && git commit -m \"Increment version\""
41
44
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
data/lib/agent.rb CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  module LibSL
4
4
  class AgentManager
5
- attr_accessor :client
6
- attr_reader :position, :look_at, :region_handle, :region_name
5
+ attr_accessor :client, :position, :look_at
6
+ attr_reader :region_handle, :region_name
7
7
 
8
8
  # New AgentManager
9
9
  # @param [Client] client The client
@@ -11,11 +11,23 @@ module LibSL
11
11
  @client = client
12
12
  @position = LLVector3.new(0, 0, 0)
13
13
  @look_at = LLVector3.new(0, 0, 0)
14
+ @region_id = LLUUID.new
14
15
  @region_handle = LLU64.new(0)
15
16
  @region_name = ""
16
17
  init_handlers
17
18
  end
18
19
 
20
+ def first_name
21
+ @client.network_manager.first_name
22
+ end
23
+
24
+ def last_name
25
+ @client.network_manager.last_name
26
+ end
27
+
28
+ def full_name
29
+ first_name + " " + last_name
30
+ end
19
31
 
20
32
  # Complete a transfer to a sim (e.g. after login or teleport)
21
33
  # @param [Simulator] sim The sim you have been transfered to
@@ -81,13 +93,73 @@ module LibSL
81
93
  # Send an instant message to another agent
82
94
  # @param [String] message the message to send
83
95
  # @param [LLUUID] to The recepients id
84
- def im(message, to)
96
+ def im(message, to, session=nil)
97
+ session ||= LLUUID.new
98
+ packet = ImprovedInstantMessagePacket.new({
99
+ :AgentData => {
100
+ :AgentID => @client.network_manager.agent_id,
101
+ :SessionID => @client.network_manager.session_id
102
+ },
103
+ :MessageBlock => {
104
+ :FromGroup => LLBool.new(false),
105
+ :ToAgentID => to,
106
+ :ParentEstateID => LLU32.new(0),
107
+ :RegionID => @region_id,
108
+ :Position => @position,
109
+ :Offline => LLU8.new(1),
110
+ :Dialog => LLU8.new(DIALOG[:IM]),
111
+ :ID => session,
112
+ :Timestamp => LLU32.new(Time.now.to_i),
113
+ :FromAgentName => LLVariable1.new(full_name),
114
+ :Message => LLVariable2.new(message),
115
+ :BinaryBucket => LLVariable2.new("")
116
+ }
117
+ })
118
+ @client.network_manager.send_packet packet
85
119
  end
86
120
 
87
121
  # Send Linden$ to another agent
88
122
  # @param [Integer] amount The amount of L$ to send
89
123
  # @param [LLUUID] to The recepient
90
- def send_money(amount, to)
124
+ def send_money(amount, to, description="")
125
+ packet = MoneyTransferRequestPacket.new({
126
+ :AgentData => {
127
+ :AgentID => @client.network_manager.agent_id,
128
+ :SessionID => @client.network_manager.session_id
129
+ },
130
+ :Money => {
131
+ :SourceID => @client.network_manager.agent_id,
132
+ :DestID => to,
133
+ :Flags => LLU8.new(0),
134
+ :Amount => LLS32.new(amount),
135
+ :AggregatePermNextOwner => LLU8.new(0),
136
+ :AggregatePermInventory => LLU8.new(0),
137
+ # see http://hg.secondlife.com/viewer-release/src/tip/indra/llinventory/lltransactiontypes.h#cl-77)
138
+ :TransactionType => LLS32.new(5001), # Gift
139
+ :Description => LLVariable1.new(description)
140
+ }
141
+ })
142
+ end
143
+
144
+ # Teleport somewhere
145
+ # @param [LLUUID] region_id The ID of the region to teleport to
146
+ # @param [LLVector3] position (optional) The position to teleport
147
+ # to in region local coordinates
148
+ def teleport(region_id, position=nil)
149
+ raise ArgumentError, "region_id has to be a LLUUID" unless region_id.is_a? LLUUID
150
+ position = LLVector3.new(128, 128, 0) unless position.is_a? LLVector3
151
+ packet = TeleportRequestPacket.new({
152
+ :AgentData => {
153
+ :AgentID => @client.network_manager.agent_id,
154
+ :SessionID => @client.network_manager.session_id
155
+ },
156
+ :Info => {
157
+ :RegionID => region_id,
158
+ :Position => position,
159
+ :LookAt => LLVector3.new(1, 0, 0)
160
+ }
161
+ })
162
+ @client.network_manager.send_packet packet
91
163
  end
92
164
 
93
165
  private
@@ -111,7 +183,8 @@ module LibSL
111
183
  EventManager.register_handler(handler)
112
184
 
113
185
  handler = EventHandler.new(Proc.new do |type, packet, sim|
114
- @region_name = packet.RegionInfo.SimName.data
186
+ @region_name = packet.RegionInfo.SimName.data.delete("\0")
187
+ @region_id = packet.RegionInfo2.RegionID
115
188
  end, :RegionHandshakePacket_Received)
116
189
  EventManager.register_handler(handler)
117
190
  end
data/lib/client.rb CHANGED
@@ -2,7 +2,7 @@ require 'net/http'
2
2
  require 'net/https'
3
3
  require 'uri'
4
4
 
5
- %w{ types packet events agent network dsl }.each { |file|
5
+ %w{ logging types packet events search agent network dsl }.each { |file|
6
6
  require File.expand_path File.join(File.dirname(__FILE__), file)
7
7
  }
8
8
 
@@ -11,13 +11,20 @@ require 'eventmachine'
11
11
 
12
12
  module LibSL
13
13
  class Client
14
- attr_accessor :event_manager, :network_manager, :agent_manager
14
+ attr_accessor :event_manager, :network_manager, :agent_manager, :search_manager, :logger
15
15
 
16
16
  def initialize()
17
17
  @is_setup = false
18
18
  #@event_manager = EventManager.new self
19
19
  @network_manager = NetworkManager.new self
20
20
  @agent_manager = AgentManager.new self
21
+ @search_manager = SearchManager.new self
22
+ @logger = Logger.new
23
+ end
24
+
25
+ def logger=(logger)
26
+ raise ArgumentError, "Argument has to be a Logger" unless logger.is_a? Logger
27
+ @logger = logger
21
28
  end
22
29
 
23
30
  def login()
data/lib/dsl.rb CHANGED
@@ -7,6 +7,19 @@ module LibSL
7
7
  end
8
8
  module_function :client
9
9
 
10
+ def logger
11
+ client.logger
12
+ end
13
+
14
+ # Configure logging
15
+ # @param [String] output Path to a logfile
16
+ # @param [IOS] output An output stream ($stdout, $stderr, etc..)
17
+ # @param [Bool] debug (optional) Enable debug messages
18
+ # @param [Bool] colors (optional) Enable ANSI coloring for terminal emulators
19
+ def set_logging(output, debug=false, colors=true)
20
+ client.logger = Logger.new(output, debug, colors)
21
+ end
22
+
10
23
  # Setup the client
11
24
  # @param [String] firstname Avatar firstname or account username
12
25
  # @param [String] lastname (optional) Account lastname. Or 'Resident' if a username
data/lib/libsl.rb CHANGED
@@ -1,5 +1,46 @@
1
1
  require File.join File.dirname(__FILE__), "client"
2
2
 
3
+ module LibSL
4
+ # IM Dialog types (see http://wiki.secondlife.com/wiki/ImprovedInstantMessage)
5
+ DIALOG = {
6
+ :IM => 0,
7
+ :Notification => 1,
8
+ :GroupInvitation => 3,
9
+ :InventoryOffer => 4,
10
+ :AcceptInventoryOffer => 5,
11
+ :DeclineInventoryOffer => 6,
12
+ :GroupVote => 7,
13
+ :ObjectInventoryOffer => 9,
14
+ :AcceptObjectInventoryOffer => 10,
15
+ :DeclineObjectInventoryOffer => 11,
16
+ :StartSession => 13,
17
+ :StartSessionOnline => 14, # Start a session but don't prune offline users
18
+ :StartGroupSession => 15,
19
+ :MessageToSession => 17,
20
+ :LeaveSession => 18,
21
+ :IMFromObject => 19,
22
+ :AutoResponse => 20,
23
+ :ChatHistory => 21, # Shows the message in the console and chat history
24
+ :SendTeleportLure => 22,
25
+ :AcceptTeleportLure => 23,
26
+ :DeclineTeleportLure => 24,
27
+ :GodlikeRequestTeleport => 25, # Only with god powers
28
+ :GotoURL => 28,
29
+ :RequestHelp => 29, # IM for help
30
+ :HelpRequested => 30, # IM sent automatically on call for help
31
+ :IMNoEmail => 31, # IM won't go to email
32
+ :IMToGroup => 32, # IM from Group Officer to all group members
33
+ :GroupNoticeRequested => 33,
34
+ :AcceptGroupInvitation => 35,
35
+ :DeclineGroupInvitation => 36,
36
+ :FriendshipOffer => 38,
37
+ :AcceptFriendshipOffer => 39,
38
+ :DeclineFriendshipOffer => 40,
39
+ :StartTyping => 41,
40
+ :StopTyping => 42
41
+ }
42
+ end
43
+
3
44
  include LibSL
4
45
  include LibSL::DSL
5
46
 
data/lib/logging.rb ADDED
@@ -0,0 +1,61 @@
1
+
2
+ module LibSL
3
+ class LogFile
4
+ def initialize(dest=nil)
5
+ @dest = dest
6
+ end
7
+
8
+ def << (val)
9
+ case @dest
10
+ when nil then return
11
+ when String then
12
+ File.new(@dest) {|f| f << val}
13
+ when IO then @dest << val
14
+ end
15
+ self
16
+ end
17
+ end
18
+
19
+ class Logger
20
+ # Colors
21
+ RESET_COLOR = "\e[0m" # Reset
22
+ ERROR_COLOR = "\e[1m\e[31m" # Red
23
+ DEBUG_COLOR = "\e[1m\e[37m" # Grey
24
+ INFO_COLOR = "\e[1m\e[33m" # Yellow
25
+ UNDERLINE = "\e[4m" # Underline
26
+
27
+ def initialize(output=nil, debug=false, colors=true)
28
+ @output = output.is_a?(LogFile) ? output : LogFile.new(output)
29
+ @debug = debug
30
+ @colors = colors
31
+ end
32
+
33
+ def log(level, message, *args)
34
+ color = self.class.const_get("#{level.to_s.upcase}_COLOR".to_sym)
35
+ @output << "[" << apply_color(color + UNDERLINE, level.to_s.upcase + " " + Time.now.strftime("%F %T")) << "] " \
36
+ << sprintf(apply_color(color, message), *args) << "\n"
37
+ end
38
+
39
+ def debug(message, *args)
40
+ return unless @debug
41
+ log(:debug, message, *args)
42
+ end
43
+
44
+ def info(message, *args)
45
+ log(:info, message, *args)
46
+ end
47
+
48
+ def error(message, *args)
49
+ log(:error, message, *args)
50
+ end
51
+
52
+ private
53
+ def apply_color(color, to)
54
+ if @colors && color
55
+ return sprintf("%s%s%s", color, to, RESET_COLOR)
56
+ else
57
+ return to
58
+ end
59
+ end
60
+ end
61
+ end
data/lib/network.rb CHANGED
@@ -26,7 +26,7 @@ module LibSL
26
26
 
27
27
  class Simulator
28
28
  attr_accessor :client, :packets_sent_reliably, :packets_received_reliably, :connected
29
- attr_reader :connect_packet_ack_handler
29
+ attr_reader :connect_packet_ack_handler, :sim_ip, :sim_port
30
30
 
31
31
  # Manages the connection to a Simulator
32
32
  # @param [Client] client The client
@@ -63,6 +63,15 @@ module LibSL
63
63
  end
64
64
  end
65
65
 
66
+ def ==(other)
67
+ return false unless other.is_a? Simulator
68
+ other.sim_ip == sim_ip and other.sim_port == sim_port
69
+ end
70
+
71
+ def eql?(other)
72
+ self == other
73
+ end
74
+
66
75
  # Open the connection to the simulator
67
76
  def connect(move_to=true)
68
77
 
@@ -107,7 +116,7 @@ module LibSL
107
116
  # Disconnect from the sim
108
117
  def disconnect
109
118
  send_acks
110
- #send_packet CloseCircuitPacket.new
119
+ send_packet CloseCircuitPacket.new
111
120
  self.connected = false
112
121
  @connection.close_connection_after_writing
113
122
  end
@@ -131,6 +140,7 @@ module LibSL
131
140
  @packets_sent_reliably[packet.sequence_number] = packet if packet.reliable_flag
132
141
 
133
142
  append_acks packet
143
+ EventManager::fire_event(:sending_packet, packet, self)
134
144
  data = packet.encode()
135
145
  @connection.send_datagram data, @sim_ip, @sim_port
136
146
  end
@@ -273,24 +283,43 @@ module LibSL
273
283
  EventManager::remove_handler(sim.client.network_manager.ready_handler)
274
284
  EventManager::fire_event(:ready, sim.client)
275
285
  end, :movement_complete))
286
+ # Teleport Finish handler
287
+ EventManager::register_handler(EventHandler.new(Proc.new do |type, packet, sim|
288
+ @active_sim.disconnect
289
+ sim = connect_to_simulator(packet.Info.SimIP.ip, packet.Info.SimPort.port)
290
+ activate_simulator(sim)
291
+ end, :TeleportFinishPacket_Received))
292
+ # Teleport Local handler
293
+ EventManager::register_handler(EventHandler.new(Proc.new do |type, packet, sim|
294
+ @client.agent_manager.position = packet.Info.Position
295
+ @client.agent_manager.look_at = packet.Info.LookAt
296
+ end, :TeleportLocalPacket_Received))
276
297
  end
277
298
 
278
299
  # Connects to a simulator
279
300
  # @param [String] ip The simulator ip
280
301
  # @param [Integer] port The simulator port
281
302
  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
303
+ sim = Simulator.new(@client, ip, port, @circuit_code, @session_id, @agent_id)
304
+ unless @sims.include? sim
305
+ @sims << sim
306
+ @sims.last.connect
307
+ @active_sim = @sims.last
308
+ end
309
+ sim
285
310
  end
286
311
 
287
312
  # Activates a simulator as the main simulator
288
313
  # @param [Simulator] sim The simulator to activate
289
314
  def activate_simulator(sim)
315
+ return if @active_sim == sim
290
316
  @sims << sim unless @sims.include? sim
291
- sim.connect unless sim.connected?
317
+ if sim.connected?
318
+ AgentManager.move_to_sim sim
319
+ else
320
+ sim.connect
321
+ end
292
322
  @active_sim = sim
293
- AgentManager.move_to_sim sim
294
323
  end
295
324
 
296
325
  # Send a packet to a specific simulator
data/lib/search.rb ADDED
@@ -0,0 +1,248 @@
1
+
2
+
3
+ module LibSL
4
+ class SearchResult
5
+ attr_reader :type, :query_id, :data
6
+
7
+ def initialize(type, query_id, data)
8
+ @type = type
9
+ @query_id = query_id
10
+ @data = data
11
+ end
12
+ end
13
+
14
+ class SearchManager
15
+
16
+ PARCEL_CATEGORIES = {
17
+ :none => 0,
18
+ :linden => 1,
19
+ :adult => 2,
20
+ :arts => 3,
21
+ :business => 4,
22
+ :educational => 5,
23
+ :gaming => 6,
24
+ :hangout => 7,
25
+ :newcomer => 8,
26
+ :park => 9,
27
+ :residential => 10,
28
+ :shopping => 11,
29
+ :stage => 12,
30
+ :other => 13,
31
+ :any => -1
32
+ }
33
+
34
+ attr_accessor :client
35
+ attr_reader :results
36
+
37
+ def initialize(client)
38
+ @client = client
39
+ @results = []
40
+ register_handlers
41
+ end
42
+
43
+ # Pick a list of avatars by name
44
+ # @param [String] name The name to search for
45
+ # @yield [SearchResult]
46
+ def pick_avatar(name, &block)
47
+ query_id = LLUUID.new
48
+ register_callback(query_id, block)
49
+ packet = AvatarPickerRequestPacket.new({
50
+ :AgentData => {
51
+ :AgentID => @client.network_manager.agent_id,
52
+ :SessionID => @client.network_manager.session_id,
53
+ :QueryID => query_id
54
+ },
55
+ :Data => { :Name => LLVariable1.new(name) }
56
+ })
57
+ @client.network_manager.send_packet packet
58
+ end
59
+
60
+ # Start a person search query
61
+ # @param [String] query The query string to search for
62
+ # @param [Bool] online (optional) List only online people if true
63
+ # @param [Integer] start (optional) Pagination support
64
+ # @yield [SearchResult]
65
+ def person(query, online=false, start=0, &block)
66
+ query_id = LLUUID.new
67
+ register_callback(query_id, block)
68
+ flags = 0x01
69
+ flags |= 0x02 if online
70
+ packet = DirFindQueryPacket.new({
71
+ :AgentData => {
72
+ :AgentID => @client.network_manager.agent_id,
73
+ :SessionID => @client.network_manager.session_id
74
+ },
75
+ :QueryData => {
76
+ :QueryID => query_id,
77
+ :QueryText => LLVariable1.new(query),
78
+ :QueryFlags => LLU32.new(flags),
79
+ :QueryStart => LLS32.new(start)
80
+ }
81
+ })
82
+ @client.network_manager.send_packet packet
83
+ end
84
+
85
+ # Start a group search query
86
+ # @param [String] query The query string to search for
87
+ # @param [Integer] start (optional) Pagination support
88
+ # @yield [SearchResult]
89
+ def group(query, start=0, &block)
90
+ query_id = LLUUID.new
91
+ register_callback(query_id, block)
92
+ flags = 0x10
93
+ packet = DirFindQueryPacket.new({
94
+ :AgentData => {
95
+ :AgentID => @client.network_manager.agent_id,
96
+ :SessionID => @client.network_manager.session_id
97
+ },
98
+ :QueryData => {
99
+ :QueryID => query_id,
100
+ :QueryText => LLVariable1.new(query),
101
+ :QueryFlags => LLU32.new(flags),
102
+ :QueryStart => LLS32.new(start)
103
+ }
104
+ })
105
+ @client.network_manager.send_packet packet
106
+ end
107
+
108
+ # Start an event search query. Searches for all upcoming events.
109
+ # @param [String] query The query string to search for
110
+ # @param [Bool] mature (optional) Whether to include mature events
111
+ # @param [Integer] start (optional) Pagination support
112
+ # @yield [SearchResult]
113
+ def event(query, mature=false, start=0, &block)
114
+ query_id = LLUUID.new
115
+ register_callback(query_id, block)
116
+ flags = 0x20
117
+ flags |= 0x2000 unless mature
118
+ packet = DirFindQueryPacket.new({
119
+ :AgentData => {
120
+ :AgentID => @client.network_manager.agent_id,
121
+ :SessionID => @client.network_manager.session_id
122
+ },
123
+ :QueryData => {
124
+ :QueryID => query_id,
125
+ :QueryText => LLVariable1.new("u|0|"+query),
126
+ :QueryFlags => LLU32.new(flags),
127
+ :QueryStart => LLS32.new(start)
128
+ }
129
+ })
130
+ @client.network_manager.send_packet packet
131
+ end
132
+
133
+ # Start a places search query
134
+ # @param [String] query (optional) Query string. Empty string => Agent owned
135
+ # @param [String] sim_name (optional) Restrict search to this region
136
+ # @param [Symbol] parcel_category (optional) See PARCEL_CATEGORIES
137
+ # @param [Integer] start (optional) Pagination support
138
+ # @yield [SearchResult]
139
+ def place(query="", sim_name="", parcel_category=:any, start=0, &block)
140
+ query_id = LLUUID.new
141
+ register_callback(query_id, block)
142
+ flags = 0
143
+ flags |= 0x40 if query == "" # Agent owned
144
+ category = PARCEL_CATEGORIES[parcel_category] or -1
145
+ packet = DirPlacesQueryPacket.new({
146
+ :AgentData => {
147
+ :AgentID => @client.network_manager.agent_id,
148
+ :SessionID => @client.network_manager.session_id
149
+ },
150
+ :QueryData => {
151
+ :QueryID => query_id,
152
+ :QueryText => LLVariable1.new(query),
153
+ :QueryFlags => LLU32.new(flags),
154
+ :Category => LLS8.new(category),
155
+ :SimName => LLVariable1.new(sim_name),
156
+ :QueryStart => LLS32.new(start)
157
+ }
158
+ })
159
+ @client.network_manager.send_packet packet
160
+ end
161
+
162
+ private
163
+
164
+ def register_handlers()
165
+ EventManager::register_handler(EventHandler.new(Proc.new do |type, packet, sim|
166
+ result_type = case type
167
+ when :AvatarPickerReplyPacket_Received then :Avatars
168
+ when :DirPeopleReplyPacket_Received then :People
169
+ when :DirEventsReplyPacket_Received then :Events
170
+ when :DirGroupsReplyPacket_Received then :Groups
171
+ when :DirPlacesReplyPacket_Received then :Places
172
+ end
173
+ results = case type
174
+ when :AvatarPickerReplyPacket_Received then
175
+ packet.Data.blocks.map do |block|
176
+ {
177
+ :FirstName => block.FirstName.data.delete("\0"),
178
+ :LastName => block.LastName.data.delete("\0"),
179
+ :ID => block.AvatarID
180
+ }
181
+ end
182
+ when :DirPeopleReplyPacket_Received then
183
+ packet.QueryReplies.blocks.map do |block|
184
+ {
185
+ :FirstName => block.FirstName.data.delete("\0"),
186
+ :LastName => block.LastName.data.delete("\0"),
187
+ :ID => block.AgentID,
188
+ :Group => block.Group.data.delete("\0"),
189
+ :Reputation => block.Reputation.value
190
+ }
191
+ end
192
+ when :DirEventsReplyPacket_Received then
193
+ packet.QueryReplies.blocks.map do |block|
194
+ {
195
+ :OwnerID => block.OwnerID,
196
+ :Name => block.Name.data.delete("\0"),
197
+ :EventID => block.EventID.value,
198
+ :Date => block.Date.data.delete("\0"),
199
+ :UnixTime => block.UnixTime.value,
200
+ :Mature => (block.EventFlags.value & 0x02 > 0)
201
+ }
202
+ end
203
+ when :DirGroupsReplyPacket_Received then
204
+ packet.QueryReplies.blocks.map do |block|
205
+ {
206
+ :ID => block.GroupID,
207
+ :Name => block.GroupName.data.delete("\0"),
208
+ :Members => block.Members.value
209
+ }
210
+ end
211
+ when :DirPlacesReplyPacket_Received then
212
+ packet.QueryReplies.block.map do |block|
213
+ {
214
+ :ID => block.ParcelID,
215
+ :Name => block.Name.data.delete("\0"),
216
+ :ForSale => block.ForSale.value,
217
+ :Auction => block.Auction.value
218
+ }
219
+ end
220
+ end
221
+ query_id = case type
222
+ when :AvatarPickerReplyPacket_Received then
223
+ packet.AgentData.QueryID
224
+ else
225
+ packet.QueryData.QueryID
226
+ end
227
+ results = SearchResult.new(result_type, query_id, results)
228
+ @results << results
229
+ EventManager::fire_event(:search_results, results)
230
+ EventManager::fire_event("search_results_#{query_id.to_s}".to_sym, results)
231
+ end, [
232
+ :AvatarPickerReplyPacket_Received,
233
+ :DirPeopleReplyPacket_Received,
234
+ :DirEventsReplyPacket_Received,
235
+ :DirGroupsReplyPacket_Received,
236
+ :DirPlacesReplyPacket_Received
237
+ ]))
238
+ end
239
+
240
+ def register_callback(query_id, cb)
241
+ if cb
242
+ EventManager::register_handler(EventHandler.new(Proc.new do |type, results|
243
+ cb.call(results)
244
+ end, "search_results_#{query_id.to_s}".to_sym))
245
+ end
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,56 @@
1
+ require "test/unit"
2
+ require File.expand_path File.join(File.dirname(__FILE__), "..", "lib", "logging")
3
+
4
+ class Time
5
+ def strftime(format)
6
+ "TIME"
7
+ end
8
+ end
9
+
10
+ module LibSL
11
+ class LogFile
12
+ def initialize(out)
13
+ @data = ""
14
+ end
15
+
16
+ def << (val)
17
+ @data += val.to_s
18
+ self
19
+ end
20
+
21
+ def print()
22
+ $stdout << @data
23
+ end
24
+
25
+ def to_s
26
+ @data
27
+ end
28
+ end
29
+
30
+ class TestLogger < Test::Unit::TestCase
31
+ def test_logging()
32
+ stream = LogFile.new
33
+ logger = Logger.new(stream, false, false)
34
+ logger.debug("DEBUG MESSAGE")
35
+ logger.info("INFO MESSAGE")
36
+ logger.error("ERROR MESSAGE")
37
+ output = "[INFO TIME] INFO MESSAGE\n[ERROR TIME] ERROR MESSAGE\n"
38
+ assert_equal(output, stream.to_s)
39
+ end
40
+
41
+ def test_colors()
42
+ stream = LogFile.new
43
+ logger = Logger.new(stream, true, true)
44
+ logger.debug("DEBUG MESSAGE")
45
+ logger.info("INFO MESSAGE")
46
+ logger.error("ERROR MESSAGE")
47
+ output = "[#{Logger::DEBUG_COLOR}#{Logger::UNDERLINE}DEBUG TIME#{Logger::RESET_COLOR}] " +
48
+ "#{Logger::DEBUG_COLOR}DEBUG MESSAGE#{Logger::RESET_COLOR}\n" +
49
+ "[#{Logger::INFO_COLOR}#{Logger::UNDERLINE}INFO TIME#{Logger::RESET_COLOR}] " +
50
+ "#{Logger::INFO_COLOR}INFO MESSAGE#{Logger::RESET_COLOR}\n" +
51
+ "[#{Logger::ERROR_COLOR}#{Logger::UNDERLINE}ERROR TIME#{Logger::RESET_COLOR}] " +
52
+ "#{Logger::ERROR_COLOR}ERROR MESSAGE#{Logger::RESET_COLOR}\n"
53
+ assert_equal(output, stream.to_s)
54
+ end
55
+ end
56
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libsl
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Lukas Botsch
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-08 00:00:00 +02:00
18
+ date: 2011-04-10 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -45,6 +45,8 @@ extra_rdoc_files: []
45
45
 
46
46
  files:
47
47
  - .gitignore
48
+ - HISTORY
49
+ - LICENSE
48
50
  - README.md
49
51
  - Rakefile
50
52
  - VERSION
@@ -54,10 +56,13 @@ files:
54
56
  - lib/dsl.rb
55
57
  - lib/events.rb
56
58
  - lib/libsl.rb
59
+ - lib/logging.rb
57
60
  - lib/network.rb
58
61
  - lib/packet.rb
62
+ - lib/search.rb
59
63
  - lib/types.rb
60
64
  - libsl.gemspec
65
+ - test/tc_logging.rb
61
66
  - test/tc_packet.rb
62
67
  - test/tc_types.rb
63
68
  - test/ts_all.rb