SLSA Protocols for Sailing

From SecondSailing

Jump to: navigation, search

Contents

SLSA Protocols for sailing

Status of this document:

  • Implemented in the generally available WWC Setter v 1.05
  • Implemented in the Flying Fizz
  • Implemented in the Shelly Fizz
  • Implemented in the WWC Interpreter and WWC Receiver scripts that are available to all boat builders
  • 2009/04/04 MD: Added a boat authenticity check upon race subscription


This document contains a series of guidelines for boat builders to follow if they want their boats to be compatible with the SLSA racing system and be able to communicate with other boats on the water.

We identify communication between:

  1. racedirector/sailor and wind/wave/current setter
  2. boat and wind/wave/current setter
  3. racedirector/sailor and startline
  4. boat and start/finishline
  5. startline and finishline
  6. boat and buoys
  7. 2 or more boats
  8. boat and external systems


  • If a builder uses (a part of) this protocol, he/she commits him/herself to supporting all future changes to the protocol as well. The boat builder should follow the protocol in detail and implement every mandatory part of the protocol where applicable. Boat builders will not make changes or enhancements to the parts of the protocol they use without contributing those changes back to the community. Instead, any needed changes and enhancements should be made by altering the protocol itself and thus making them available to everyone.
  • Implementing the wind, waves and current system described here is made easy by using the freely available WWC Receiver and WWC Interpreter scripts. These scripts provide wind, waves, current implementation, race subscriptions, wind shadowing, wind fluctuations and local conditions. Contact Mothgirl Dibou or Cynthia Centaur for a copy.
  • This protocol is a living document and is likely to change over time.

Design goals

The following issues shall be covered by this specification:

  1. The communication protocols shall be extendable, i.e. when new parameters turn out to be important for new boats/applications it shall be possible to add such parameters to the protocol.
  2. The communication protocols shall allow for the implementation of distributed systems, i.e. a set of devices located in several objects which are located remotely (example: a race course with buoys on the course that report a passing boat).
  3. The communication protocols shall allow for independent systems, e.g. race wind that only acts on boats that are logged in to that race. This also includes independent systems of the same type (e.g. two sets of wind, wave, current parameters for two start lines that are located close to each other)
  4. the system should be open to every serious boat builder and for every serious builder of racing equipment but it should include a few "secrets" that make it necessary to ask for those. The reason behind that is to disallow anonymous usage of these specifications to discourage griefing.
  5. explicitly excluded (and not forgotten) cryptographic and similar means to obscure or verify the content of sent messages. This specification assumes that cheating and griefing will not be done by serious members of the sailing community.



Communication between RD/Sailor and Wind, Wave, Current Setter



Communication between boats and Wind, Wave, Current Setter

WWC Setter Ping

The WWC setter (subsequently known as "the setter") precedes every broadcast with a ping message on a non-public channel. Boats use this signal to compute the non-public channels for receiving either old style wind, wwc cruise settings or wwc race settings.


Backward compatibility with previous wind setter system

The wwc setter broadcasts its cruise wind settings 3 seconds after the ping on a non-public channel. This channel and the data strings sent on it are compatible with Kanker Greenacre's wind setter system. These broadcasts are for backward compatibility only and ensure that boats based on the Tako sailing engine can use the wwc wind setter. The wwc setter's race settings use a different format that is incompatible with the Tako and its derivatives.


Cruise Wind, Waves, Current

  • Cruise WWC can be implemented using the current WWC Interpreter and WWC Receiver scripts.
  • This part of the protocol is mandatory. Any implementation of the Cruise WWC protocol will make use of either all three settings or, at minimum, of the wind and current parameters only. Further, any local wind, wave or current variances are not optional. This rule is to ensure that every boat will sail with the same parameter set. Waves can be a little harder to implement, so they are optional for now.
  • Boats that implement the protocol will not offer any other weather options to the avatar that controls the boat, such as user-defined wind, switching off current, using SL wind or other wind sources, etc. The basic idea is to make all boats behave in the same way and thus no exceptions are allowed. The boat builder always has the choice not to use the protocol at all.


Notification Message (regionsay)

3 seconds after the ping, the WWC setter broadcasts a notification message announcing its presence on a non-public channel using the llRegionSay() function. For security reasons, the computation of this channel isn't published here. The message looks like this:

 message type   value="WwcSetter"
 unique id      a numeric value that increases every time the cruise settings have changed

Cruise WWC Request (email)

All boats in the wwc setter's region that haven't yet locked onto weather parameters - or that have ignored other settings in order to keep listening for other WWC setters - will pick up the notification message and send back an email to the wwc setter (the UUID of the setter has been retrieved from the incoming message), requesting the cruise wwc parameters. The email subject contains the message type with a value of "CrWwcReq". The body of the email remains empty. Example:

 llEmail("a311ce4d-e755-f148-7999-56f289ca3f3b@lsl.secondlife.com", "CrWwcReq", "");


WWC Cruise Params Message (email)

The WWC setter checks for email every 3 seconds; it retrieves the boat's UUID key and sends an email back that contains the Cruise WWC parameters.

The subject of this email contains the value "CrWwc". The message body consists of several records with parameters in a comma-separated list. Individual records are separated by a new line ("\n"). The message body contains the following records:

Cruise Wind Message

 message type      value = "CrWnd"
 wind direction    average wind direction using compass (i.e. not geometric) angles; range: 0˚-359˚
 wind speed        average wind speed in m/s; range: 2.5m/s-18.0m/s
 wind gusts        maximum variability of gusts/lulls as a percentage of wind speed; range: 0%(0.0)-100%(1.0)
 wind shifts       max. wind shift half-arc in degrees; range 0˚(0.0)-180˚(180.0)
 wind change rate  rate multiplier at which the wind gusts and shifts occur. 1.0 = default; range: x0.1-x5.0
 wind system       name of an external wind system to use (optional)
 speed multiplier  1.0 is RL realistic speed. At time of writing 1.9 is SL realistic speed. range: x0.1-x2.0
  • All parameters reference the wwc wind system; if an external wind system is specified, all other parameters in the "CrWnd"message must be ignored.

Cruise Waves Message

 message type     value = "CrWav"
 wave height      average wave height in meters. range: 0.0m-5.0m
 wave length      average wave length in meters. range: 10.0m-50.0m
 wave speed       average wave speed in m/s. range: 3.0m/s-15.0m/s
 wave height variance wave height variance as a percentage of av. wave height. range: 0%(0.0)-100%(100.0)
 wave length variance wave length variance as a percentage of av. wave length. range: 0%(0.0)-75%(0.75)
 wave origin X    x wave origin using global SL grid coordinates; allows wave sync between boats. (supplied by wwc)
 wave origin Y    y wave origin using global SL grid coordinates. (supplied by wwc)
 water depth      default water depth for current and waves in m. (sensed automatically)
 wave system      name of an external wave system to use (optional)
  • All parameters reference the wwc wave system; if an external wave system is specified, all other parameters in the "CrWave" message must be ignored.

Cruise Current Message

 message type         value = "CrCrt"
 current direction    direction where the current is flowing *towards* relative to the seabed
                      in compass (i.e. not geometric) degrees. range: 0˚-359˚
 current speed        average strength of the current in m/s. range: 0.0m/s-3.0m/s
 water depth          default water depth for current and waves. (sensed automatically)
 current system       name of an external current system to use (optional)
  • All parameters reference the wwc current system; if an external current system is specified, all other parameters in the "CrCrnt" message must be ignored.

Cruise WWC Local Variances

The email body of the Cruise WWC Parameters Message contains any local variances of the WWC settings, if they have been stored in a settings notecard. There is one separate line in the email body for each local variance setting.

 message type     (value = "CrWwcLoc"),
 global x coordinate,
 global y coordinate,
 100% effect radius in meters (range 0 - 200)
 0% effect radius in meters (range: 100% effect radius - 255)
 wind speed multiplier (range: 0.0 - 3.0),
 extra wind angle (range: 180 - 180),
 wave height multiplier (range: 0.0 - 3.0),
 current speed multiplier (range: 0.0 - 3.0),
 extra current angle (range: 180 - 180)
  • The decay works as follows: the effect is full in a circle with a radius of "100% effect radius" and gradually decays to 0% at a distance of "0% effect radius". Example:
 100% effect radius = 50
 0% effect radius = 100
  • At 40 meters from the point specified by global coordinates, the effect will be 100%; at 75 meters, the effect is reduced to 50%, at 90 meters the effect's strength is 20%.

Crosstalk Avoidance

  • The boat only checks for emails that originate from the WWC setter it signed up to (because it stored its UUID key) and only accepts messages that contain the right data string in the subject. Example:
 llGetNextEmail("a311ce4d-e755-f148-7999-56f289ca3f3b@lsl.secondlife.com", "CrWwc");


Security considerations

Boats are unlikely to receive emails from objects other than the WWC setter because no other object will know the boat's UUID key, which is generated on rez. It would be possible to retrieve the UUID key of a rezzed boat by listening in on the communications it sends out, but the boat itself only accepts email send out by the WWC setter, ignoring any other messages.

Furthermore, the WWC setter only checks for emails with the correct subject header and ignores any other messages. A possible attack vector would be a classic denial of service attack, i.e. to bombard the setter with emails with the correct format, making the setter stall as it attempts to satisfy the fake email requests and incurs the LSL penalty for sending email. This would only work if the UUID key of the WWC setter was known. A remedy: after receiving multiple emails from the same sender in a short period of time, the sender could be added to a temporary blacklist and send out a warning on channel 0 for all to hear what is going on.

  • Blacklist implemented: The boat can stop listening for other WWC setters now and stop checking for incoming emails. Implementation of this feature is optional.


  • Sanity check: the boat now prompts the helmsman if she wants to accept any new wwc settings. Boat builders are encouraged to add a basic sanity check to this prompt, i.e. to display a summary of the parameters, in order to prevent accepting settings that are unreasonable for the type of boat in question. It is always possible for people to wear their own wwc setters, use fake setters or to accidentally set up parameters that are off the scale, say a wind speed of 50 m/s. The sanity check gives the helmsman the opportunity to both identify the wind setter in question and to decide wether to accept or ignore the received values.



Race Wind, Waves, Current

  • This part of the protocol is optional. Implementation however is very easy when using the standard WWC Interpreter and WWC Receiver scripts.
  • Any boat that uses this part of the protocol will at minimum, make use of the wind and current settings. The local variance parameters, where applicable, are not optional. This is to ensure that every boat will behave in a similar way when on the water. At present, the implementation of the wave parameters is optional.


Notification message (regionsay)

The WWC setter broadcasts a race notification 3 seconds after the ping message on a computed channel using the llRegionSay() function. The computation of the communications channel is not published here for security reasons. The message send has the following format:

 message type       value = "Rc"
 race id            unique ID for this race. range: 1-9999
 race name          example: SailOn
 class name         examples: Flying Fizz, Tako, Tradewind
 sailing mode       0,1,2,3 meaning: no mode requirement, novice mode, competition mode, expert mode
 crew size          required crew size for this race. 0 if no requirement
 race director      name of race director
 unique id          numeric value that increases every time the wwc settings change
  • The purpose of the race notification message is to prompt the sailor with a subscription notice for the race; the race parameters themselves are sent through email as detailed below.

Race Sub Request (email)

  • The boats pick up the notification message and ask the helmsman if he/she wants to subscribe to the race. If the helmsman confirms, a subscription request is send from the boat to the WWC setter using email. The email subject will contain the message type, which has the value "RcWwcReq". The body of the email contains:
 message type    value = "RcWwcReq"
 race id         unique race ID for this race. range: 1-9999

Example:

 llEmail("a311ce4d-e755-f148-7999-56f289ca3f3b@lsl.secondlife.com", "RcWwcReq", "RcWwcReq,1234");


The WWC setter picks up the subscription request, retrieves the UUID key of the boat and sends an email back to the boat with the current race parameters. The boat stores the WWC setter's UUID key; it only accepts emails coming from setter and only if they contain the right subject header.

Race Params Message (email)

The subject of the email send by the WWC setter to the boat has the value "RcWwc". The message body contains several records with WWC information in a comma-separated list. Individual records are separated by a new line "\n". The message body contains the following records:


Race Information Message

 message type     value = "Rc"
 race id          unique ID for this race; range: 1-9999
 race name        example: SailOn
 class name       examples: Flying Fizz, Tako, Tradewind
 boat version     version number of the boat that is required or a seed to check the version numbers 
                  of the internal scripts of the boat (to ensure all boats are of the same version,
                  have not been tampered with and are equally fast)
 crew size        required crew size during the race, includes the helmsman; 0 if no requirement
 sailing mode     0,1,2,3 meaning: no mode required, novice mode, competition mode, expert mode
 extra value 1    custom value
 extra value 2    custom value
  • Boat version: If a boat version is specified, only boats with the same version number can subscribe to the race
  • Class name: If a boat class is specified, only boats of the same class can subscribe to the race

Race Wind Message

 message type     value = "RcWnd"
 race id          unique ID for this race, range: 1-9999
 wind direction   average wind direction using compass (i.e. not geometric) angles; range: 0˚-359˚
 wind speed       average wind speed in in m/s; range: 2.5m/s-18.0m/s
 wind gusts       maximum variability of gusts/lulls as percentage of wind speed; range: 0%(0.0)-100%(100.0)
 wind shifts      max. wind shift half-arc in degrees; range: 0˚-180˚
 wind change rate rate multiplier at which the wind gusts and shifts occur. 1.0 = default; range: x0.1-x5.0
 wind system      name of an external wind system to use (optional)
 speed multiplier 1.0 is RL realistic speed. At time of writing 1.9 is SL realistic speed. range: x1.0-x2.0
  • All parameters reference the wwc wind system. If an external wind system is specified, all other parameters in the "RcWnd" message must be ignored.

Race Waves Message

 message type    value = "RcWav"
 race id         unique ID for this race; range: 1-9999
 wave height     average wave height in meters; range 0.0m-5.0m
 wave length     average wave length in meters; range 10.0m-100.0m
 wave speed      average wave speed in m/s; range: 3.0m/s-15.0m/s
 wave height variance wave height variance as a percentage of av. wave height; range: 0%(0.0)-200%(2.0)
 wave length variance wave length variance as a percentage of av. wave length; range: 0%(0.0)-75%(0.75)
 wave origin X   x wave origin using global SL grid coordinates; allows wave sync between boats. (provided by wwc)
 wave origin Y   y wave origin using global SL grid coordinates (provided by wwc) 
 water depth     default water depth for current and waves, in m; sensed automatically
 wave system     name of an external wave system to use instead
  • All parameters reference the wwc wave system; if an external wave system is specified, all other parameters in the "RcWav" message must be ignored.

Race Current Message

 message type      value = "RcCrt"
 race id           unique ID for this race; range: 1-9999
 current direction direction where the current is flowing *towards* relative to the seabed
                   in compass (i.e. not geometric) degrees; range: 0˚-359˚
 current speed     average strength of the current in m/s; range: 0.0m/s-3.0m/s
 water depth       default water depth for current and waves in m; sensed automatically
 current system    name of an external current system to use (optional)
  • All parameters reference the wwc current system; if an external current system is specified, all other parameters in the "RcCrt" message must be ignored.

Race Local Variances Message

The email body of the Race WWC Parameters Message contains any local variances of the WWC settings, if they have been stored in a settings notecard. There is one separate line in the email body for each local variance setting.

 message type                 (value = "RcWwcLoc"),
 race id                      (randomly generated number),
 global x coordinate,
 global y coordinate,
 100% effect radius in meters (range: 0 to 200),
 0% effect radius in meters   (range: 100% effect radius to 255),
 wind speed multiplier         (range: 0.0 to 3.0),
 extra wind angle             (range: -180 to +180),
 wave height multiplier       (range: 0.0 to 3.0),
 current speed multiplier     (range: 0.0 to 3.0),
 extra current angle          (range: -180 to +180)
  • The decay works as follows: the effect is full in a circle with a radius of "100% effect radius" and gradually decays to 0% at a distance of "0% effect radius". Example:
 100% effect radius = 50
 0% effect radius = 100
  • At 40 meters from the specified global coordinates the effect will be 100%, at 75 meters from the coordinates the effect will be 50%, at 90 meters from the coordinates, the effect is 20%.

Race subscription (email)

Once the boat has received the email containing the race parameters, it sends an email back with the value "RcSub" as subject line and a message body in this format:

 message type          (value = "RcSub"),
 race id             (randomly generated number),
 name of skipper, 
 name of crew member 1 (if present),
 name of crew member 2 (if present),
 name of crew member 3 (if present),
 key to determine the authenticity of the boat,
  • The UUID key of the boat does not need to be passed on in the email body because it is already part of the LSL email message.
  • Best practice consideration: find a way to show that the boat's helmsman has subscribed to the current race, so that both the race director and the other racers can see that the boat has entered. Example: The Flying Fizz v3 pops up its ID box when a helmsman subscribes to the race. Another good practice: show the helmsman's initials or first name on the sails or in the race id, where applicable.
  • The key to determine the authenticity of the boat can be omitted, but can also be used to determine whether or not the scripts inside the boat are authentic. In the Fizz scripts it works as follows:

- each script has the same secret key, which is given to it by the builder

- upon rez all the script keys are checked internally, to eliminate the existence of extra scripts or altered scripts

- to eliminate the possibility that all the scripts have been replaced by fake versions, an encrypted key is included in the race subscription message. The key is computed like this: llSHA1String(secretScriptKey+(string)receivedRaceId)

Race Parameter Updates (email)

Boats continue to check for email because the race director may decide to change the racing conditions before or during the race itself. For example, the RD might may change conditions during a race to simulate a sudden weather change. In this case, the WWC setter sends out an email to every boat that is subscribed to the race. The message format is the same as with the initial Race Params Message ("RcWwc" email); the Race Params Update email only contains any params in the message body that have changed from the inital Race Params. The boats then keep any previous settings and only replace the parts that are passed along in the Params Update.


Crosstalk Avoidance

  • The boat only checks for emails that originate from the WWC setter it signed up to (because it stored its UUID key) and only accepts messages that contain the right data string in the subject. Example:
 llGetNextEmail("a311ce4d-e755-f148-7999-56f289ca3f3b@lsl.secondlife.com", "RcWwc");

Security Considerations

See #Security_considerations



Communications between WWC Setters and Start Lines

Note that this part of the protocol is still under construction. In most circumstances, the start line should make a 90 degree angle with the wind. If the start line is able to pick up wind parameters from the setter, it can rotate into the correct position. To achieve this, the start line acts like a boat to pick up the cruise wind parameters. When a race director starts a race, the race wind settings are used instead. If the wind direction changes during a race (for example, in between individual heats) the setter sends out updates to the line. But if there is no race and the cruise wind is changed instead, no updates are sent out automatically; in this case, the line should reset and ask for new wind parameters.

  • The automatic rotating with the wind should be an optional feature.

Line Request (email)

The start line request for wind is little bit different, to let the setter know it is dealing with the line instead of a boat.

 message type    value="CrWwcReqLine"

for cruising, and:

 message type    value="RcWwcReqLine"
 race id         unique race ID for this race. range: 1-9999

for races. For example

 llEmail("a311ce4d-e755-f148-7999-56f289ca3f3b@lsl.secondlife.com", "RcWwcReqLine", "RcWwcReq,1234");

See above for the rest of this protocol. Start lines do not subscribe to a race, so the "RcSub" message is not used.

Handling Race Subscriptions (email)

The WWC setter passes race subscriptions on to the start line. It does so by sending an email to the start line or finish line (the WWC Setter stores the UUID key of any line that requests the wind settings).

 message type, (value = "RcSub")
 race id,
 name of skipper, 
 name of crew member 1, (if present)
 name of crew member 2, (if present)
 name of crew member 3, etc.


The line will need to be able to store subscription lists for multiple race id's. It is possible to use more than one WWC setter when there is a race for several classes that start shortly after each other. Each class will have its own list of competitors and its own results. The wind should be the same for all classes of course, but this is the responsibility of the race director.

Communication between racedirector/sailor and startline

To be defined.

Remark CC: Obviously no communication between the start line and the race director is needed anymore. A race is completely controlled by the wind setter.

Communication between boat and start line

Countdown Notification Message (shout)

At the beginning of each start sequence, the start line broadcasts a time signal on the race channel (-8001). Boats can pick up this message and trigger on-board countdown timers at the correct point in time and with the correct countdown interval. The message format is as follows:

 llShout(-8001,"start," + (string)(llGetUnixTime()+time));
  • the time variable describes the countdown interval, in seconds. Thus, the signal contains the point in (unix) time at which the countdown expires.
  • shout vs regionsay: using shout as a compromise - regionsay only helps if boats are indeed within the same region. boats with timers will need to be within 100m from the line.

Communication between startline and finishline revised by MD

(Note by MD: I revised the original section that can be found below this. If everyone agrees on the contents of this revised section, we can delete the old)


First a major choice needs to be made:

  • do we use email as the communication method or http requests?
  • for email the UUID keys of both lines are needed (UUID keys remain the same as long as the lines are not re-rezzed
    • (note YN): both http and email only need one key or url handle to start a connection - the other key/url is always embedded in the request.
  • for http an object needs to apply for a valid URL to set itself up as a webserver. This url can change over time when the old one has become invalid
    • (note YN): whenever the urls change, the script sends an update to the service to keep the network record up to date (automatically).


This has a huge impact on the way the lines are able to find each other.

We have to take a decision on this first.


Comment (YN): While I agree with you that we'd likely want to choose either http or email for object discovery from the protocol perspective, it is worth pointing out that both methods I described are just as easy to implement. Using both methods in parallel would be likely be undesirable, leading to unnecessary code duplication and increased maintenance effort. Now, regarding the question itself: as you point out, there are many drawbacks using email when compared to http, most of which can be summed up as 'increased inefficiency' (which also causes lag btw): the need for slave scripts and attendant link messages, the polling method that needs to be used (i.e. using the timer to check for incoming messages), and the fact that communication is always one-way meaning two emails need to be sent in this fashion just to mimick a request and response pair. The http method is far more efficient: it reduces the number of running scripts and link messages, it eliminates the need for polling and it allows proper two-way communication (and its way faster of course).


I (MD) personally think that http is the best way to let the lines communicate. Each time an email is send the script is paused for 20 seconds. To overcome this, the object needs a load of emailer scripts. Also, emailing is 1 way communication. The sender sends the email and hopes it will arrive. Whereas with HTTP the sender sends a request, it is received and replied to. There are no time delay penalties when HTTP is used. When email is used, a script needs to periodically check for new messages using a timer, where with HTTP, the script simply receives an event notification.


Because I think and hope you will agree with me on this i took the liberty of writing the next part assuming that HTTP will be the communication method to use. If we decide that email is the preferred method, this section will have to be changed.

(end of MD's note)

  • Race lines can be networked to create a course with a separate start and finish line.
  • In order to set up this communication, both lines need to know either the UUID key of the other line to send messages or the URL made available by the other line.
  • There are several methods of approach for this. At the moment of writing this it is not clear which method should be used. These methods are:
  1. notecard method - providing each line with a notecard that holds the UUID of the other line, The url can be asked to the other line by sending an email.
  2. inworld chat - flying towards both lines and instructing them what URL to use for communication with the other line.
  3. HUD method - variation on the chat method where a HUD takes care of the chat communication to inform the line of the URL to use
  4. email method - telling the URL of the other line to 1 line, thus allowing that line to send a HTTP request or email to the other line, which in turn povides the other line with its URL
  5. DNS method - using an external DNS service to register the lines
  6. other methods ...

It is possible that more than one method will have to be supported by a line. Since we cannot force builders to support all of these methods a choice will have to be made after the first experiences in the near future


Comment (YN): I think we need to unpack this a bit: there are only two "methods" to connect one line with the other - either using http or using email. What you (MD) describe here are various implementations of these communication methods, not the methods themselves. The protocol only needs to define the method(s) used to connect the lines and subsequently exchange data with - the details of the implementation of the spec are, to some extent, up to the builder. First and foremost, the protocol needs to define the precise message format used to

  • a) "discover" the other line and
  • b) to deliver the data that the other line needs to run the remote race.

However, I agree that the implementation of the protocol also needs to be discussed to some extent; for example: if you only allow the use of notecards for specifying the UUID or network handle, it would be harder for the general public to use the network feature (as it would be up to the object owner to maintain the connections). On the other hand, if we specify a common (non-zero) chat channel for use when starting a connection, the implementation would be much more flexible (there are also security concerns but that is a separate topic).


Connecting the lines (discovery)

  • Any line can act as either start/finish, start line with remote finish, or finish line with remote start.
  • Communication between separate lines occurs via http. (comment by MD: I deleted the email as an alternative. We have to make some choices if we want to move on. see the above comment for this)
  • Connection attempts always originate from the designated start line.
  • Upon request, the line establishes communication with another line by looking up its handle, then contacting it directly with the corresponding caps_url. If the contacted line is available for connection, it responds with an ACK message; if it is not, it responds with a BUSY message. (note: clarified the connection process. YN)
  • When a valid caps_url has been returned, the start line makes a connection request to the finish line using the following syntax in the body of the http request:
 942,                    connection request messagetype (start line requests connection to finish line)
 avatar ID,             the UUID key of the avatar operating the start line
  • (YN) The message is contained in the body of the http request sent by the start line. The first value acts like a header or email subject if you like (similar to how the protocol uses the email subject elsewhere to differentiate the message type). For convenience, it uses an integer constant which allows us to plug it right into the line's code. The only other value the start line should send at this point is the avatar UUID - it allows the remote line to IM the RD, telling them if the connection request succeeded or failed, and why. As discussed above, the http method always allows two-way communication; in fact, the object sending the http request expects a reply, which is where the http status code 200 below comes in.


  • If the finish line is ready for use, it responds with a status code of "200" and the following message body:
 ACK,                 connection request granted (MD: is this a string? YN: Y)
 line name,           line name (= object name)
 line location         line location ("region name, x,y,z coordinates")
  • (YN) Just like any web server, the object receiving the http request responds with a status code (200 = OK). The status code is not part of the message body - it's a separate field in the http response. The first value in the message body is "ACK"; this is a (text) string that the start line should test for. The line location value is a concatenation of the region name and x,y,z coordinates of the finish line. It's for informational purposes only, making it easier for the RD to ensure exactly what/where we have just connected to.


  • If the finish line is not available at this time, it responds with status code "200" and the following message body:
 BUSY,                 connection request denied
  • (YN) The BUSY message only needs to carry the "BUSY" message itself (we don't need to know the remote line's name or coords since we are not connecting anyway).


  • The start line should handle both cases appropriately.


  • (MD): when is it not available? when in use by another race? pending the last boat to finish? In that case there should be a remote reset message available
  • (YN): The correct handling of ACK and BUSY cases from the finish line's perspective is quite important: The finish line must check if it's currently in use as a "normal", i.e. start/finish line; if so, it should deny the connection request. Likewise if the finish line is already connected to a different start line - in short, a RD should not be able to accidentally disrupt races going on in different parts of the grid by issuing a connection request. To further secure against "hijacking", I have added something called "relay mode" to the start line: To connect two lines together, you must enable relay mode on both ends first - otherwise the lines will not respond to connection requests. This ensures that the RD wanting to run a networked race has been present at both ends of their course; they "know what's going on" on either end and they have made sure that neither line is currently in use before they try to connect them up. This encourages RDs to act responsibly and makes it impossible for them to try and connect distant lines together on the fly and just "see what happens". Remote reset messages are implemented - they are needed to sync up the two lines. See the data exchange section below.


Line Communications (data exchange)

  • Data exchange is the second part of the networking protocol. Once connected, the two lines exchange race data based on the role (start vs. finish) they play in the established connection.
  • The start line acts as the "clock master" during a networked session; that means it provides the finish line with the data it needs to stay synced up with the start line.
  • At the beginning of the start sequence, the start line sends a message to the finish line with the following details
RLYSTART,         (MD: lets make this some readable text like all the other messages in the protocol document)
start,            start time (unix epoch)
avatarID,         key of the avatar operating the start line
racelimit         maximum race time in seconds (each line will reset automatically 
                  after 'racelimit' has been reached; suggestion: 2 hours)
  • (YN): The first value is again an integer constant - it can be plugged directly into scripts, passed along internally using link messages etc. - the name her is just a placeholder; we'll need to settle what integer value to use.
  • The start line sends all valid starts to the finish line using the following format:
RMLAP,     
ownerName,          name of boat owner
startTimeRel,       start time (elapsed)
startTimeAbs,       start time (unix epoch)
boatKey             UUID key of the boat

This format is derived from the line crossing message used in previous start line versions which should ensure backwards compatibility.

  • The start line ignores any subsequent line crossings by starters; the finish line ignores all crossings but those of valid starts from the start line.
  • The start line sends a "remote reset" message to keep the finish line in sync after the race has concluded. Whenever the start line itself is reset, it sends a message to the finish line containing the message body
 RLYRESET,          issue remote reset command
 avatarID           key of the avatar operating the start line


  • (MD) Why pass the owner between the lines? Why not the helmsman and crew members?
  • (YN) The llVolumeDetect function can only deal with the prim it detects (and derive the owner); it can't tell you anything about the avatars sitting on it - but the wwc setter can :) So, to get more (and better) details on races, we'll be better off using the Race Manager.


  • (MD) What is startTimeRel?
  • (YN) It's simply the elapsed time within the race, i.e. startTimeRel = 4 » "onwerName starts at +00:00:04"


  • (MD) What happens if someone re-rezzes during the race? The boat gets a new key and should not be finished i think, but if the key of the owner is used instead this will go wrong)
  • (YN) Correct, if you crash, you'll get a new boat key and I agree you should not be counted as "finished" after that. Line builders should make sure the line crossings store and compare against the detected boat key, not the owner.
  • (CC) You are going the same (misleaded?) way that I did to get rid of the various race ID systems, that is using the owner UID. I ran into problems the very moment a couple of rented boats (all the same owner) came to the line. Similar problems with race situations like SFL where several people raced the same boat.
  • (YN) That's precisely my point and I have an almost identical corner case suggestion - training lessons with the trainee and trainer both using boats owned by the trainer. That's why I suggest using the boat key instead of the owner to compare against.

--CynthiaCentaur 07:33, 10 September 2009 (UTC) Yuu, think of a boat that crashes and is either gone or unusable afterwards. Common practice is to rezz a new boat and continue the race. The new boat will have a new UID so the line will not accept it. Though I don't like it much, going for the owner ID seems the best alternative unless we find a way (either by xxDetect, Sensor or boat to line communication) to detect the helmsman.

One idea for future boat designs:

  • A boat uses a given sailing ID if provided by a user
  • If no ID is given, a boat generates a short key from the helmsman's UID. Given a good algorithm is chosen it should be possible to drop the probability of doublets to a bearable level.

An algorithm like the above mentioned would result in boats with a (mostly) unique ID and would preserve the current ID system.

BUT: This will still not give us the name of the helmsman to show in results.


(MD: 16/9/2009) We could simply make the boat delete any key in its name upon rez and then add the full UUID key of the helmsman upon sitting down. But I don't know. Making the line system depend on whether or not the boats are updated to match the system is not a very good idea. I think it would be a lot better to use the race subscriptions for it and alternatively use the old #id method for compatibilty. If re-rezzing is so important, we need to make sure the new instance of the boat re-subscribes to the race no matter where it is. What if the boat would ask the other boats in the neighbourhood for the address of the WWC setter? This would fail if no other boats are there, but if that is the case, re-rezzing can not be seen by anyone and could be regarded as an act of cheating anyway.

Or alternatively, you could use a hud that stores the WWC id (a very ugly solution), have an umpire fly around wearing a hud that will repond to the "does anyone know the id of the WWC setter" message, have little objects in every sim that will inform boats of the nearest setter, or use a DNS service for it. The DNS could be created from the region name for instance and then looked up in an external table.


  • (MD) What happens with the valid finishes? Do they need to be send back to the startline?
  • (YN) The finish line tallies the results and provides them locally. I think that is natural since that is "where the action is" (and where the spectators will be as well, watching the finish).

Usability Considerations

  • Race lines with networked features should provide safeguards on both ends that ensure they cannot be triggered accidentally. Race Officers should not be able to use two lines in separate locations without ensuring both are available first.


Example for connecting racelines using a HUD

This sample code uses email as the communication method once the line know each other's UUID key. I (MD) think this has to be altered a little if you want to use HTTP as the protocol. If the lines only know each other's keys, they will have to send an email telling the other what URL to use. Or alternatively the HUD can pass the URL's instead of the UUID keys. This depends of course on the decision that is made concerning the communication method to use (email or http).

The HUD and the communication used here is a builder specific solution to the problem of identifying the lines and is not part of the protocol itself. It is a generous offer by Hay Ah to show how the communication could be set up.


when pressing the raceline it will start listening to commands from the dialogmenu if the network menu is chosen it will be presenting 2 important options: 'set start' and 'set finish' according to the button pressed the script will get into the correct mode

the line needs to listen to a dialogchannel

here is a little piece of the dialog listener code:

   listen(integer channel, string name, key id, string cmd){
       llListenRemove(handle);
       cmd = llToLower(cmd);
       
       if (cmd == "set start"){
           raceNumLaps = 1; default_raceNumLaps = 1;
           lineType = "S";
           // line mode
           llRegionSay(-9001, lineType +(string)operator);
           // send key ID of the line to the RD NETWORK HUD
           // operator is the key of the one who locked the line
           NW_S_mode = TRUE;
           NW_F_mode = FALSE;
           StartLine_Key = (key)llGetSubString(str, 1, -1);
           llSetTimerEvent(5);
           // turn on email recieving
       
       }else if (cmd == "set finish"){
           raceNumLaps = 1; default_raceNumLaps = 1;
           lineType = "F";
           // line mode
           llRegionSay(-9001, lineType +(string)operator);
           // send key ID of the line to the RD NETWORK HUD
           // operator is the key of the one who locked the line
           NW_F_mode = TRUE;
           NW_S_mode = FALSE;
           FinishLine_Key = (key)llGetSubString(str, 1, -1);
           llSetTimerEvent(5);
           // turn on email recieving
           
       }else if (cmd == "give hud"){
           llGiveInventory(me_clicks ,giveName());
           
       }
   }
           
   timer() {
       llGetNextEmail("", "");
   }

Nothing has been synced or started on this point... only that both lines will listen to email.

When the RD HUD is weared while making choices on the start and finish it will recieve both keys and send the finishline key to the startline. The HUD uses a listener on channel -9001 This will look as follows:

   listen( integer channel, string name, key id, string message ) {
       identify = llGetSubString( message, 0, 0);
       key sender_key = llGetSubString( message, 1, -1);
       
       if(llGetOwner() == sender_key){
           if (identify == "S"){
               StartSim = llGetRegionName();
               SKey = id;
               // Skey will be the startline Key
               if(FKey != NULL_KEY){
                   llRegionSay(9000, "6"+ (string)FKey);
               // if finishlinekey is present, then regionsay Fkey to startline
               // !!!!  the raceline need a listener on channel 9000 to recieve this !!!!
               }
               llOwnerSay("Recieving Startline Key");
               }
               
           }else if(identify == "F"){
               FinishSim = llGetRegionName();
               FKey = id;
               //Fkey will be the finishline key
               if(SKey != NULL_KEY){
               // if startline is present, then mail Fkey to startlijn
                   data = "FKey,"+ (string)FKey;
                   llMessageLinked(Mailer, (++Counter % 10), data, SKey);
               // use email handler
               }
               llOwnerSay("Recieving Finishline Key");
               }
               
           }else if(identify == "G"){
               llOwnerSay("The finishline has been synced");
           }
       }


At this point the startline has the finishline key and is ready to transmit data anytime when the startbutton is pressed. So when the startline is started it will send the starting time to the finishline.

       zero_time =  llGetUnixTime() + pre_start;
       // pre_start is the default time before the race starts
       if(NW_S_mode){
           string settings = "sync,"+ (string)zero_time +","+ (string)StartLine_Key;
           llMessageLinked(MailNum, (++Counter % 15), settings, FinishLine_Key);
       // use email handler
       }

next is a piece of the code for email recieving

   email( string time, string address, string subj, string message, integer numQueued ){
       llSetTimerEvent(0);
       message = llDeleteSubString(message, 0, llSubStringIndex(message, "\n\n") + 1);
           
       if(subj == "sync"){
       // --> synchronize the timer of the finishline
       // insert a function here to reset all line defaults
           integer str_index = llSubStringIndex(message,",");
           zero_time     = (integer)llDeleteSubString(message, str_index, -1);
       // sync to the current time
           StartLine_Key = (key)llDeleteSubString(message, 0, str_index);
       // startlijn is also know by finishline by now
           llRegionSay(9000, "0"+ lineType +(string)zero_time);
       // start the display timer 
           string settings = "good, yes :)";
           llMessageLinked(MailNum, (++Counter % 15), settings, StartLine_Key); // message to startlijn that sync is succesfull
               
       }else if (subj == "data"){
       // --> data of racers: name & time
           string ownerName = llDeleteSubString(message, llSubStringIndex(message,","), -1);
           integer crossTime = (integer)llDeleteSubString(message, 0, llSubStringIndex(message,","));
           addRacer(ownerName, crossTime);
           
       }else if (subj == "good"){
       // -->synced confirmation
           llRegionSay((Chan-1), "G");
       // message from finishlijn to the HUD, so the Hud can ownersay
       
       }else if (subj == "FKey"){
           FinishLine_Key = message;
           
       }
       if (numQueued > 0) llGetNextEmail("", ""); 
       else llSetTimerEvent(Interval);
   }

Every script uses a email handler... it's nothing more then a linked prim, wich contains (in my case) 15 same email scripts).

This is the script (thanks to Bittersweet Lime)

  // this goes into the root prim
  // the basic name of the script should NOT include spaces.
  // Parameters:
  // num = ScriptNr
  // message = semicolon separated list for stuff
  
  integer scriptNr;
  
  default{
      state_entry(){
          string s = llGetScriptName();
          integer i = llSubStringIndex(s," ");
          if (i==-1) scriptNr = 0; else scriptNr = (integer) llDeleteSubString(s,0,i);
      }
  
      on_rez(integer what){
          llResetScript();
      }
      
      link_message(integer sender,integer num,string message,key id){
          if (num == scriptNr){
              string subject = llDeleteSubString(message, llSubStringIndex(message,","), -1);
              string body = llDeleteSubString(message, 0, llSubStringIndex(message,","));
              llEmail( (string)id + "@lsl.secondlife.com", subject, body );
          }
      }
  }

For questions about this Network HUD method and integration into an existing line, you can always IM me inworld (or drop a notecard if i don't answer after the first IM)

Kind regards Hay Ah

Communication between startline and finishline

(Note by MD: If everyone agrees to the alternative section i wrote which can be found above this, we can remove this part)

  • Race lines can be networked to create a course with a separate start and finish line.
  • Currently two methods of approach are used:
  1. HTTP or email method - using either http or email to connect the lines directly
  2. HUD method - using a inworld hud to get a key


HTTP/email method

  • Any line can act as either start/finish, start line with remote finish, or finish line with remote start.
  • Communication between separate lines occurs via http or email. The difference between the two methods lies in the discovery method; the communication protocol (data exchange) between the lines stays the same.
  • Communications (data exchange) between start and finish lines are identical to internal communications in the normal start/finish mode. The format is also identical to and thus backward compatible with the format of previous start lines.
  • The two discovery methods described here are simpler, faster and more robust than the HUD-based method described below:
    • there is no need to use a third object to connect two objects in SL and the protocol should not require it.
    • the http method is instantaneous and eliminates the need for dozens of email slave scripts; caveat: it requires the use of third-party services for caps_url discovery at this time.
    • the email method is just as simple and uses the same data exchange protocol as the http method; it can thus serve as a fallback method.
    • to start a networked race, only one network handle or key is required (the handle/key of the finish line)
    • the start lines always communicate directly with each other
  • From the user perspective, the only difference between the http and email methods described here is the use of an easy-to-remember network handle ("connect Boogdolt") vs. the use of a UUID key ("connect xxxx-xxx-xxx-xxxx").
  • Comment by Yuu: A protocol sets out to describe a set of 'requirements' (as opposed to features) for purposes of interoperability. In this instance, the protocol attempts to describe the requirements for connecting and sharing data between two objects. No third-party objects are required for this operation. If you want to use a HUD for the connection between two objects in SL even though you could do the same by connecting them directly, you are free to do so - but the protocol should not bind you to it.


Discovery using http

  • Each line provides a handle with an easily-accesible command (in chat or using a menu) that can be used to look up a corresponding caps_url.
  • A line establishes communication with another line by looking up its handle, then contacting it directly with the corresponding caps_url. If the contacted line is available for connection, it responds with an ACK message; if it is not, it responds with a BUSY message.
  • A race line's handle should be easily discoverable. Currently, a variety of third-part services exist that provide this functionality.
  • Connection attempts originate from the designated start line. Upon request, the start line looks up the caps_url that corresponds to the finish line's network handle.
  • When a valid caps_url has been returned, the start line makes a connection request to the finish line using the following syntax:
 MSG_DNSREQ,          connection request messagetype (start line requests connection to finish line)
 queryID              the UUID key of the avatar operating the start line
  • When the designated finish line receives the connection request, it tests itself for availability. If the line is available for use as a finish line in this context, it replies with the following message:
 200,                 status code 200
 ACK,                 connection request granted
 line name,           line name (= object name)
 line location        line location (region name, x,y,z coordinate)
  • If the finish line is not available for use at this time, it replies with
 200,                 status code 200
 BUSY                 connection request denied
  • The start line should handle both cases appropriately.

Discovery using email

  • Each line provides its object UUID with a readily-accessible command (in chat or using a menu).
  • All connection attempts originate from the designated start line. The designated finish line's UUID key can either be provided to the start line using a settings notecard or in local chat.
  • Just like in the case of http discovery, the finish line should either accept or deny the connection request. If the line is available for use, it switches to finish line mode and sends a confirmation message to the avatar making the connection attempt. The finish line is now ready to receive emails from the start line.
  • If the finish line is not available, it replies with a "busy message" and remains in its current state.

Just to spice up things a bit: This is how I did it with my prototype last year --CynthiaCentaur 06:34, 10 September 2009 (UTC)

Discovery using a broker

  • A third party object exists that is used as a broker (UUID known and guaranteed to be long term stable). In the ideal case, this broker exists once in SL which would allow each line talk to each other line. But given human nature I think that quite some broker objects would exist, forming separate "clouds".
  • Each line registers at the broker with a URN that is unique by design but that reflects it's nature (e.g. "urn:slsa.raceline.madaket1"). (Re-)Registering is done on a regular time scale to renew the entry, otherwise it will decease thus signalling the un-availability of a resource. Registering can also be done at any time, e.g. after onRezz. This allows lines to be replaced by newer versions or rezzed on demand (like in areas where a reasonable autoreturn is enabled, think of "line-on-demand").
  • The communication to this broker can either be done via email or via HTTP, who cares at this moment. I used email due to the lack of a better protocol one year ago.
  • Each line (and also each other object) can query the UUID of it's partner from the broker by knowing the URN. Note to the reader: URNs can be designed in a way they can be constructed from partial knowledge, that is, if a line knows it wants to talk to another line it already knows the URN must have the form urn:slsa.raceline.<name of the line>. Thus a user only needs to supply the name of the line.

Remark (CC): after having written this I re-read Yuu's part. I think it seems quite similar in the basic idea.

Comment (YN): Yup, these two approaches are pretty much one and the same; except there's no need to mimic a web service any more - now you're actually using one. Did you also have a data exchange part?

Comment (--CynthiaCentaur 06:04, 21 September 2009 (UTC)): With data exchange I assume you meant the line to line communication. Yes, it was done, based on email. As my line was not monolithic but built on a set of scripts it was fairly easy to just forward some of the internal messages. Worked fine. On the other hand it was messy, not modular and bound to internal details like hell. That's one reason why it never saw the light of the public. I always wanted to restructure it and lacked the time.

Line Communications (data exchange)

  • Data exchange is the second part of the networking protocol. Once connected, the two lines exchange race data based on the role (start vs. finish) they play in the established connection.
  • At the beginning of the start sequence, the start line sends a message to the finish line with the following details
MSG_RLYSTART,
start,                start time (unix epoch)
queryID,              key of the avatar operating the start line
racelimit             maximum race time in seconds (each line will reset automatically 
                      after 'racelimit' has been reached; suggestion: 2 hours)
 
  • The start line sends all valid starts to the finish line using the following format:
MSG_RMLAP,     
ownerName,          name of boat owner
startTimeRel,       start time (elapsed)
startTimeAbs,       start time (unix epoch)
boatKey             boat key

This format is derived from the line crossing message used in previous start line versions which should ensure backwards compatibility.

  • The start line ignores any subsequent line crossings by starters; the finish line ignores all crossings but those of valid starts from the start line.

Usability Considerations

  • Race lines with networked features should provide safeguards on both ends that ensure they cannot be triggered accidentally. Race Officers should not be able to use two lines in separate locations without ensuring both are available first.
  • The start/finish line must be able to maintain its caps_url handle to ensure discoverability.

- HUD method


  • Any line can act as either start or finish.
  • Instead of relying on an external service the HUD method relies on an inworld hud.
  • The hud is always usable where an external service can always collapse. (when the person is not active in sl anymore for instance)
  • The HUD should be provided by the raceline itself and it can be used to obtain the keys of both lines.


Networked Raceline Protocol Explained:

when pressing the raceline it will start listening to commands from the dialogmenu if the network menu is choosen it will be presenting 2 important options: 'set start' and 'set finish' according to the button pressed the script will get into the correct mode

the line needs to listen to a dialogchannel

here is a little piece of the dialog listener code:

   listen(integer channel, string name, key id, string cmd){
       llListenRemove(handle);
       cmd = llToLower(cmd);
       
       if (cmd == "set start"){
           raceNumLaps = 1; default_raceNumLaps = 1;
           lineType = "S";
           // line mode
           llRegionSay(-9001, lineType +(string)operator);
           // send key ID of the line to the RD NETWORK HUD
           // operator is the key of the one who locked the line
           NW_S_mode = TRUE;
           NW_F_mode = FALSE;
           StartLine_Key = (key)llGetSubString(str, 1, -1);
           llSetTimerEvent(5);
           // turn on email recieving
       
       }else if (cmd == "set finish"){
           raceNumLaps = 1; default_raceNumLaps = 1;
           lineType = "F";
           // line mode
           llRegionSay(-9001, lineType +(string)operator);
           // send key ID of the line to the RD NETWORK HUD
           // operator is the key of the one who locked the line
           NW_F_mode = TRUE;
           NW_S_mode = FALSE;
           FinishLine_Key = (key)llGetSubString(str, 1, -1);
           llSetTimerEvent(5);
           // turn on email recieving
           
       }else if (cmd == "give hud"){
           llGiveInventory(me_clicks ,giveName());
           
       }
   }
           
   timer() {
       llGetNextEmail("", "");
   }

Nothing has been synced or started on this point... only that both lines will listen to email.

When the RD HUD is weared while making choices on the start and finish it will recieve both keys and send the finishline key to the startline. The HUD uses a listener on channel -9001 This will look as follows:

   listen( integer channel, string name, key id, string message ) {
       identify = llGetSubString( message, 0, 0);
       key sender_key = llGetSubString( message, 1, -1);
       
       if(llGetOwner() == sender_key){
           if (identify == "S"){
               StartSim = llGetRegionName();
               SKey = id;
               // Skey will be the startline Key
               if(FKey != NULL_KEY){
                   llRegionSay(9000, "6"+ (string)FKey);
               // if finishlinekey is present, then regionsay Fkey to startline
               // !!!!  the raceline need a listener on channel 9000 to recieve this !!!!
               }
               llOwnerSay("Recieving Startline Key");
               }
               
           }else if(identify == "F"){
               FinishSim = llGetRegionName();
               FKey = id;
               //Fkey will be the finishline key
               if(SKey != NULL_KEY){
               // if startline is present, then mail Fkey to startlijn
                   data = "FKey,"+ (string)FKey;
                   llMessageLinked(Mailer, (++Counter % 10), data, SKey);
               // use email handler
               }
               llOwnerSay("Recieving Finishline Key");
               }
               
           }else if(identify == "G"){
               llOwnerSay("The finishline has been synced");
           }
       }


At this point the startline has the finishline key and is ready to transmit data anytime when the startbutton is pressed. So when the startline is started it will send the starting time to the finishline.

       zero_time =  llGetUnixTime() + pre_start;
       // pre_start is the default time before the race starts
       if(NW_S_mode){
           string settings = "sync,"+ (string)zero_time +","+ (string)StartLine_Key;
           llMessageLinked(MailNum, (++Counter % 15), settings, FinishLine_Key);
       // use email handler
       }

next is a piece of the code for email recieving

   email( string time, string address, string subj, string message, integer numQueued ){
       llSetTimerEvent(0);
       message = llDeleteSubString(message, 0, llSubStringIndex(message, "\n\n") + 1);
           
       if(subj == "sync"){
       // --> synchronize the timer of the finishline
       // insert a function here to reset all line defaults
           integer str_index = llSubStringIndex(message,",");
           zero_time     = (integer)llDeleteSubString(message, str_index, -1);
       // sync to the current time
           StartLine_Key = (key)llDeleteSubString(message, 0, str_index);
       // startlijn is also know by finishline by now
           llRegionSay(9000, "0"+ lineType +(string)zero_time);
       // start the display timer 
           string settings = "good, yes :)";
           llMessageLinked(MailNum, (++Counter % 15), settings, StartLine_Key); // message to startlijn that sync is succesfull
               
       }else if (subj == "data"){
       // --> data of racers: name & time
           string ownerName = llDeleteSubString(message, llSubStringIndex(message,","), -1);
           integer crossTime = (integer)llDeleteSubString(message, 0, llSubStringIndex(message,","));
           addRacer(ownerName, crossTime);
           
       }else if (subj == "good"){
       // -->synced confirmation
           llRegionSay((Chan-1), "G");
       // message from finishlijn to the HUD, so the Hud can ownersay
       
       }else if (subj == "FKey"){
           FinishLine_Key = message;
           
       }
       if (numQueued > 0) llGetNextEmail("", ""); 
       else llSetTimerEvent(Interval);
   }

Every script uses a email handler... it's nothing more then a linked prim, wich contains (in my case) 15 same email scripts).

This is the script (thanks to Bittersweet Lime)

  // this goes into the root prim
  // the basic name of the script should NOT include spaces.
  // Parameters:
  // num = ScriptNr
  // message = semicolon separated list for stuff
  
  integer scriptNr;
  
  default{
      state_entry(){
          string s = llGetScriptName();
          integer i = llSubStringIndex(s," ");
          if (i==-1) scriptNr = 0; else scriptNr = (integer) llDeleteSubString(s,0,i);
      }
  
      on_rez(integer what){
          llResetScript();
      }
      
      link_message(integer sender,integer num,string message,key id){
          if (num == scriptNr){
              string subject = llDeleteSubString(message, llSubStringIndex(message,","), -1);
              string body = llDeleteSubString(message, 0, llSubStringIndex(message,","));
              llEmail( (string)id + "@lsl.secondlife.com", subject, body );
          }
      }
  }

For questions about this Network HUD method and integration into an existing line, you can always IM me inworld (or drop a notecard if i don't answer after the first IM)

Kind regards Hay Ah

Communication between boats

  • This part of the protocol is optional. Implementation however is very easy when using the standard WWC Interpreter and WWC Receiver scripts.

Two boats that are near each other will have an effect on each other. For instance:

  • A boat can block the other boat's wind.
  • If a boat sails closely behind the other, the air flow is disturbed and turbulent.
  • One of the boats has Right of Way (ROW); the other does not

A boat should transmit its position and heading at regular intervals. This is done on channel -7001 for cruising boats and -8001 for racing boats by using llSay() or llShout() / llRegionSay() (for bigger boats). The different channels for cruising and racing ensure that cruisers will not interfere with races and vice versa. Also, race wind and cruise wind can have different values, and strange things would occur with two boats shadowing each other while their wind is coming from opposite directions.

The message format is:

 message type, (value = "BtPos")
 x coordinate (global x coordinate),
 y coordinate (global y coordinate),
 sail area (sail area in m^2),
 tack the boat is sailing on (P = port tack so the sail is to starboard, S = starboard tack with the sail to port),
 boat size from root prim to bow (in meters used to determine side by side situations for ROW computation),
 boat size from root prim to stern (in meters used to determine side by side situations for ROW computation),
 speed in x direction (in m/s, including any tidal current),
 speed in y direction (in m/s, including any tidal current)

The speed values can be used to interpolate the boat's position in between broadcasts. The tack, heading and boat size values can be used to establish simple ROW indications. (leeward boat and port/starboard rules)

Boats that have their sails flapping in the wind do not create a shadow and should not broadcast anything until the sheet is pulled.

Example:

   if(relativeWindDir!=0.0 && ((llFabs(relativeWindDir)-sheetAngle)/llFabs(relativeWindDir))>0.2) {
     vector pos = llGetPos()+llGetRegionCorner();
     string tack = "S";
     integer sailArea = 25;
     if(gennakerRaised) sailArea+=20;
     if(relativeWindDir<0) tack = "P";
     llSay(-7001,(string)((integer)pos.x)+","+
       (string)((integer)pos.y)+","+
       (string)sailArea+","+
       tack+
       ",1.8,2.5,"+   // these are always fixed values
       llGetSubstring((string)(llGetVel().x),0,2)+","+   // llGetSubstring is used to shorten the message
       llGetSubstring((string)(llGetVel().y),0,2)
     );
   }


  • A short broadcast interval could lead to avoidable sim lag. Builders are advised to reduce this interval to 3 seconds or more.
  • Don't use llShout() or llRegionSay() unless you have a big boat that will rarely be sailed in races with 10+ boats.
  • If the broadcast interval is bigger than the interval of the internal clock of the boat, received wind shadow broadcasts will need to be stored per transmitting boat to prevent the next cycle from pushing the boat forward with 0 shadow again.

Communication between boat and buoys

Each mark should broadcast its position to all boats in the neighbourhood using llShout on channel -8001 every 3 seconds. This way, boats that are competing in a race can use this information together with their own position and the positions of the other boats to implement ROW indication within the 2 shiplengths zone.

The message format is:

 message type     value = "Buoy"
 x coordinate     global x coordinate of buoy
 y coordinate     global y coordinate of buoy
 buoy name

Mooring protocol

This protocol describes how a boat might dock to a mooring buoy or similar device. (To be defined.)

Protocol version

Personal tools