├── Player Connect ├── Fonts │ ├── Montserrat-Black.ttf │ ├── Montserrat-Bold.ttf │ ├── Montserrat-SemiBold.ttf │ ├── Montserrat-Bold.ttf.import │ ├── Montserrat-Black.ttf.import │ └── Montserrat-SemiBold.ttf.import └── Scripts │ ├── WebhookCreator.gd │ └── PlayerConnect.gd ├── project.godot ├── README.md └── LICENSE /Player Connect/Fonts/Montserrat-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitbutter/PlayerConnect/main/Player Connect/Fonts/Montserrat-Black.ttf -------------------------------------------------------------------------------- /Player Connect/Fonts/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitbutter/PlayerConnect/main/Player Connect/Fonts/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /Player Connect/Fonts/Montserrat-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitbutter/PlayerConnect/main/Player Connect/Fonts/Montserrat-SemiBold.ttf -------------------------------------------------------------------------------- /Player Connect/Fonts/Montserrat-Bold.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://iw7cdue8nv41" 6 | path="res://.godot/imported/Montserrat-Bold.ttf-d49f680f6f3bc06317439feb48d02da9.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://Player Connect/Fonts/Montserrat-Bold.ttf" 11 | dest_files=["res://.godot/imported/Montserrat-Bold.ttf-d49f680f6f3bc06317439feb48d02da9.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | disable_embedded_bitmaps=true 19 | multichannel_signed_distance_field=false 20 | msdf_pixel_range=8 21 | msdf_size=48 22 | allow_system_fallback=true 23 | force_autohinter=false 24 | hinting=1 25 | subpixel_positioning=1 26 | oversampling=0.0 27 | Fallbacks=null 28 | fallbacks=[] 29 | Compress=null 30 | compress=true 31 | preload=[] 32 | language_support={} 33 | script_support={} 34 | opentype_features={} 35 | -------------------------------------------------------------------------------- /Player Connect/Fonts/Montserrat-Black.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://bwrtrht42hemw" 6 | path="res://.godot/imported/Montserrat-Black.ttf-408d5d119bac61c18577df720ccd1277.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://Player Connect/Fonts/Montserrat-Black.ttf" 11 | dest_files=["res://.godot/imported/Montserrat-Black.ttf-408d5d119bac61c18577df720ccd1277.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | disable_embedded_bitmaps=true 19 | multichannel_signed_distance_field=false 20 | msdf_pixel_range=8 21 | msdf_size=48 22 | allow_system_fallback=true 23 | force_autohinter=false 24 | hinting=1 25 | subpixel_positioning=1 26 | oversampling=0.0 27 | Fallbacks=null 28 | fallbacks=[] 29 | Compress=null 30 | compress=true 31 | preload=[] 32 | language_support={} 33 | script_support={} 34 | opentype_features={} 35 | -------------------------------------------------------------------------------- /Player Connect/Fonts/Montserrat-SemiBold.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://c2urtc164q04" 6 | path="res://.godot/imported/Montserrat-SemiBold.ttf-96b2b784277327212bb15cadcc52f1e0.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://Player Connect/Fonts/Montserrat-SemiBold.ttf" 11 | dest_files=["res://.godot/imported/Montserrat-SemiBold.ttf-96b2b784277327212bb15cadcc52f1e0.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | disable_embedded_bitmaps=true 19 | multichannel_signed_distance_field=false 20 | msdf_pixel_range=8 21 | msdf_size=48 22 | allow_system_fallback=true 23 | force_autohinter=false 24 | hinting=1 25 | subpixel_positioning=1 26 | oversampling=0.0 27 | Fallbacks=null 28 | fallbacks=[] 29 | Compress=null 30 | compress=true 31 | preload=[] 32 | language_support={} 33 | script_support={} 34 | opentype_features={} 35 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="Player Connect" 14 | config/version="0.5.a" 15 | run/main_scene="res://Player Connect/Scenes/PlayerConnect.tscn" 16 | config/features=PackedStringArray("4.3", "Forward Plus") 17 | 18 | [display] 19 | 20 | window/size/viewport_width=960 21 | window/size/viewport_height=540 22 | window/stretch/mode="canvas_items" 23 | window/stretch/aspect="keep_width" 24 | window/vsync/vsync_mode=0 25 | 26 | [editor_plugins] 27 | 28 | enabled=PackedStringArray() 29 | 30 | [input] 31 | 32 | Report={ 33 | "deadzone": 0.5, 34 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194333,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 35 | ] 36 | } 37 | Escape={ 38 | "deadzone": 0.5, 39 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 40 | ] 41 | } 42 | 43 | [rendering] 44 | 45 | environment/defaults/default_clear_color=Color(0.145098, 0.164706, 0.196078, 1) 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

PLAYER CONNECT

2 |

Player Connect also known as a Reporting System which can be implemented inside your Godot Game and with ease. it uses Godot's HTTPRequest node to send Calls to Discord's Webhook.. and so in whichever channel your webhook is.. it will send the data to that specific channel.. please keep in mind don't share your webhook url to the public. it would lead to disasters

3 | 4 | ![Cover](https://github.com/rayzorite/PlayerConnect/assets/92097566/b7e949cd-c08f-4a53-84e9-9415f577a680) 5 | 6 |
7 |
8 |
9 | 10 |

HOW TO USE IT

11 |
  • Download Zip or Clone this repository, Alternatively you can go to releases page and just download the tool folder (it doesnt come up with project.godot file)
  • 12 |
  • Now inside your game scene.. press a little "Link" icon in your Scene Tree Hierarchy and search "PlayerConnect".
  • 13 |
  • This will add the scene to your main game scene.. from here you can go inside PlayerConnect scene and can customize the whole ui to your liking..
  • 14 |
  • There are two scripts that comes with this tool.. PlayerConnect.gd and WebhookCreator.gd.
  • 15 |
  • Both these scripts contain alot of comments so it might help you understand my spaghetti code :p
  • 16 | 17 |
    18 |
    19 |
    20 | 21 |

    USEFUL LINKS

    22 |
  • Understanding Discord Webhooks
  • 23 |
  • Discord Embed Color Codes (Integer Values)
  • 24 |
  • Godot HTTP Request
  • 25 | 26 |
    27 |
    28 |
    29 | 30 |

    CONTRIBUTION

    31 |

    Well, as you can see with this code, i make alot of spaghetti code.. if you still wanna help and make this a better tool for everyone you can help contributing so everyone can take advantage of this tool more..

    32 | 33 |
    34 |
    35 |
    36 | 37 |

    LICENSE

    38 |

    it's CC0, so no credit is required but appreciated.. Please dont reframe it as your own and sell it.. Thanks

    39 | -------------------------------------------------------------------------------- /Player Connect/Scripts/WebhookCreator.gd: -------------------------------------------------------------------------------- 1 | class_name WebhookCreator 2 | extends HTTPRequest 3 | 4 | ## Defining signals for different outcomes 5 | signal SendingMessageFinished 6 | signal SendingMessageFailed 7 | signal SendingMessageSuccess 8 | 9 | var requestBody := [] ## List to store entire message/embed body 10 | var jsonPayload := {} ## Dictionary to store JSON data 11 | var isEmbedding := false ## Flag to check if an embed is currently being created 12 | var lastEmbed := {} ## Dictionary to store the current embed data 13 | var lastEmbedFields := [] ## List to store fields for the current embed 14 | 15 | ## Starts constructing a new message 16 | func StartMessage(): 17 | ## Checking if the HTTP client is currently connected 18 | if get_http_client_status() != HTTPClient.STATUS_DISCONNECTED: 19 | return ERR_BUSY ## Returns error if the client is busy 20 | 21 | ## Clearing previous (if any) request data 22 | requestBody.clear() 23 | jsonPayload.clear() 24 | requestBody.push_back(jsonPayload) 25 | lastEmbed.clear() 26 | lastEmbedFields.clear() 27 | return OK ## Returns OK to indicate success 28 | 29 | ## Setting the player's username to indicate who made the report 30 | func SetUsername(username:String): 31 | jsonPayload["username"] = username 32 | 33 | ## Function to start creating an embed 34 | func StartEmbed(): 35 | if isEmbedding: 36 | FinishEmbed() 37 | isEmbedding = true ## Setting the flag to indicate that embedding has started 38 | 39 | ## Function to finish and add the current embed to the message 40 | func FinishEmbed(): 41 | if isEmbedding: 42 | lastEmbed["fields"] = lastEmbedFields ## Adding fields to the current embed 43 | if jsonPayload.get("embeds") is Array: 44 | jsonPayload["embeds"].push_back(lastEmbed) ## Adding the embed to the list of embeds 45 | else: 46 | jsonPayload["embeds"] = [lastEmbed] ## Creating a new list with the embed 47 | isEmbedding = false ## Reset the embedding flag 48 | 49 | ## Function to add a field to the current embed 50 | func AddField(field_name:String, field_value:String, field_inline:=false): 51 | lastEmbedFields.push_back({"name": field_name, "value": field_value, "inline": field_inline}) 52 | 53 | ## Function to set the color of the current embed 54 | func SetEmbedColor(color:int): 55 | lastEmbed["color"] = color 56 | 57 | ## Function to set the title of the current embed (Report Types) 58 | func SetEmbedTitle(title:String): 59 | lastEmbed["title"] = title 60 | 61 | ## Function to set the footer of the current embed with game version 62 | func SetEmbedFooter(footer_text:String, version:String): 63 | lastEmbed["footer"] = {"text": "%s: v%s" % [footer_text, version]} 64 | 65 | ## Function to convert an array of variants into multipart form data 66 | func ArrayToFormData(array: Array, boundary := "boundary")->String: 67 | var file_counter := 0 68 | var output = "" 69 | 70 | for element in array: 71 | output += "--%s\n" % boundary # Start boundary for each part 72 | 73 | if element is Dictionary: 74 | # Same handling of dictionaries as in version 1 75 | output += 'Content-Disposition: form-data; name="payload_json"\nContent-Type: application/json\n\n' 76 | output += JSON.stringify(element, " ") + "\n" 77 | elif element is String: 78 | # Checks if the string element is both an absolute path and file exists 79 | if element.is_absolute_path() and FileAccess.file_exists(element): 80 | var file := FileAccess.open(element, FileAccess.READ) 81 | # Checks if file object is successfully created 82 | if file != null: 83 | var file_content := file.get_buffer(file.get_length()) 84 | file.close() 85 | 86 | # Sets up headers for file upload and adds binary file content 87 | output += 'Content-Disposition: form-data; name="files[%s]"; filename="%s"\n' % [file_counter, element.get_file()] 88 | output += "Content-Type: application/octet-stream\n\n" 89 | output += file_content.get_string_from_utf8() # Converts binary to string assuming UTF-8 encoding 90 | output += "\n" 91 | else: 92 | # Error handling if file cannot be opened 93 | printerr("Reporter could not attach File %s to Message, Reason: Failed to open file" % element) 94 | else: 95 | # Error handling if file does not exist 96 | printerr("Reporter could not attach File %s to Message, Reason: File does not exist" % element) 97 | file_counter += 1 98 | 99 | output += "--%s--" % boundary # Closing boundary 100 | return output 101 | 102 | ## Function to send the constructed message 103 | func SendMessage(url:String): 104 | FinishEmbed() ## Ensure any current embed is finished 105 | var boundary := "b%s" % hash(str(Time.get_unix_time_from_system(), jsonPayload)) 106 | var payload := ArrayToFormData(requestBody, boundary) # Convert request body to multipart form data 107 | 108 | ## Requesting HTTPClient 109 | request(url, 110 | PackedStringArray(["connection: keep-alive", "Content-type: multipart/form-data; boundary=%s" % boundary]), 111 | HTTPClient.METHOD_POST, 112 | payload 113 | ) 114 | 115 | ## Function called when the request is completed 116 | func OnRequestCompleted(result, _response_code, _headers, _body): 117 | if result == RESULT_SUCCESS: 118 | SendingMessageSuccess.emit() 119 | else: 120 | SendingMessageFailed.emit() 121 | SendingMessageFinished.emit() 122 | 123 | func AddFile(file_path: String, file_name: String): 124 | if file_path.is_absolute_path() and FileAccess.file_exists(file_path): 125 | requestBody.push_back(file_path) 126 | else: 127 | printerr("Reporter could not attach File %s to Message, Reason: File does not exist" % file_path) 128 | 129 | -------------------------------------------------------------------------------- /Player Connect/Scripts/PlayerConnect.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | class_name PlayerConnect 3 | 4 | ## Create webhook of your discord channel and paste in the url here 5 | const WEBHOOK_URL: String = "" 6 | 7 | ## Add your game's name here, this will be your webhook's username 8 | const GAME_NAME: String = "The Void Project" 9 | 10 | ## Calling game version from Project Setttings.. change your game version from there.. 11 | var gameVer = ProjectSettings.get("application/config/version") 12 | 13 | ## Use this website to find discord embed color codes (copy int value) 14 | ## https://gist.github.com/thomasbnt/b6f455e2c7d743b796917fa3c205f812?permalink_comment_id=3546054 15 | ## If you wish to add your own or contribute, please describe colors here for other options 16 | const BUG_REPORT_EMBED_COLOR: int = 15548997 # RED 17 | const PLAYER_FEEDBACK_EMBED_COLOR: int = 15844367 #YELLOW 18 | const FEATURE_REQUEST_EMBED_COLOR: int = 5763719 #GREEN 19 | 20 | @export var webhookCreator : WebhookCreator 21 | 22 | @export_group("Fields") 23 | @export var nameLineEdit: LineEdit 24 | @export var emailLineEdit: LineEdit 25 | @export var typeOptions: OptionButton 26 | @export var messageTextEdit: TextEdit 27 | 28 | @export_group("Button") 29 | @export var submitButton: Button 30 | 31 | @export_group("Misc") 32 | @export var animator: AnimationPlayer 33 | 34 | var isOpened: bool 35 | 36 | func _ready() -> void: 37 | ## Setting Submit Button Pivot to Center 38 | submitButton.pivot_offset = submitButton.size / 2 39 | webhookCreator.SendingMessageFinished.connect(submitButton.set.bind("disabled", false)) 40 | 41 | func _process(_delta: float) -> void: 42 | ## Checking Empty fields and if there are any, disabling submit button 43 | ## You can remove it or add exception if you want to make any lineEdit optional 44 | CheckingEmptyFields() 45 | 46 | func _input(event: InputEvent) -> void: 47 | ## Add Input key in your project settings for Report and Escape if u want 48 | if Input.is_action_pressed("Report") and not isOpened: 49 | OpenAnimation() 50 | elif event.is_action_pressed("Report") or event.is_action_pressed("Escape") and isOpened: 51 | CloseAnimation() 52 | 53 | func OpenAnimation() -> void: 54 | animator.play("Open") 55 | get_tree().paused = true 56 | await animator.animation_finished 57 | isOpened = true 58 | 59 | func CloseAnimation() -> void: 60 | animator.play("Close") 61 | await animator.animation_finished 62 | isOpened = false 63 | get_tree().paused = false 64 | 65 | func CheckingEmptyFields() -> void: 66 | if nameLineEdit.text.is_empty() or emailLineEdit.text.is_empty() or typeOptions.text.is_empty() or messageTextEdit.text.is_empty(): 67 | submitButton.disabled = true 68 | submitButton.mouse_default_cursor_shape = Control.CURSOR_ARROW 69 | if not nameLineEdit.text.is_empty() and not emailLineEdit.text.is_empty() and not typeOptions.text.is_empty() and not messageTextEdit.text.is_empty(): 70 | submitButton.disabled = false 71 | submitButton.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND 72 | 73 | #region Submit Button 74 | 75 | func OnSubmitButtonHoverEnter() -> void: 76 | if submitButton.disabled: return 77 | ParallelTweening(submitButton, "scale", Vector2.ONE * 1.1, 0.15) 78 | 79 | func OnSubmitButtonHoverExit() -> void: 80 | if submitButton.disabled: return 81 | ParallelTweening(submitButton, "scale", Vector2.ONE, 0.1) 82 | 83 | func OnSubmitButtonPressed() -> void: 84 | NonParallelTweening(submitButton, "scale", Vector2.ONE * 0.95, Vector2.ONE, 0.1) 85 | 86 | if webhookCreator.StartMessage() == OK: 87 | SendReport() 88 | 89 | func SendReport(): 90 | ## Setting Webhook Name 91 | webhookCreator.SetUsername(GAME_NAME) 92 | 93 | ## Setting up Embed 94 | webhookCreator.StartEmbed() 95 | webhookCreator.SetEmbedTitle("%s by %s" % [typeOptions.text, nameLineEdit.text]) 96 | 97 | ## Setting embed color based on what type of option is selected based on their item ids from options button node 98 | match typeOptions.get_selected_id(): 99 | 0: webhookCreator.SetEmbedColor(BUG_REPORT_EMBED_COLOR) # Bug Report 100 | 1: webhookCreator.SetEmbedColor(FEATURE_REQUEST_EMBED_COLOR) # Feature Request 101 | 2: webhookCreator.SetEmbedColor(PLAYER_FEEDBACK_EMBED_COLOR) # Feedback 102 | 103 | ## Example of how to attach a diagnostic log file 104 | #var my_diagnostic_log_string = "Log of game events. 1, 2, 3" 105 | #var diagnostic_log_file = FileAccess.open("user://diagnostic_log.txt", FileAccess.WRITE) 106 | #diagnostic_log_file.store_string(my_diagnostic_log_string) 107 | #diagnostic_log_file.close() 108 | #webhookCreator.AddFile("user://diagnostic_log.txt", "diagnostic_log.txt") 109 | 110 | ## Adding Email to Embed 111 | var contactInfo := emailLineEdit.text 112 | if !contactInfo.is_empty(): 113 | webhookCreator.AddField("Email Address: ", contactInfo) 114 | 115 | ## Adding Scene Name to Embed 116 | var sceneName = get_tree().current_scene.name 117 | if !sceneName.is_empty(): 118 | webhookCreator.AddField("Scene: ", sceneName) 119 | 120 | ## Adding Message to Embed 121 | var message = messageTextEdit.text.replace("```", "") 122 | if !message.is_empty(): 123 | webhookCreator.AddField("Message: ", message) 124 | 125 | ## Adding footer with game version 126 | webhookCreator.SetEmbedFooter("Game Version", gameVer) 127 | 128 | webhookCreator.SendMessage(WEBHOOK_URL) 129 | 130 | ## FOR DEBUGGING, YOU CAN REMOVE THIS 131 | print_rich( 132 | "[b][color=green]REPORT SENT[/color][/b]", "\n", 133 | "[b]Name:[/b] ", nameLineEdit.text, "\n", 134 | "[b]Email:[/b] ", emailLineEdit.text, "\n", 135 | "[b]Report Type:[/b] ", typeOptions.text, "\n", 136 | "[b]Scene:[/b] ", sceneName, "\n", 137 | "[b]Detailed Report:[/b] ", messageTextEdit.text, "\n", 138 | "[b]Game Version:[/b] v", gameVer, "\n", 139 | ) 140 | 141 | ## Closing after submit 142 | CloseAnimation() 143 | 144 | #endregion 145 | 146 | #region Misc Functions 147 | 148 | ## FOR ANIMATIONS 149 | func ParallelTweening(object: Object, property: String, finalValue: Variant, duration: float) -> void: 150 | var tween = get_tree().create_tween().set_ease(Tween.EASE_IN).set_parallel(true) 151 | tween.tween_property(object, property, finalValue, duration) 152 | 153 | func NonParallelTweening(object: Object, property: String, firstValue: Variant, finalValue: Variant, duration: float) -> void: 154 | var tween = get_tree().create_tween().set_ease(Tween.EASE_IN).set_parallel(false) 155 | tween.tween_property(object, property, firstValue, duration) 156 | tween.tween_property(object, property, finalValue, duration) 157 | 158 | #endregion 159 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | --------------------------------------------------------------------------------