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 = "2.0.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
129 string REMOTE_UPDATE = "REMOTE_UPDATE";
130
131
136 string EXTENDED_LOCAL = "EXTENDED_LOCAL";
137
145string REGION_LOCATION = "REGION";
146
154string WORLD_LOCATION = "WORLD";
155
163string METAVERSE_LOCATION = "METAVERSE";
164
169integer GROUP_FLAG = 1;
170
175integer REGION_FLAG = 2;
176
181integer WORLD_FLAG = 4;
182
187integer METAVERSE_FLAG = 8;
188
199integer ANONYMOUS_FLAG = 16;
200
210
218
226
227
232string LOCALITY_GROUP = "LOCALITY_GROUP";
233
238float TIMER_OFF = 0.0;
239
247
252float MINIMUM_OFFSET = 0.5;
253
258float MAXIMUM_OFFSET = 10.0;
259
272
281
282string locality_group = "null";
283
290
296
302
308
317
323
330
337
343integer location_info = 0;
344
355
362 "// Filename: teleport_destinations.config",
363 "// Version: " + VERSION_STRING,
364 "// Date: " + llGetDate() + " UTC",
365 "// Author: River Drifter ( river-drifter@aussiebroadband.com.au )",
366 "// Email: river-drifter@aussiebroadband.com.au",
367 "// Licence: Creative Commons Attribution Share Alike 4.0 International or better",
368 "//",
369 "// This destination file is created specifically for this teleporter in the region where",
370 "// it was located. If the teleporter is moved to another region, it must be reset to",
371 "// generate a new version of this file.",
372 "//",
373 "// *NOTE*: This file is periodically recreated by the Teleporter Heartbeat script.",
374 "// All entries place here manually will be lost when the file is recreated. If you",
375 "// wish do testing with manual entries, disable the heartbeat script for the duration.",
376 "//=========================================================="
377 ];
378
387rdProcessFailureMessage(string FailureMessage)
388{
389 string failure_message;
390
391 list status = llParseString2List(FailureMessage, [":"], ["\n"]);
392 string failure_type = llList2String(status, 0);
393
394 // Explain why the Teleporter could not be automatically processed
395 if (failure_type == "BANNED")
396 {
397 failure_message = "Teleporters owned by user " + llList2String(status, 1) + " are not permitted to";
398 failure_message += " add teleporters to the database, update teleporter information or update teleporter destinations.";
399 }
400
401 // Explain that the Updating of the Datasbase using the Heartbeat message has failed.
402 else if (failure_type == "UPDATE")
403 {
404 failure_message = "The updating of the Teleporter's information in the database has unexpectedly failure with the error message: ";
405 failure_message += llList2String(status, 1);
406 }
407
408 // Explain that the Insertion into the Database using the Heartbeat message has failed
409 else if (failure_type == "INSERT")
410 {
411 failure_message = "The insertion of a new teleporter's information into the database has failed unexpectedly with the error message: ";
412 failure_message += llList2String(status, 1);
413 }
414
415 // Explain that the Insertion/update failed because the Teleporter name was already in use and duplicate names are not allowed.
416 else if (failure_type == "NAME_MATCH")
417 {
418 failure_message = "Unable to insert the new teleporter's information into the database because the Teleporter's Name is already in use ";
419 failure_message += "by another teleporter located at " + llList2String(status, 1);
420 }
421
422 // Explain that a failure in extracting the destination list for this Teleporter
423 else if (failure_type == "EXTRACT")
424 {
425 failure_message = "The extraction of the list of teleporter destinations has failed unexpectedly with the error message: ";
426 failure_message += llList2String(status, 1);
427 }
428
429 // Explain that Teleporters from world's outside of this one cannot be added automatically added.
430 else if (failure_type == "INVADER")
431 {
432 failure_message = "Teleports from home world '" + llList2String(status, 1) + "' are not permitted to ";
433 failure_message += " add teleporters to the database, update teleporter information or update teleporter destinations.";
434 }
435
436 // Tell the person what to do if there was an error.
437 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";
438 llSay(0, failure_message);
439}
440
446integer rdSetAnonType(string ValueObject, integer InfoInteger)
447{
448 if (llToUpper(ValueObject) == "YES") InfoInteger |= ANONYMOUS_FLAG; else InfoInteger &= ~ANONYMOUS_FLAG;
449
450 return InfoInteger;
451}
452
458integer rdSetRemoteUpdate(string ValueObject, integer InfoInteger)
459{
460 if (llToUpper(ValueObject) == "YES") InfoInteger |= REMOTE_UPDATE_FLAG; else InfoInteger &= ~REMOTE_UPDATE_FLAG;
461 return InfoInteger;
462}
463
469integer rdSetExtendedLocal(string ValueObject, integer InfoInteger)
470{
471 if (llToUpper(ValueObject) == "TRUE") InfoInteger |= EXTENDED_LOCAL_FLAG; else InfoInteger &= ~EXTENDED_LOCAL_FLAG;
472 return InfoInteger;
473}
474
482integer rdGetVersionNumber(string VersionString)
483{
484 integer version;
485
486 list versions = llParseString2List(VersionString, ["."], []);
487 version = (integer)llList2String(versions,2) + ((integer)llList2String(versions,1) * 100) + ((integer)llList2String(versions,0) * 10000);
488
489 return version;
490}
491
500integer rdSetLocationType(string ValueString, integer LocationInfo)
501{
502 integer location_buffer = 0;
503
504 // Cut the Location Types out of the Location Info
505 LocationInfo &= LOCATION_MASK;
506
507 // Break the Value String into Components
508 list type_component = llParseString2List(ValueString, [","], []);
509 integer list_size = llGetListLength(type_component);
510 integer index = 0;
511
512 // Process each LocationType
513 for (; index < list_size; ++index)
514 {
515 string location_type = llStringTrim(llList2String(type_component, index), STRING_TRIM);
516 if (location_type == GROUP_LOCATION) location_buffer += GROUP_FLAG;
517 else if (location_type == REGION_LOCATION) location_buffer += REGION_FLAG;
518 else if (location_type == WORLD_LOCATION) location_buffer += WORLD_FLAG;
519 else if (location_type == METAVERSE_LOCATION) location_buffer += METAVERSE_FLAG;
520 }
521
522 // Put intp the Location Information
523 LocationInfo |= location_buffer;
524
525 return LocationInfo;
526}
527
528string rdAdjustPosition(string Line)
529{
530 string world;
531 string region;
532 string output_line;
533 vector landing;
534 vector look_at;
535
536 //llSay(0,Line);
537
538 // Split the Entry into components
539 list components = llParseString2List(Line, ["|"], []);
540
541 string name = components[0];
542 vector init_pos = (vector)components[1];
543 rotation initial_rot = (rotation)components[2];
544 vector offset_info = (vector)components[3];
545 string location_group = components[4];
546 integer address_type = (integer)components[5];
547
548 if (address_type == 2)
549 {
550 region = components[6];
551 world = components[7];
552 }
553 else if (address_type == 1)
554 {
555 region = components[6];
556 world = location_world;
557 }
558 else if (address_type == 0)
559 {
560 region = location_region;
561 world = location_world;
562 }
563 else
564 {
565 llSay(DEBUG_CHANNEL, "Format Error");
566 }
567
568 // Because of the Inherent limit of eight(8) elements when parsing a string
569 // three (3) of the numeric items were condensed into a vector to overcome this
570 // problem.
571 float offset_distance = (float)offset_info.x;
572 float look_angle = (float)offset_info.y;
573 integer location_information = (integer)offset_info.z;
574
575 // Determine the Landing Position by adding offset to the Teleporter's Location
576 // The offset is set negative to move to it "back to the front" of the Teleporter Object
577 landing = init_pos + llRot2Fwd(initial_rot) * -offset_distance;
578
579 vector temp = llRot2Euler(initial_rot * llAxisAngle2Rot(<0,0,1>, look_angle));
580 look_at = <llCos(temp.z), llSin(temp.z), 0.0>;
581
582 // Create the String to be stored in the Teleport Destination Notecard.
583
584 output_line = name + "|" + world + "|" + region + "|";
585 output_line += (string)landing + '|' + (string)look_at + '|';
586 output_line += (string)location_information + '|';
587 output_line += location_group + "\n";
588
589 return output_line;
590}
591
601{
602 // Add the Preamble Text before the List of Destinations
604
605 // Delete the Existing Teleporter Destination Notecard, if it exists
606 integer count = llGetInventoryNumber(INVENTORY_NOTECARD);
607 integer index = 0;
608 for (; index < count; ++index)
609 {
610 if (llGetInventoryName(INVENTORY_NOTECARD, index) == CONFIG_DESTINATIONS_NAME)
611 {
612 llRemoveInventory(CONFIG_DESTINATIONS_NAME);
613 index = count; // Ext Loop
614 }
615 }
616
617 // Write the Teleport List to a New Notecard
619}
620
635{
636 // Do a cursory Check that the configuration has been set up
637 if ((location_name != "") && (database_interface != ""))
638 {
639 // Reset the Data received for the Database
640 teleport_list = [];
641 integer teleport_list_started = FALSE;
642
643 key teleporter_key = llGetKey();
644 list details = llGetObjectDetails(teleporter_key, [OBJECT_POS, OBJECT_ROT, OBJECT_OWNER, OBJECT_GROUP]);
645
646 string heartbeat_message = database_interface + "?command=heartbeat"
647 + "&name=" + llEscapeURL(location_name)
648 + "&key=" + teleporter_key
649 + "&position=" + osReplaceString(llList2String(details, 0), " ", "", -1, 0)
650 + "&rotation=" + osReplaceString(llList2String(details, 1), " ", "", -1, 0)
651 + "&owner=" + llList2String(details, 2)
652 + "&group=" + llList2String(details, 3)
653 + "&world=" + location_world
654 + "&region=" + llGetRegionName()
655 + "&offset=" + (string)landing_offset
656 + "&offsetangle=" + (string)front_offset_angle
657 + "&locationinfo=" + (string)location_info
658 + "&vernum=" + (string)version_number
659 + "&localitygroup=" + locality_group;
660 heartbeat_key = llHTTPRequest(heartbeat_message, [HTTP_BODY_MAXLENGTH,16384], [""]);
661 }
662 else
663 {
664 llSay(DEBUG_CHANNEL, "Either the location_name or database_interface are undefined! Teleporter " + location_name + " has been disabled");
665 llSetScriptState(llGetScriptName(), FALSE);
666 }
667}
668
673default
674{
681 state_entry()
682 {
683
684 location_world = llGetSubString(osGetGridHomeURI(), 7, -1);
685 location_region = llGetRegionName();
687
688 // Read the Configuration File into a List of Lines
689 string config = osGetNotecard(CONFIG_NOTECARD_NAME);
690 list config_data = llParseString2List(config, ["\n"], []);
691
692 // Process each line in the Configuration Data
693 integer index = 0;
694 integer list_length = llGetListLength(config_data);
695 for (; index < list_length; ++index)
696 {
697 // Trim line of Leading and Trailing Spaces
698 string trimmed_line = llStringTrim(llList2String(config_data, index), STRING_TRIM);
699
700 // Only Process lines that are not a comment line or blank
701 if ( (llGetSubString(trimmed_line, 0, COMMENT_PREAMBLE_LENGTH - 1) != COMMENT_PREAMBLE) && (trimmed_line != "") )
702 {
703 // Parse Line for a Configuration Field.
704 list key_value = llParseString2List(trimmed_line, ["="], []);
705
706 // Fold the Trimmed Key into upper case, to eliminate errors where the case is wrong in the config file.
707 string key_object = llToUpper(llStringTrim(llList2String(key_value, 0), STRING_TRIM));
708
709 // Trim the Value to remove leading and training spaces
710 string value_object = llStringTrim(llList2String(key_value, 1), STRING_TRIM);
711
712 // Process the Key-Value Pairs to Set Configuration
713 if (key_object == DATABASE_INTERFACE) database_interface = value_object;
714 else if (key_object == LOCATION_NAME) location_name = value_object;
715 else if (key_object == LANDING_OFFSET) landing_offset = (float)value_object;
716 else if (key_object == HEARTBEAT_PERIOD) heartbeat_period = (float)value_object * 3600.0; // Convert hours to seconds
717 else if (key_object == FRONT_OFFSET_ANGLE) front_offset_angle = (float)value_object;
718 else if (key_object == LOCATION_TYPE) location_info = rdSetLocationType(llToUpper(value_object), location_info);
719 else if (key_object == LOCALITY_GROUP) locality_group = llEscapeURL(value_object);
720 else if (key_object == ANONYMOUS_UNIT) location_info = rdSetAnonType(value_object, location_info);
721 else if (key_object == REMOTE_UPDATE) location_info = rdSetRemoteUpdate(value_object, location_info);
722 else if (key_object == EXTENDED_LOCAL) location_info = rdSetExtendedLocal(value_object, location_info);
723 }
724
725 // Check that the Heartbeat Period is equal to or greater than the Minimum
727
728 // Check the Landing Offset values against limits
730 }
731
732 // Send out an Initial Heartbeat Message
734
735 // Start the Heatbeat Timer, but first check that the heartbeat period would no result in flooding of the database.
737 llSetTimerEvent(heartbeat_period);
738 }
739
754 http_response(key RequestId, integer Status, list Metadata, string Body)
755 {
756 list teleport_list;
757
758 // Only respond to the Heartbeat Request
759 if (RequestId == heartbeat_key)
760 {
761 // Check to see if the Request was a Success
762 if (Status != 200)
763 {
764 llSay(DEBUG_CHANNEL, "Heartbeat Request Failed with error " + (string)Status);
765 }
766 else
767 {
768 // Split into a list for easier processing
769 list input_list = llParseString2List(Body, ["\n"], []);
770
771 // Step thought the list a line at a time
772 integer index = 0;
773 integer input_list_started = FALSE;
774 integer list_count = llGetListLength(input_list);
775
776 string line;
777 do
778 {
779 // Extract the Line
780 line = llList2String(input_list, index);
781
782 // Start the Teleport Notecard
783 if (line == "EXTRACT_LIST=START") input_list_started = TRUE;
784
785 // End if you find the END FLAG by setting index to the end
786 else if (line == "EXTRACT_LIST=END")
787 {
788 index = list_count;
789 input_list_started = FALSE;
790 }
791
792 // Extract the Data Line & Process
793 else if (input_list_started == TRUE)
794 {
795 string updated_line = rdAdjustPosition(line);
796 teleport_list += updated_line;
797 }
798
799 // Check if this is a status message of Pin Setting Message
800 else
801 {
802 list status_list = llParseString2List(line, ["="], []);
803 string key_string = llList2String(status_list, 0);
804 string value_string = llList2String(status_list, 1);
805 if (key_string == "FAILURE") rdProcessFailureMessage(value_string);
806 else if (key_string == "ACCESS_PIN") llSetRemoteScriptAccessPin((integer)value_string);
807 }
808
809 // Add Destination to the Teleport Notecard
810 }
811 while ( ++index < list_count);
812
813 // Replace the old Teleport Notecard with New One
815 }
816 }
817 }
818
824 timer()
825 {
827 }
828}
integer REGION_FLAG
Number value of REgion Location flag.
integer REMOTE_UPDATE_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.
integer ANONYMOUS_FLAG
This flag designates the teleporter as anonymous.
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.
integer EXTENDED_LOCAL_FLAG
Flag for Extended Local teleports.
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.
string REMOTE_UPDATE
Flag to Enable Auto Updating.
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.
string EXTENDED_LOCAL
The Extended Local indentifier.
list destination_preamble
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.
integer rdSetExtendedLocal(string ValueObject, integer InfoInteger)
Set of Reset the Extended Local Telportation Flag.
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.
integer rdSetRemoteUpdate(string ValueObject, integer InfoInteger)
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.