Database Teleporter BRIGADOON-0009
An Open Simulator Teleporter using a central database.
Loading...
Searching...
No Matches
teleport_heartbeat.osl
Go to the documentation of this file.
1
16
17 string VERSION_STRING = "1.3.0";
18
28
39
46string CONFIG_NOTECARD_NAME = "brigadoon_teleporter.config";
47
56string CONFIG_DESTINATIONS_NAME = "teleport_destinations.config";
57
64string COMMENT_PREAMBLE = "//";
65
72
77string DATABASE_INTERFACE = "DATABASE_INTERFACE";
78
83string LOCATION_NAME = "LOCATION_NAME";
84
89string LANDING_OFFSET = "LANDING_OFFSET";
90
95string HEARTBEAT_PERIOD = "HEARTBEAT_PERIOD";
96
101string FRONT_OFFSET_ANGLE = "FRONT_OFFSET_ANGLE";
102
107string LOCATION_TYPE = "LOCATION_TYPE";
108
116string GROUP_LOCATION = "GROUP";
117
122string ANONYMOUS_UNIT = "ANONYMOUS";
123
131string REGION_LOCATION = "REGION";
132
140string WORLD_LOCATION = "WORLD";
141
149string METAVERSE_LOCATION = "METAVERSE";
150
155integer GROUP_FLAG = 1;
156
161integer REGION_FLAG = 2;
162
167integer WORLD_FLAG = 4;
168
173integer METAVERSE_FLAG = 8;
174
182
193integer ANONYMOUS_FLAG = 16;
194
199string LOCALITY_GROUP = "LOCALITY_GROUP";
200
205float TIMER_OFF = 0.0;
206
214
219float MINIMUM_OFFSET = 0.5;
220
225float MAXIMUM_OFFSET = 10.0;
226
239
248
249string locality_group = "null";
250
257
263
269
275
284
290
297
304
310integer location_info = 0;
311
322
329 "// Filename: teleport_destinations.config",
330 "// Version: " + VERSION_STRING,
331 "// Date: " + llGetDate() + " UTC",
332 "// Author: River Drifter",
333 "// Email: river-drifter@aussiebroadband.com.au",
334 "// Licence: Creative Commons Attribution Share Alike 4.0 International or better",
335 "//",
336 "// *NOTE*: This file is periodically recreated by the Teleporter Heartbeat script.",
337 "// All entries place here manually will be lost when the file is recreated. If you",
338 "// wish do testing with manual entries, disable the heartbeat script for the duration.",
339 "//=========================================================="
340 ];
341
350rdProcessFailureMessage(string FailureMessage)
351{
352 string failure_message;
353
354 list status = llParseString2List(FailureMessage, [":"], ["\n"]);
355 string failure_type = llList2String(status, 0);
356
357 // Explain why the Teleporter could not be automatically processed
358 if (failure_type == "BANNED")
359 {
360 failure_message = "Teleporters owned by user " + llList2String(status, 1) + " are not permitted to";
361 failure_message += " add teleporters to the database, update teleporter information or update teleporter destinations.";
362 }
363
364 // Explain that the Updating of the Datasbase using the Heartbeat message has failed.
365 else if (failure_type == "UPDATE")
366 {
367 failure_message = "The updating of the Teleporter's information in the database has unexpectedly failure with the error message: ";
368 failure_message += llList2String(status, 1);
369 }
370
371 // Explain that the Insertion into the Database using the Heartbeat message has failed
372 else if (failure_type == "INSERT")
373 {
374 failure_message = "The insertion of a new teleporter's information into the database has failed unexpectedly with the error message: ";
375 failure_message += llList2String(status, 1);
376 }
377
378 // Explain that the Insertion/update failed because the Teleporter name was already in use and duplicate names are not allowed.
379 else if (failure_type == "NAME_MATCH")
380 {
381 failure_message = "Unable to insert the new teleporter's information into the database because the Teleporter's Name is already in use ";
382 failure_message += "by another teleporter located at " + llList2String(status, 1);
383 }
384
385 // Explain that a failure in extracting the destination list for this Teleporter
386 else if (failure_type == "EXTRACT")
387 {
388 failure_message = "The extraction of the list of teleporter destinations has failed unexpectedly with the error message: ";
389 failure_message += llList2String(status, 1);
390 }
391
392 // Explain that Teleporters from world's outside of this one cannot be added automatically added.
393 else if (failure_type == "INVADER")
394 {
395 failure_message = "Teleports from home world '" + llList2String(status, 1) + "' are not permitted to ";
396 failure_message += " add teleporters to the database, update teleporter information or update teleporter destinations.";
397 }
398
399 // Tell the person what to do if there was an error.
400 failure_message += "\n If you wish to report this as an error please send this message to River Drifter with details of what happened and when.\n";
401 llSay(0, failure_message);
402}
403
409integer rdSetAnonType(string ValueObject, integer InfoInteger)
410{
411 if (llToUpper(ValueObject) == "YES") InfoInteger |= ANONYMOUS_FLAG; else InfoInteger &= ~ANONYMOUS_FLAG;
412
413 return InfoInteger;
414}
415
423integer rdGetVersionNumber(string VersionString)
424{
425 integer version;
426
427 list versions = llParseString2List(VersionString, ["."], []);
428 version = (integer)llList2String(versions,2) + ((integer)llList2String(versions,1) * 100) + ((integer)llList2String(versions,0) * 10000);
429
430 return version;
431}
432
441integer rdSetLocationType(string ValueString, integer LocationInfo)
442{
443 integer location_buffer = 0;
444
445 // Cut the Location Types out of the Location Info
446 LocationInfo &= LOCATION_MASK;
447
448 // Break the Value String into Components
449 list type_component = llParseString2List(ValueString, [","], []);
450 integer list_size = llGetListLength(type_component);
451 integer index = 0;
452
453 // Process each LocationType
454 for (; index < list_size; ++index)
455 {
456 string location_type = llStringTrim(llList2String(type_component, index), STRING_TRIM);
457 if (location_type == GROUP_LOCATION) location_buffer += GROUP_FLAG;
458 else if (location_type == REGION_LOCATION) location_buffer += REGION_FLAG;
459 else if (location_type == WORLD_LOCATION) location_buffer += WORLD_FLAG;
460 else if (location_type == METAVERSE_LOCATION) location_buffer += METAVERSE_FLAG;
461 }
462
463 // Put intp the Location Information
464 LocationInfo |= location_buffer;
465
466 return LocationInfo;
467}
468
469string rdAdjustPosition(string Line)
470{
471 string world;
472 string region;
473 string output_line;
474 vector landing;
475 vector look_at;
476
477 // Split the Entry into components
478 list components = llParseString2List(Line, ["|"], []);
479
480 string name = components[0];
481 vector init_pos = (vector)components[1];
482 rotation initial_rot = (rotation)components[2];
483 vector offset_info = (vector)components[3];
484 string location_group = components[4];
485 integer address_type = (integer)components[5];
486
487 if (address_type == 2)
488 {
489 region = components[6];
490 world = components[7];
491 }
492 else if (address_type == 1)
493 {
494 region = components[6];
495 world = location_world;
496 }
497 else if (address_type == 0)
498 {
499 region = location_region;
500 world = location_world;
501 }
502 else
503 {
504 llSay(DEBUG_CHANNEL, "Format Error");
505 }
506
507 // Because of the Inherent lilmit of eight(8) elements when parsing a string
508 // three (3) of teh numeric items were condensed into a vector to overcome this
509 // problem.
510 float offset_distance = (float)offset_info.x;
511 float look_angle = (float)offset_info.y;
512 integer location_information = (integer)offset_info.z;
513
514 // Determine the Landing Position by adding offset to the Teleporter's Location
515 // The offset is set negative to move to it "back to the front" of the Teleporter Object
516 landing = init_pos + llRot2Fwd(initial_rot) * -offset_distance;
517
518 vector temp = llRot2Euler(initial_rot * llAxisAngle2Rot(<0,0,1>, look_angle));
519 look_at = <llCos(temp.z), llSin(temp.z), 0.0>;
520
521 // Create the String to be stored in the Teleport Destination Notecard.
522
523 output_line = name + "|" + world + "|" + region + "|";
524 output_line += (string)landing + '|' + (string)look_at + '|';
525 output_line += (string)location_information + '|';
526 output_line += location_group + "\n";
527
528 return output_line;
529}
530
540{
541 // Add the Preamble Text before the List of Destinations
543
544 // Delete the Existing Teleporter Destination Notecard, if it exists
545 integer count = llGetInventoryNumber(INVENTORY_NOTECARD);
546 integer index = 0;
547 for (; index < count; ++index)
548 {
549 if (llGetInventoryName(INVENTORY_NOTECARD, index) == CONFIG_DESTINATIONS_NAME)
550 {
551 llRemoveInventory(CONFIG_DESTINATIONS_NAME);
552 index = count; // Ext Loop
553 }
554 }
555
556 // Write the Teleport List to a New Notecard
558}
559
574{
575 // Do a cursory Check that the configuration has been set up
576 if ((location_name != "") && (database_interface != ""))
577 {
578 // Reset the Data received for the Database
579 teleport_list = [];
580 integer teleport_list_started = FALSE;
581
582 key teleporter_key = llGetKey();
583 list details = llGetObjectDetails(teleporter_key, [OBJECT_POS, OBJECT_ROT, OBJECT_OWNER, OBJECT_GROUP]);
584
585 string heartbeat_message = database_interface + "?command=heartbeat"
586 + "&name=" + llEscapeURL(location_name)
587 + "&key=" + teleporter_key
588 + "&position=" + osReplaceString(llList2String(details, 0), " ", "", -1, 0)
589 + "&rotation=" + osReplaceString(llList2String(details, 1), " ", "", -1, 0)
590 + "&owner=" + llList2String(details, 2)
591 + "&group=" + llList2String(details, 3)
592 + "&world=" + location_world
593 + "&region=" + llGetRegionName()
594 + "&offset=" + (string)landing_offset
595 + "&offsetangle=" + (string)front_offset_angle
596 + "&locationinfo=" + (string)location_info
597 + "&vernum=" + (string)version_number
598 + "&localitygroup=" + locality_group;
599 heartbeat_key = llHTTPRequest(heartbeat_message, [HTTP_BODY_MAXLENGTH,16384], [""]);
600 }
601 else
602 {
603 llSay(DEBUG_CHANNEL, "Either the location_name or database_interface are undefined! Teleporter " + location_name + " has been disabled");
604 llSetScriptState(llGetScriptName(), FALSE);
605 }
606}
607
612default
613{
620 state_entry()
621 {
622
623 location_world = llGetSubString(osGetGridHomeURI(), 7, -1);
624 location_region = llGetRegionName();
626
627 // Read the Configuration File into a List of Lines
628 string config = osGetNotecard(CONFIG_NOTECARD_NAME);
629 list config_data = llParseString2List(config, ["\n"], []);
630
631 // Process each line in the Configuration Data
632 integer index = 0;
633 integer list_length = llGetListLength(config_data);
634 for (; index < list_length; ++index)
635 {
636 // Trim line of Leading and Trailing Spaces
637 string trimmed_line = llStringTrim(llList2String(config_data, index), STRING_TRIM);
638
639 // Only Process lines that are not a comment line or blank
640 if ( (llGetSubString(trimmed_line, 0, COMMENT_PREAMBLE_LENGTH - 1) != COMMENT_PREAMBLE) && (trimmed_line != "") )
641 {
642 // Parse Line for a Configuration Field.
643 list key_value = llParseString2List(trimmed_line, ["="], []);
644
645 // Fold the Trimmed Key into upper case, to eliminate errors where the case is wrong in the config file.
646 string key_object = llToUpper(llStringTrim(llList2String(key_value, 0), STRING_TRIM));
647
648 // Trim the Value to remove leading and training spaces
649 string value_object = llStringTrim(llList2String(key_value, 1), STRING_TRIM);
650
651 // Process the Key-Value Pairs to Set Configuration
652 if (key_object == DATABASE_INTERFACE) database_interface = value_object;
653 else if (key_object == LOCATION_NAME) location_name = value_object;
654 else if (key_object == LANDING_OFFSET) landing_offset = (float)value_object;
655 else if (key_object == HEARTBEAT_PERIOD) heartbeat_period = (float)value_object * 3600.0; // Convert hours to seconds
656 else if (key_object == FRONT_OFFSET_ANGLE) front_offset_angle = (float)value_object;
657 else if (key_object == LOCATION_TYPE) location_info = rdSetLocationType(llToUpper(value_object), location_info);
658 else if (key_object == LOCALITY_GROUP) locality_group = llEscapeURL(value_object);
659 else if (key_object == ANONYMOUS_UNIT) location_info = rdSetAnonType(value_object, location_info);
660 }
661
662 // Check that the Heartbeat Period is equal to or greater than the Minimum
664
665 // Check the Landing Offset values against limits
667 }
668
669 // Send out an Initial Heartbeat Message
671
672 // Start the Heatbeat Timer, but first check that the heartbeat period would no result in flooding of the database.
674 llSetTimerEvent(heartbeat_period);
675 }
676
691 http_response(key RequestId, integer Status, list Metadata, string Body)
692 {
693 list teleport_list;
694
695 // Only respond to the Heartbeat Request
696 if (RequestId == heartbeat_key)
697 {
698 // Check to see if the Reuest was a Success
699 if (Status != 200)
700 {
701 llSay(DEBUG_CHANNEL, "Heartbeat Request Failed with error " + (string)Status);
702 }
703 else
704 {
705 // Split into a list for easier processing
706 list input_list = llParseString2List(Body, ["\n"], []);
707
708 // Step thought the list a line at a time
709 integer index = 0;
710 integer input_list_started = FALSE;
711 integer list_count = llGetListLength(input_list);
712
713 string line;
714 do
715 {
716 // Extract the Line
717 line = llList2String(input_list, index);
718
719 // Start the Teleport Notecard
720 if (line == "EXTRACT_LIST=START") input_list_started = TRUE;
721
722 // End if you find the END FLAG by setting index to the end
723 else if (line == "EXTRACT_LIST=END")
724 {
725 index = list_count;
726 input_list_started = FALSE;
727 }
728
729 // Extract the Data Line & Process
730 else if (input_list_started == TRUE)
731 {
732 string updated_line = rdAdjustPosition(line);
733 teleport_list += updated_line;
734 }
735
736 // Check if this is a status message
737 else
738 {
739 list status_list = llParseString2List(line, ["="], []);
740 if (llList2String(status_list, 0) == "FAILURE") rdProcessFailureMessage(llList2String(status_list, 1));
741 }
742
743 // Add Destination to the Teleport Notecard
744 }
745 while ( ++index < list_count);
746
747 // Replace the old Teleport Notecard with New One
749 }
750 }
751 }
752
758 timer()
759 {
761 }
762}
integer REGION_FLAG
Number value of REgion Location flag.
integer COMMENT_PREAMBLE_LENGTH
THe number of characters in the comment preamble.
string CONFIG_DESTINATIONS_NAME
The automatically generated list of teleporter destinations.
string location_name
The display name of the current location.
string CONFIG_NOTECARD_NAME
The name of the notecard containing the Teleport's Configuration.
string LOCATION_NAME
THe Key Value for defining hte name of the location in the Config notecard.
float TIMER_OFF
Settings a Zero Time will turn off the Timer.
integer METAVERSE_FLAG
Number value of Metaverse Location flag.
string location_region
Region holding the Teleporter.
string VERSION_STRING
The Current version of the software.
integer WORLD_FLAG
Number value of World Location flag.
string COMMENT_PREAMBLE
Preamble for a comment line in the configuration file.
string location_world
The Teleporter Location's World.
string database_interface
The HTTP address for invoking the php script to do the scanning & deleting.
string DATABASE_INTERFACE
The Identifier for the Database Interface URL.
string WORLD_LOCATION
The Configuration File Identifier for the World Location.
float DEFAULT_LOCATION_OFFSET
The default offset from the landing teleport position when using a display panel;.
rdSendHeartbeatMessage()
list destination_data
A list of the Teleport Destinations from the COnfiguration File.
float front_offset_angle
The LookAt angle after teleportation.
integer rdSetLocationType(string ValueString, integer LocationInfo)
Set the teleporter Location Type.
list teleport_list
The list of Teleport Destinations.
float landing_offset
The distance offset between the landing and the Teleporter.
string LOCALITY_GROUP
Configuration File Identifier for the Regional Location.
float MINIMUM_OFFSET
Minimum allowable offset.
string LANDING_OFFSET
The Configuration File Identifier for the Landing Offset Distance.
rdProcessFailureMessage(string FailureMessage)
Convert error messages into something that is more readable.
float MAXIMUM_OFFSET
Maximum allowable offset.
list destination_preamble
integer ANONYMOUS_FLAG
This flag designates the teleporter as anonymous.
float heartbeat_period
Interval in seconds between Heartbeat messages.
rdSaveNewTeleportNotecard(list teleport_list)
Save the Teleportation Destinations into a Notecard.
string REGION_LOCATION
The Configuration File Identifier for the Regional Location.
string GROUP_LOCATION
The Configuration File Identifier for all Goup Locations.
key heartbeat_key
The Heatbeat HTTP Requrest Key.
string HEARTBEAT_PERIOD
The Configuration File Identifier for the Heartbeat Period.
string LOCATION_TYPE
The Configuration File Identifier for the Location Type.
float MINIMUM_HEARTBEAT_INTERVAL
integer rdSetAnonType(string ValueObject, integer InfoInteger)
Set of Reset the Anonymous Flag.
string FRONT_OFFSET_ANGLE
The Configuration File Identifier for the Look At Angle.
string METAVERSE_LOCATION
The Configuration File Identifier for the Metaverse Location.
string rdAdjustPosition(string Line)
integer GROUP_FLAG
Numeric identifier of a Group Location.
integer LOCATION_MASK
A mask to remove locaiton information.
integer version_number
Version number as integer.
string ANONYMOUS_UNIT
The configuration Identifier for Anonymous Operation.
string locality_group
integer rdGetVersionNumber(string VersionString)
Convert Version String into an Integer.
integer location_info
Information on the Teleporter Location.
float MINIMUM_HEARTBEAT_PERIOD
The fastest allowable heartbeat.