├── .gitignore ├── LICENSE.txt ├── README.md ├── demo └── EnetNode │ ├── client.gd │ ├── client.xscn │ ├── engine.cfg │ ├── export.cfg │ ├── fonts │ ├── mono-bold-20.fnt │ ├── mono-bold-20.inc │ ├── mono-bold-20.sv.png │ ├── mono-bold-20.sv.png.flags │ ├── mono-regular-18.fnt │ ├── mono-regular-18.inc │ ├── mono-regular-18.sv.png │ ├── mono-regular-18.sv.png.flags │ └── originals │ │ ├── AUTHORS │ │ ├── LICENSE │ │ ├── LiberationMono-Bold.ttf │ │ └── LiberationMono-Regular.ttf │ ├── icon.png │ ├── icon.png.flags │ ├── server.gd │ └── server.xscn └── modules └── benet ├── SCsub ├── config.py ├── enet_node.cpp ├── enet_node.h ├── enet_packet_peer.cpp ├── enet_packet_peer.h ├── register_types.cpp └── register_types.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.pyc 4 | *.swp 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2017 Fabio Alessandrelli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | The `benet` module for Godot is a fork of `NetworkedMultiplayerPacketPeer` (although it stays compatible) to allow access to multiple channels and the ability to run multiple clients/servers in the same scene. 3 | 4 | The module is composed by two parts: 5 | 6 | - `ENetPacketPeer`: The fork of `NetworkedMultiplayerPacketPeer` 7 | - `create_server`: Add parameter to specify max channels (default 1) 8 | - `create_client`: Add parameter to specify max channels (default 1) 9 | - `put_packet_channel`: New method, allow to put a packet in the specified channel 10 | - `send` (`_unreliable`, `_ordered`) allow to send to specific client in reliable, unreliable, ordered way whlie selecting the channel 11 | - `broadcast` (`_unreliable`, `_ordered`) allow to broadcast a packet in a reliable, unreliable, ordered way while selecting the channel 12 | 13 | - `ENetNode`: Act like `SceneTree`: 14 | - Poll on idle/fixed time (must be in tree to work!) 15 | - Emit signals on idle/fixed time (must be in tree to work!) 16 | - Emit additional `server_packet` and `client_packet` signals when receiving packets 17 | - Allow kicking clients by unique id. 18 | - Will hopefully support RPC in the future 19 | 20 | # Installation 21 | Being a module you will need to recompile godot from source. To do that: 22 | 23 | 1. Clone the godot engine repository 24 | 2. Copy the `benet` folder from this repository into the godot `modules` folder 25 | 3. Recompile godot (see http://docs.godotengine.org/en/latest/reference/_compiling.html ) 26 | 27 | # Usage 28 | 29 | For usage examples please refer to the project in the `demo` folder. 30 | 31 | The methods should be self explainatory. 32 | 33 | # Disclaimer 34 | 35 | > THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | -------------------------------------------------------------------------------- /demo/EnetNode/client.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Control 3 | 4 | var id = 0 5 | var connected = false 6 | 7 | var client_peer = ENetPacketPeer.new() 8 | onready var client = get_node("ENetNode") 9 | onready var client_log = get_node("ScrollContainer/ClientLog") 10 | onready var scroll_container = get_node("ScrollContainer") 11 | 12 | func _ready(): 13 | # Sent when the client disconnects 14 | client.connect("server_disconnected", self, "disconnected") 15 | # Sent when the client disconnects 16 | client.connect("connection_failed", self, "connect_failed") 17 | # Sent when the client connects to the server 18 | client.connect("connected_to_server", self, "connected") 19 | # Sent when a valid packet is received from the server 20 | client.connect("server_packet", self, "on_server_packet") 21 | # Sent when a valid packet is received from another peer 22 | client.connect("peer_packet", self, "on_peer_packet") 23 | 24 | # Sent when another peer connect to this server (will be called once for every connected client when you first connect) 25 | client.connect("network_peer_connected", self, "peer_connect") 26 | # Sent when another peer disconnect from the server 27 | client.connect("network_peer_disconnected", self, "peer_disconnect") 28 | 29 | # Create a client to 127.0.0.1 on port 4666 with 16 custom channels 30 | client_peer.create_client("127.0.0.1", 4666, 16) 31 | client.set_network_peer(client_peer) 32 | 33 | client_log.set_text("") 34 | write_log("Connecting...") 35 | set_fixed_process(true) 36 | set_process(true) 37 | 38 | func disconnected(): 39 | write_log("Client Disconnected!") 40 | call_deferred("queue_free") 41 | 42 | func connected(): 43 | write_log("Just Connected! My ID is: " + str(client.get_network_unique_id()) ) 44 | 45 | func connect_failed(): 46 | write_log("Connection failed!") 47 | 48 | func peer_connect(id): 49 | write_log(str(id) + " - Connect") 50 | 51 | func peer_disconnect(id): 52 | write_log(str(id) + " - Disconnect") 53 | 54 | func on_server_packet(cmd, pkt): 55 | write_log("SERVER - CMD: " + str(cmd) + " DATA:" + str(Array(pkt))) 56 | 57 | func on_peer_packet(id, cmd, pkt): 58 | write_log(str(id), " - CMD: " + str(cmd) + " DATA:" + str(Array(pkt))) 59 | 60 | func _process(delta): 61 | scroll_container.set_v_scroll(scroll_container.get_v_scroll()+100) 62 | 63 | ### Scene functions 64 | func write_log(msg): 65 | print(msg) 66 | client_log.set_text(client_log.get_text()+"\n"+str(msg)) 67 | 68 | func _on_Button_pressed(): 69 | client.send_ordered(1, RawArray([2,52,12]), 2) 70 | 71 | func _on_TCP_pressed(): 72 | client.send(1, RawArray([22,36,89]), 1) 73 | 74 | func _exit_tree(): 75 | client_peer.close_connection() 76 | -------------------------------------------------------------------------------- /demo/EnetNode/client.xscn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | "conn_count" 8 | 2 9 | "conns" 10 | 4, 0, 34, 33, 2, 0, 5, 0, 34, 35, 2, 0 11 | "editable_instances" 12 | 13 | 14 | "names" 15 | 16 | "Scrollable" 17 | "anchor/right" 18 | "anchor/bottom" 19 | "focus/ignore_mouse" 20 | "focus/stop_mouse" 21 | "size_flags/horizontal" 22 | "size_flags/vertical" 23 | "margin/left" 24 | "margin/top" 25 | "margin/right" 26 | "margin/bottom" 27 | "script/script" 28 | "Control" 29 | "ScrollContainer" 30 | "editor/display_folded" 31 | "scroll/horizontal" 32 | "scroll/vertical" 33 | "ClientLog" 34 | "custom_fonts/font" 35 | "percent_visible" 36 | "lines_skipped" 37 | "max_lines_visible" 38 | "Label" 39 | "ENetNode" 40 | "signal_mode" 41 | "UDP" 42 | "toggle_mode" 43 | "enabled_focus_mode" 44 | "shortcut" 45 | "text" 46 | "flat" 47 | "Button" 48 | "TCP" 49 | "_on_Button_pressed" 50 | "pressed" 51 | "_on_TCP_pressed" 52 | 53 | "node_count" 54 | 6 55 | "node_paths" 56 | 57 | 58 | "nodes" 59 | -1, -1, 12, 0, -1, 11, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 8, 4, 9, 4, 10, 4, 11, 5, 0, 0, 0, 13, 13, -1, 13, 14, 2, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 8, 4, 9, 4, 10, 4, 15, 2, 16, 2, 0, 1, 0, 22, 17, -1, 12, 3, 1, 4, 2, 5, 6, 6, 6, 7, 7, 8, 7, 9, 4, 10, 8, 18, 9, 19, 10, 20, 11, 21, 12, 0, 0, 0, 23, 23, -1, 1, 24, 0, 0, 0, 0, 31, 25, -1, 14, 3, 1, 4, 2, 5, 6, 6, 6, 7, 4, 8, 4, 9, 13, 10, 14, 18, 9, 26, 1, 27, 6, 28, 15, 29, 16, 30, 1, 0, 0, 0, 31, 32, -1, 14, 3, 1, 4, 2, 5, 6, 6, 6, 7, 13, 8, 4, 9, 17, 10, 14, 18, 9, 26, 1, 27, 6, 28, 15, 29, 18, 30, 1, 0 60 | "variants" 61 | 62 | 1 63 | False 64 | True 65 | 3 66 | 0 67 | 68 | 2 69 | -0 70 | 18 71 | 72 | 1 73 | 0 74 | -1 75 | 56 76 | 24 77 | "UDP" 78 | 112 79 | "TCP" 80 | 81 | "version" 82 | 2 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /demo/EnetNode/engine.cfg: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | name="EnetNode" 4 | main_scene="res://server.xscn" 5 | target_fps=60 6 | icon="res://icon.png" 7 | -------------------------------------------------------------------------------- /demo/EnetNode/export.cfg: -------------------------------------------------------------------------------- 1 | [convert_images] 2 | 3 | action="none" 4 | compress_quality=0.7 5 | formats="png" 6 | shrink=1.0 7 | 8 | [convert_samples] 9 | 10 | action="none" 11 | max_hz=44100 12 | trim=false 13 | 14 | [convert_scenes] 15 | 16 | convert_text_scenes=true 17 | 18 | [export_filter] 19 | 20 | filter="" 21 | filter_exclude="" 22 | type="resources" 23 | 24 | [platform:Android] 25 | 26 | apk_expansion/SALT="" 27 | apk_expansion/enable=false 28 | apk_expansion/public_key="" 29 | architecture/arm=true 30 | architecture/x86=false 31 | command_line/extra_args="" 32 | custom_package/debug="" 33 | custom_package/release="" 34 | debug/debugging_enabled=true 35 | keystore/release="" 36 | keystore/release_password="" 37 | keystore/release_user="" 38 | one_click_deploy/clear_previous_install=true 39 | package/icon="" 40 | package/name="" 41 | package/signed=true 42 | package/unique_name="org.godotengine.$genname" 43 | permissions/access_checkin_properties=false 44 | permissions/access_coarse_location=false 45 | permissions/access_fine_location=false 46 | permissions/access_location_extra_commands=false 47 | permissions/access_mock_location=false 48 | permissions/access_network_state=false 49 | permissions/access_surface_flinger=false 50 | permissions/access_wifi_state=false 51 | permissions/account_manager=false 52 | permissions/add_voicemail=false 53 | permissions/authenticate_accounts=false 54 | permissions/battery_stats=false 55 | permissions/bind_accessibility_service=false 56 | permissions/bind_appwidget=false 57 | permissions/bind_device_admin=false 58 | permissions/bind_input_method=false 59 | permissions/bind_nfc_service=false 60 | permissions/bind_notification_listener_service=false 61 | permissions/bind_print_service=false 62 | permissions/bind_remoteviews=false 63 | permissions/bind_text_service=false 64 | permissions/bind_vpn_service=false 65 | permissions/bind_wallpaper=false 66 | permissions/bluetooth=false 67 | permissions/bluetooth_admin=false 68 | permissions/bluetooth_privileged=false 69 | permissions/brick=false 70 | permissions/broadcast_package_removed=false 71 | permissions/broadcast_sms=false 72 | permissions/broadcast_sticky=false 73 | permissions/broadcast_wap_push=false 74 | permissions/call_phone=false 75 | permissions/call_privileged=false 76 | permissions/camera=false 77 | permissions/capture_audio_output=false 78 | permissions/capture_secure_video_output=false 79 | permissions/capture_video_output=false 80 | permissions/change_component_enabled_state=false 81 | permissions/change_configuration=false 82 | permissions/change_network_state=false 83 | permissions/change_wifi_multicast_state=false 84 | permissions/change_wifi_state=false 85 | permissions/clear_app_cache=false 86 | permissions/clear_app_user_data=false 87 | permissions/control_location_updates=false 88 | permissions/delete_cache_files=false 89 | permissions/delete_packages=false 90 | permissions/device_power=false 91 | permissions/diagnostic=false 92 | permissions/disable_keyguard=false 93 | permissions/dump=false 94 | permissions/expand_status_bar=false 95 | permissions/factory_test=false 96 | permissions/flashlight=false 97 | permissions/force_back=false 98 | permissions/get_accounts=false 99 | permissions/get_package_size=false 100 | permissions/get_tasks=false 101 | permissions/get_top_activity_info=false 102 | permissions/global_search=false 103 | permissions/hardware_test=false 104 | permissions/inject_events=false 105 | permissions/install_location_provider=false 106 | permissions/install_packages=false 107 | permissions/install_shortcut=false 108 | permissions/internal_system_window=false 109 | permissions/internet=false 110 | permissions/kill_background_processes=false 111 | permissions/location_hardware=false 112 | permissions/manage_accounts=false 113 | permissions/manage_app_tokens=false 114 | permissions/manage_documents=false 115 | permissions/master_clear=false 116 | permissions/media_content_control=false 117 | permissions/modify_audio_settings=false 118 | permissions/modify_phone_state=false 119 | permissions/mount_format_filesystems=false 120 | permissions/mount_unmount_filesystems=false 121 | permissions/nfc=false 122 | permissions/persistent_activity=false 123 | permissions/process_outgoing_calls=false 124 | permissions/read_calendar=false 125 | permissions/read_call_log=false 126 | permissions/read_contacts=false 127 | permissions/read_external_storage=false 128 | permissions/read_frame_buffer=false 129 | permissions/read_history_bookmarks=false 130 | permissions/read_input_state=false 131 | permissions/read_logs=false 132 | permissions/read_phone_state=false 133 | permissions/read_profile=false 134 | permissions/read_sms=false 135 | permissions/read_social_stream=false 136 | permissions/read_sync_settings=false 137 | permissions/read_sync_stats=false 138 | permissions/read_user_dictionary=false 139 | permissions/reboot=false 140 | permissions/receive_boot_completed=false 141 | permissions/receive_mms=false 142 | permissions/receive_sms=false 143 | permissions/receive_wap_push=false 144 | permissions/record_audio=false 145 | permissions/reorder_tasks=false 146 | permissions/restart_packages=false 147 | permissions/send_respond_via_message=false 148 | permissions/send_sms=false 149 | permissions/set_activity_watcher=false 150 | permissions/set_alarm=false 151 | permissions/set_always_finish=false 152 | permissions/set_animation_scale=false 153 | permissions/set_debug_app=false 154 | permissions/set_orientation=false 155 | permissions/set_pointer_speed=false 156 | permissions/set_preferred_applications=false 157 | permissions/set_process_limit=false 158 | permissions/set_time=false 159 | permissions/set_time_zone=false 160 | permissions/set_wallpaper=false 161 | permissions/set_wallpaper_hints=false 162 | permissions/signal_persistent_processes=false 163 | permissions/status_bar=false 164 | permissions/subscribed_feeds_read=false 165 | permissions/subscribed_feeds_write=false 166 | permissions/system_alert_window=false 167 | permissions/transmit_ir=false 168 | permissions/uninstall_shortcut=false 169 | permissions/update_device_stats=false 170 | permissions/use_credentials=false 171 | permissions/use_sip=false 172 | permissions/vibrate=false 173 | permissions/wake_lock=false 174 | permissions/write_apn_settings=false 175 | permissions/write_calendar=false 176 | permissions/write_call_log=false 177 | permissions/write_contacts=false 178 | permissions/write_external_storage=false 179 | permissions/write_gservices=false 180 | permissions/write_history_bookmarks=false 181 | permissions/write_profile=false 182 | permissions/write_secure_settings=false 183 | permissions/write_settings=false 184 | permissions/write_sms=false 185 | permissions/write_social_stream=false 186 | permissions/write_sync_settings=false 187 | permissions/write_user_dictionary=false 188 | screen/immersive_mode=true 189 | screen/orientation=0 190 | screen/support_large=true 191 | screen/support_normal=true 192 | screen/support_small=true 193 | screen/support_xlarge=true 194 | screen/use_32_bits_view=true 195 | user_permissions/0="" 196 | user_permissions/1="" 197 | user_permissions/10="" 198 | user_permissions/11="" 199 | user_permissions/12="" 200 | user_permissions/13="" 201 | user_permissions/14="" 202 | user_permissions/15="" 203 | user_permissions/16="" 204 | user_permissions/17="" 205 | user_permissions/18="" 206 | user_permissions/19="" 207 | user_permissions/2="" 208 | user_permissions/3="" 209 | user_permissions/4="" 210 | user_permissions/5="" 211 | user_permissions/6="" 212 | user_permissions/7="" 213 | user_permissions/8="" 214 | user_permissions/9="" 215 | version/code=1 216 | version/name="1.0" 217 | 218 | [platform:BlackBerry 10] 219 | 220 | debug/debugging_enabled=true 221 | package/category="core.games" 222 | package/custom_template="" 223 | package/description="Game made with Godot Engine" 224 | package/icon="" 225 | package/name="" 226 | package/unique_name="com.godot.noname" 227 | release/author="Cert. Name" 228 | release/author_id="Cert. ID" 229 | version/code=1 230 | version/name="1.0" 231 | 232 | [platform:HTML5] 233 | 234 | browser/enable_run=false 235 | custom_package/debug="" 236 | custom_package/release="" 237 | debug/debugging_enabled=true 238 | html/controls_enabled=true 239 | html/font_family="arial,sans-serif" 240 | html/head_include="" 241 | html/style_include="" 242 | html/title="" 243 | options/memory_size=3 244 | 245 | [platform:Linux X11] 246 | 247 | binary/64_bits=true 248 | custom_binary/debug="/home/fales/Programming/workspaces/git/godot/bin/godot_server.server.opt.debug.64" 249 | custom_binary/release="" 250 | debug/debugging_enabled=true 251 | resources/bundle_dependencies_(for_optical_disc)=false 252 | resources/pack_mode=0 253 | 254 | [platform:Mac OSX] 255 | 256 | application/bits_mode=0 257 | application/copyright="" 258 | application/icon="" 259 | application/identifier="org.godotengine.macgame" 260 | application/info="Made with Godot Engine" 261 | application/name="" 262 | application/short_version="1.0" 263 | application/signature="godotmacgame" 264 | application/version="1.0" 265 | custom_package/debug="" 266 | custom_package/release="" 267 | debug/debugging_enabled=true 268 | display/high_res=false 269 | 270 | [platform:Windows Desktop] 271 | 272 | binary/64_bits=true 273 | custom_binary/debug="" 274 | custom_binary/release="" 275 | debug/debugging_enabled=true 276 | resources/bundle_dependencies_(for_optical_disc)=false 277 | resources/pack_mode=1 278 | 279 | [platform:Windows Universal] 280 | 281 | architecture/target=1 282 | capabilities/all_Joyn=false 283 | capabilities/appointments=false 284 | capabilities/blocked_Chat_Messages=false 285 | capabilities/bluetooth=false 286 | capabilities/chat=false 287 | capabilities/code_Generation=false 288 | capabilities/contacts=false 289 | capabilities/enterprise_Authentication=false 290 | capabilities/internet_Client=false 291 | capabilities/internet_Client_Server=false 292 | capabilities/location=false 293 | capabilities/microphone=false 294 | capabilities/music_Library=false 295 | capabilities/objects3_D=false 296 | capabilities/phone_Call=false 297 | capabilities/pictures_Library=false 298 | capabilities/private_Network_Client_Server=false 299 | capabilities/proximity=false 300 | capabilities/removable_Storage=false 301 | capabilities/shared_User_Certificates=false 302 | capabilities/user_Account_Information=false 303 | capabilities/videos_Library=false 304 | capabilities/voip_Call=false 305 | capabilities/webcam=false 306 | command_line/extra_args="" 307 | custom_package/debug="" 308 | custom_package/release="" 309 | debug/debugging_enabled=true 310 | identity/product_guid="00000000-0000-0000-0000-000000000000" 311 | identity/publisher_guid="00000000-0000-0000-0000-000000000000" 312 | images/background_color="transparent" 313 | images/splash_screen=null 314 | images/square150x150_logo=null 315 | images/square310x310_logo=null 316 | images/square44x44_logo=null 317 | images/square71x71_logo=null 318 | images/store_logo=null 319 | images/wide310x150_logo=null 320 | orientation/landscape=true 321 | orientation/landscape_flipped=true 322 | orientation/portrait=true 323 | orientation/portrait_flipped=true 324 | package/description="Godot Engine" 325 | package/display_name="" 326 | package/publisher="CN=GodotEngine" 327 | package/publisher_display_name="Godot Engine" 328 | package/short_name="Godot" 329 | package/unique_name="Godot.Engine" 330 | tiles/show_name_on_square150x150=false 331 | tiles/show_name_on_square310x310=false 332 | tiles/show_name_on_wide310x150=false 333 | version/build=0 334 | version/major=1 335 | version/minor=0 336 | version/revision=0 337 | 338 | [script] 339 | 340 | action="compile" 341 | encrypt_key="" 342 | -------------------------------------------------------------------------------- /demo/EnetNode/fonts/mono-bold-20.fnt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Faless/godot-enet-better/fc294ca1f418cfcd8e9864620dee8b52fbc49eca/demo/EnetNode/fonts/mono-bold-20.fnt -------------------------------------------------------------------------------- /demo/EnetNode/fonts/mono-bold-20.sv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Faless/godot-enet-better/fc294ca1f418cfcd8e9864620dee8b52fbc49eca/demo/EnetNode/fonts/mono-bold-20.sv.png -------------------------------------------------------------------------------- /demo/EnetNode/fonts/mono-bold-20.sv.png.flags: -------------------------------------------------------------------------------- 1 | gen_mipmaps=false 2 | -------------------------------------------------------------------------------- /demo/EnetNode/fonts/mono-regular-18.fnt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Faless/godot-enet-better/fc294ca1f418cfcd8e9864620dee8b52fbc49eca/demo/EnetNode/fonts/mono-regular-18.fnt -------------------------------------------------------------------------------- /demo/EnetNode/fonts/mono-regular-18.sv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Faless/godot-enet-better/fc294ca1f418cfcd8e9864620dee8b52fbc49eca/demo/EnetNode/fonts/mono-regular-18.sv.png -------------------------------------------------------------------------------- /demo/EnetNode/fonts/mono-regular-18.sv.png.flags: -------------------------------------------------------------------------------- 1 | gen_mipmaps=false 2 | -------------------------------------------------------------------------------- /demo/EnetNode/fonts/originals/AUTHORS: -------------------------------------------------------------------------------- 1 | AUTHORS 2 | 3 | Current Contributors (sorted alphabetically): 4 | - Pravin Satpute 5 | Project Owner (Current) 6 | Red Hat, Inc. 7 | 8 | Previous Contributors 9 | 10 | - Steve Matteson 11 | Original Designer 12 | Ascender, Inc. 13 | -------------------------------------------------------------------------------- /demo/EnetNode/fonts/originals/LICENSE: -------------------------------------------------------------------------------- 1 | Digitized data copyright (c) 2010 Google Corporation 2 | with Reserved Font Arimo, Tinos and Cousine. 3 | Copyright (c) 2012 Red Hat, Inc. 4 | with Reserved Font Name Liberation. 5 | 6 | This Font Software is licensed under the SIL Open Font License, 7 | Version 1.1. 8 | 9 | This license is copied below, and is also available with a FAQ at: 10 | http://scripts.sil.org/OFL 11 | 12 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 13 | 14 | PREAMBLE The goals of the Open Font License (OFL) are to stimulate 15 | worldwide development of collaborative font projects, to support the font 16 | creation efforts of academic and linguistic communities, and to provide 17 | a free and open framework in which fonts may be shared and improved in 18 | partnership with others. 19 | 20 | The OFL allows the licensed fonts to be used, studied, modified and 21 | redistributed freely as long as they are not sold by themselves. 22 | The fonts, including any derivative works, can be bundled, embedded, 23 | redistributed and/or sold with any software provided that any reserved 24 | names are not used by derivative works. The fonts and derivatives, 25 | however, cannot be released under any other type of license. The 26 | requirement for fonts to remain under this license does not apply to 27 | any document created using the fonts or their derivatives. 28 | 29 | 30 | 31 | DEFINITIONS 32 | "Font Software" refers to the set of files released by the Copyright 33 | Holder(s) under this license and clearly marked as such. 34 | This may include source files, build scripts and documentation. 35 | 36 | "Reserved Font Name" refers to any names specified as such after the 37 | copyright statement(s). 38 | 39 | "Original Version" refers to the collection of Font Software components 40 | as distributed by the Copyright Holder(s). 41 | 42 | "Modified Version" refers to any derivative made by adding to, deleting, 43 | or substituting ? in part or in whole ? 44 | any of the components of the Original Version, by changing formats or 45 | by porting the Font Software to a new environment. 46 | 47 | "Author" refers to any designer, engineer, programmer, technical writer 48 | or other person who contributed to the Font Software. 49 | 50 | 51 | PERMISSION & CONDITIONS 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a 54 | copy of the Font Software, to use, study, copy, merge, embed, modify, 55 | redistribute, and sell modified and unmodified copies of the Font 56 | Software, subject to the following conditions: 57 | 58 | 1) Neither the Font Software nor any of its individual components,in 59 | Original or Modified Versions, may be sold by itself. 60 | 61 | 2) Original or Modified Versions of the Font Software may be bundled, 62 | redistributed and/or sold with any software, provided that each copy 63 | contains the above copyright notice and this license. These can be 64 | included either as stand-alone text files, human-readable headers or 65 | in the appropriate machine-readable metadata fields within text or 66 | binary files as long as those fields can be easily viewed by the user. 67 | 68 | 3) No Modified Version of the Font Software may use the Reserved Font 69 | Name(s) unless explicit written permission is granted by the 70 | corresponding Copyright Holder. This restriction only applies to the 71 | primary font name as presented to the users. 72 | 73 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 74 | Software shall not be used to promote, endorse or advertise any 75 | Modified Version, except to acknowledge the contribution(s) of the 76 | Copyright Holder(s) and the Author(s) or with their explicit written 77 | permission. 78 | 79 | 5) The Font Software, modified or unmodified, in part or in whole, must 80 | be distributed entirely under this license, and must not be distributed 81 | under any other license. The requirement for fonts to remain under 82 | this license does not apply to any document created using the Font 83 | Software. 84 | 85 | 86 | 87 | TERMINATION 88 | This license becomes null and void if any of the above conditions are not met. 89 | 90 | 91 | 92 | DISCLAIMER 93 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 94 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 95 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 96 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 97 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 98 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 99 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 100 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER 101 | DEALINGS IN THE FONT SOFTWARE. 102 | 103 | -------------------------------------------------------------------------------- /demo/EnetNode/fonts/originals/LiberationMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Faless/godot-enet-better/fc294ca1f418cfcd8e9864620dee8b52fbc49eca/demo/EnetNode/fonts/originals/LiberationMono-Bold.ttf -------------------------------------------------------------------------------- /demo/EnetNode/fonts/originals/LiberationMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Faless/godot-enet-better/fc294ca1f418cfcd8e9864620dee8b52fbc49eca/demo/EnetNode/fonts/originals/LiberationMono-Regular.ttf -------------------------------------------------------------------------------- /demo/EnetNode/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Faless/godot-enet-better/fc294ca1f418cfcd8e9864620dee8b52fbc49eca/demo/EnetNode/icon.png -------------------------------------------------------------------------------- /demo/EnetNode/icon.png.flags: -------------------------------------------------------------------------------- 1 | gen_mipmaps=false 2 | -------------------------------------------------------------------------------- /demo/EnetNode/server.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Panel 3 | 4 | var client = preload("res://client.xscn") 5 | var clients = [] 6 | var server_peer = ENetPacketPeer.new() 7 | 8 | var udp_port = 4666 9 | 10 | onready var container = get_node("Client/Container") 11 | onready var server_log = get_node("Server/ScrollContainer/ServerLog") 12 | onready var server = get_node("Server/ScrollContainer/ENetNode") 13 | onready var scroll = get_node("Server/ScrollContainer") 14 | 15 | func _ready(): 16 | # Sent when a client disconnects 17 | server.connect("network_peer_disconnected", self, "server_client_disconnect") 18 | # Sent when a new client connects 19 | server.connect("network_peer_connected", self, "server_client_connect") 20 | # Sent when a valid UDP packet is received from a client 21 | server.connect("peer_packet", self, "on_peer_packet") 22 | 23 | # Create a server on port udp_port with 16 custom channels 24 | server_peer.create_server(udp_port, 16) 25 | server.set_network_peer(server_peer) 26 | 27 | set_process(true) 28 | 29 | 30 | func on_peer_packet(id, cmd, pkt): 31 | write_log(str(id) + " - CMD: " + str(cmd) + " DATA:" + str(Array(pkt))) 32 | 33 | func server_client_connect(id): 34 | write_log(str(id) + " - Connected") 35 | clients.append(id) 36 | 37 | func server_client_disconnect(id): 38 | write_log(str(id) + " - Disconnected") 39 | 40 | 41 | 42 | ### Scene functions 43 | func _process(delta): 44 | scroll.set_v_scroll(scroll.get_v_scroll()+1000) 45 | 46 | func spawn_client(): 47 | var spawn = client.instance() 48 | container.add_child(spawn) 49 | 50 | func write_log(msg): 51 | print(msg) 52 | server_log.set_text(server_log.get_text()+"\n"+str(msg)) 53 | 54 | func _on_RemoveClient_pressed(): 55 | if clients.size() > 0: 56 | var c = clients[0] 57 | server.kick_client(c) 58 | clients.remove(0) 59 | 60 | func _on_AddClient_pressed(): 61 | spawn_client() 62 | 63 | func _on_BcastTCP_pressed(): 64 | server.broadcast(RawArray([11,12,23]), 1) 65 | 66 | func _on_BcastUDP_pressed(): 67 | server.broadcast_ordered(RawArray([57,12,23,1,1,1,2,3]), 0) 68 | -------------------------------------------------------------------------------- /demo/EnetNode/server.xscn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | "conn_count" 9 | 4 10 | "conns" 11 | 3, 0, 46, 45, 2, 0, 5, 0, 46, 47, 2, 0, 11, 0, 46, 48, 2, 0, 13, 0, 46, 49, 2, 0 12 | "editable_instances" 13 | 14 | 15 | "names" 16 | 17 | "Panel" 18 | "anchor/right" 19 | "anchor/bottom" 20 | "focus/ignore_mouse" 21 | "focus/stop_mouse" 22 | "size_flags/horizontal" 23 | "size_flags/vertical" 24 | "margin/left" 25 | "margin/top" 26 | "margin/right" 27 | "margin/bottom" 28 | "script/script" 29 | "Server" 30 | "HBoxContainer" 31 | "custom_constants/separation" 32 | "alignment" 33 | "BcastUDP" 34 | "custom_fonts/font" 35 | "toggle_mode" 36 | "enabled_focus_mode" 37 | "shortcut" 38 | "text" 39 | "flat" 40 | "Button" 41 | "ServerTitle" 42 | "align" 43 | "valign" 44 | "percent_visible" 45 | "lines_skipped" 46 | "max_lines_visible" 47 | "Label" 48 | "BcastTCP" 49 | "ScrollContainer" 50 | "scroll/horizontal" 51 | "scroll/vertical" 52 | "ServerLog" 53 | "ENetNode" 54 | "signal_mode" 55 | "Client" 56 | "anchor/top" 57 | "editor/display_folded" 58 | "RemoveClient" 59 | "ClientTitle" 60 | "AddClient" 61 | "Container" 62 | "_on_BcastUDP_pressed" 63 | "pressed" 64 | "_on_BcastTCP_pressed" 65 | "_on_RemoveClient_pressed" 66 | "_on_AddClient_pressed" 67 | 68 | "node_count" 69 | 15 70 | "node_paths" 71 | 72 | 73 | "nodes" 74 | -1, -1, 0, 0, -1, 11, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 8, 4, 9, 4, 10, 4, 11, 5, 0, 0, 0, 0, 12, -1, 10, 1, 0, 2, 3, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 8, 4, 9, 4, 10, 6, 0, 1, 0, 13, 13, -1, 11, 1, 0, 3, 1, 4, 1, 5, 3, 6, 3, 7, 4, 8, 4, 9, 4, 10, 7, 14, 8, 15, 0, 0, 2, 0, 23, 16, -1, 14, 3, 1, 4, 2, 5, 3, 6, 3, 7, 9, 8, 4, 9, 10, 10, 7, 17, 11, 18, 1, 19, 3, 20, 12, 21, 13, 22, 1, 0, 2, 0, 30, 24, -1, 15, 3, 2, 4, 2, 5, 3, 6, 14, 7, 15, 8, 16, 9, 17, 10, 18, 17, 19, 21, 20, 25, 0, 26, 0, 27, 21, 28, 14, 29, 22, 0, 2, 0, 23, 31, -1, 14, 3, 1, 4, 2, 5, 3, 6, 3, 7, 23, 8, 4, 9, 24, 10, 7, 17, 11, 18, 1, 19, 3, 20, 12, 21, 25, 22, 1, 0, 1, 0, 32, 32, -1, 12, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 8, 7, 9, 4, 10, 4, 33, 2, 34, 2, 0, 6, 0, 30, 35, -1, 12, 3, 1, 4, 2, 5, 3, 6, 3, 7, 26, 8, 26, 9, 4, 10, 27, 17, 19, 27, 21, 28, 14, 29, 22, 0, 6, 0, 36, 36, -1, 1, 37, 0, 0, 0, 0, 0, 38, -1, 11, 39, 3, 1, 0, 2, 0, 3, 2, 4, 2, 5, 3, 6, 14, 7, 4, 8, 6, 9, 4, 10, 4, 0, 9, 0, 13, 13, -1, 12, 40, 2, 1, 0, 3, 1, 4, 1, 5, 3, 6, 3, 7, 4, 8, 4, 9, 4, 10, 7, 14, 8, 15, 0, 0, 10, 0, 23, 41, -1, 13, 3, 1, 4, 2, 5, 3, 6, 3, 7, 28, 8, 4, 9, 29, 10, 7, 18, 1, 19, 3, 20, 12, 21, 30, 22, 1, 0, 10, 0, 30, 42, -1, 15, 3, 2, 4, 2, 5, 3, 6, 14, 7, 31, 8, 16, 9, 32, 10, 18, 17, 19, 21, 33, 25, 0, 26, 0, 27, 21, 28, 14, 29, 22, 0, 10, 0, 23, 43, -1, 13, 3, 1, 4, 2, 5, 3, 6, 3, 7, 34, 8, 4, 9, 35, 10, 7, 18, 1, 19, 3, 20, 12, 21, 36, 22, 1, 0, 9, 0, 13, 44, -1, 11, 1, 0, 2, 0, 3, 1, 4, 1, 5, 3, 6, 3, 7, 4, 8, 7, 9, 4, 10, 4, 15, 14, 0 75 | "variants" 76 | 77 | 1 78 | False 79 | True 80 | 2 81 | 0 82 | 83 | 0.5 84 | 50 85 | 20 86 | 282 87 | 426 88 | 89 | "Broacast UDP" 90 | 0 91 | 446 92 | 15 93 | 566 94 | 34 95 | 96 | "Server Log" 97 | 1 98 | -1 99 | 586 100 | 741 101 | "Broadcast TCP" 102 | -0 103 | 19 104 | 334 105 | 439 106 | "Remove Client" 107 | 459 108 | 591 109 | "Client Logs" 110 | 611 111 | 689 112 | "Add Client" 113 | 114 | "version" 115 | 2 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /modules/benet/SCsub: -------------------------------------------------------------------------------- 1 | Import('env') 2 | Import('env_modules') 3 | 4 | # Thirdparty source files 5 | 6 | env_benet = env_modules.Clone() 7 | 8 | if env["builtin_enet"]: # builtin 9 | thirdparty_dir = "#thirdparty/enet/" 10 | thirdparty_sources = [ 11 | "callbacks.c", 12 | "compress.c", 13 | "host.c", 14 | "list.c", 15 | "packet.c", 16 | "peer.c", 17 | "protocol.c", 18 | "godot.cpp" 19 | ] 20 | thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] 21 | 22 | # env_benet.add_source_files(env.modules_sources, thirdparty_sources) 23 | env_benet.Append(CPPPATH=[thirdparty_dir]) 24 | env_benet.Append(CPPFLAGS=["-DGODOT_ENET"]) 25 | 26 | env_benet.add_source_files(env.modules_sources, "*.cpp") 27 | -------------------------------------------------------------------------------- /modules/benet/config.py: -------------------------------------------------------------------------------- 1 | def can_build(env, platform): 2 | return True 3 | 4 | 5 | def configure(env): 6 | pass 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /modules/benet/enet_node.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "modules/benet/enet_node.h" 3 | #include "core/engine.h" 4 | 5 | void ENetNode::_notification(int p_what) { 6 | if(!is_inside_tree() || Engine::get_singleton()->is_editor_hint() || !network_peer.is_valid()) 7 | return; 8 | 9 | if(p_what == NOTIFICATION_PHYSICS_PROCESS) { 10 | if(poll_mode == MODE_PHYSICS) 11 | _network_poll(); 12 | if(signal_mode == MODE_PHYSICS) 13 | _network_process(); 14 | } else if (p_what == NOTIFICATION_PROCESS) { 15 | if(poll_mode == MODE_IDLE) 16 | _network_poll(); 17 | if(signal_mode == MODE_IDLE) 18 | _network_process(); 19 | } 20 | } 21 | 22 | void ENetNode::_update_process_mode() { 23 | 24 | bool idle = signal_mode == MODE_IDLE || poll_mode == MODE_IDLE; 25 | bool physics = signal_mode == MODE_PHYSICS || poll_mode == MODE_PHYSICS; 26 | 27 | if (is_physics_processing() && !physics) { 28 | set_physics_process(false); 29 | } 30 | if (is_processing() && !idle) { 31 | set_process(false); 32 | } 33 | 34 | if(idle && !is_processing()) { 35 | set_process(true); 36 | } 37 | if(physics && !is_physics_processing()) { 38 | set_physics_process(true); 39 | } 40 | } 41 | 42 | void ENetNode::set_signal_mode(NetProcessMode p_mode) { 43 | 44 | if(signal_mode == p_mode) 45 | return; 46 | 47 | signal_mode = p_mode; 48 | 49 | _update_process_mode(); 50 | } 51 | 52 | ENetNode::NetProcessMode ENetNode::get_signal_mode() const{ 53 | return signal_mode; 54 | } 55 | 56 | void ENetNode::set_poll_mode(NetProcessMode p_mode) { 57 | 58 | if(poll_mode == p_mode) 59 | return; 60 | 61 | poll_mode = p_mode; 62 | 63 | _update_process_mode(); 64 | } 65 | 66 | ENetNode::NetProcessMode ENetNode::get_poll_mode() const{ 67 | return poll_mode; 68 | } 69 | 70 | void ENetNode::set_network_peer(const Ref& p_network_peer) { 71 | if (network_peer.is_valid()) { 72 | network_peer->disconnect("peer_connected",this,"_network_peer_connected"); 73 | network_peer->disconnect("peer_disconnected",this,"_network_peer_disconnected"); 74 | network_peer->disconnect("connection_succeeded",this,"_connected_to_server"); 75 | network_peer->disconnect("connection_failed",this,"_connection_failed"); 76 | network_peer->disconnect("server_disconnected",this,"_server_disconnected"); 77 | connected_peers.clear(); 78 | //path_get_cache.clear(); 79 | //path_send_cache.clear(); 80 | //last_send_cache_id=1; 81 | } 82 | 83 | ERR_FAIL_COND_MSG(p_network_peer.is_valid() && p_network_peer->get_connection_status()==NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, "Supplied NetworkedNetworkPeer must be connecting or connected."); 84 | 85 | network_peer=p_network_peer; 86 | 87 | if (network_peer.is_valid()) { 88 | network_peer->connect("peer_connected",this,"_network_peer_connected"); 89 | network_peer->connect("peer_disconnected",this,"_network_peer_disconnected"); 90 | network_peer->connect("connection_succeeded",this,"_connected_to_server"); 91 | network_peer->connect("connection_failed",this,"_connection_failed"); 92 | network_peer->connect("server_disconnected",this,"_server_disconnected"); 93 | } 94 | } 95 | 96 | bool ENetNode::is_network_server() const { 97 | 98 | ERR_FAIL_COND_V(!network_peer.is_valid(),false); 99 | return network_peer->is_server(); 100 | 101 | } 102 | 103 | int ENetNode::get_network_unique_id() const { 104 | 105 | ERR_FAIL_COND_V(!network_peer.is_valid(),0); 106 | return network_peer->get_unique_id(); 107 | } 108 | 109 | Error ENetNode::kick_client(int p_id) { 110 | 111 | ERR_FAIL_COND_V(!network_peer.is_valid(),ERR_UNCONFIGURED); 112 | 113 | return network_peer->disconnect_peer(p_id); 114 | } 115 | 116 | void ENetNode::_network_peer_connected(int p_id) { 117 | 118 | connected_peers.insert(p_id); 119 | //path_get_cache.insert(p_id,PathGetCache()); 120 | emit_signal("network_peer_connected",p_id); 121 | } 122 | 123 | void ENetNode::_network_peer_disconnected(int p_id) { 124 | 125 | connected_peers.erase(p_id); 126 | //path_get_cache.erase(p_id); //I no longer need your cache, sorry 127 | emit_signal("network_peer_disconnected",p_id); 128 | } 129 | 130 | void ENetNode::_connected_to_server() { 131 | 132 | emit_signal("connected_to_server"); 133 | } 134 | 135 | void ENetNode::_connection_failed() { 136 | 137 | emit_signal("connection_failed"); 138 | } 139 | 140 | void ENetNode::_server_disconnected() { 141 | 142 | emit_signal("server_disconnected"); 143 | } 144 | 145 | Error ENetNode::broadcast(const PoolVector &p_packet, int p_channel) { 146 | return put_packet(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE, 0, p_packet, p_channel); 147 | } 148 | 149 | Error ENetNode::send(int p_id, const PoolVector &p_packet, int p_channel) { 150 | return put_packet(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE, p_id, p_packet, p_channel); 151 | } 152 | 153 | Error ENetNode::broadcast_unreliable(const PoolVector &p_packet, int p_channel) { 154 | return put_packet(NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE, 0, p_packet, p_channel); 155 | } 156 | 157 | Error ENetNode::send_unreliable(int p_id, const PoolVector &p_packet, int p_channel) { 158 | return put_packet(NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE, p_id, p_packet, p_channel); 159 | } 160 | 161 | Error ENetNode::broadcast_ordered(const PoolVector &p_packet, int p_channel) { 162 | return put_packet(NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED, 0, p_packet, p_channel); 163 | } 164 | 165 | Error ENetNode::send_ordered(int p_id, const PoolVector &p_packet, int p_channel) { 166 | return put_packet(NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED, p_id, p_packet, p_channel); 167 | } 168 | 169 | Error ENetNode::put_packet(NetworkedMultiplayerPeer::TransferMode p_mode, int p_target, const PoolVector &p_packet, int p_channel) { 170 | ERR_FAIL_COND_V(!network_peer.is_valid(),ERR_UNCONFIGURED); 171 | 172 | network_peer->set_transfer_mode(p_mode); 173 | network_peer->set_target_peer(p_target); 174 | return network_peer->_put_packet_channel(p_packet, p_channel); 175 | } 176 | 177 | void ENetNode::_network_poll() { 178 | 179 | if (!network_peer.is_valid() || network_peer->get_connection_status()==NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) 180 | return; 181 | 182 | network_peer->poll(); 183 | } 184 | 185 | void ENetNode::_network_process() { 186 | 187 | if (!network_peer.is_valid() || network_peer->get_connection_status()==NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) 188 | return; 189 | 190 | while(network_peer->get_available_packet_count()) { 191 | 192 | int sender = network_peer->get_packet_peer(); 193 | int channel = network_peer->get_packet_channel(); 194 | 195 | if(channel==-1) { 196 | 197 | int len; 198 | const uint8_t *packet; 199 | 200 | Error err = network_peer->get_packet(&packet,len); 201 | if (err!=OK) { 202 | ERR_PRINT("Error getting packet!"); 203 | } 204 | 205 | _network_process_packet(sender,packet,len); 206 | 207 | } else { 208 | 209 | PoolVector pkt; 210 | 211 | Error err = network_peer->get_packet_buffer(pkt); 212 | if (err!=OK) { 213 | ERR_PRINT("Error getting packet!"); 214 | } 215 | 216 | if(sender == 1) { 217 | emit_signal("server_packet", channel, pkt); 218 | } 219 | else { 220 | emit_signal("peer_packet", sender, channel, pkt); 221 | } 222 | 223 | } 224 | 225 | if (!network_peer.is_valid()) { 226 | break; //it's also possible that a packet or RPC caused a disconnection, so also check here 227 | } 228 | } 229 | 230 | 231 | } 232 | 233 | void ENetNode::_network_process_packet(int p_from, const uint8_t* p_packet, int p_packet_len) { 234 | // Not implemented yet! 235 | /* 236 | ERR_FAIL_COND(p_packet_len<5); 237 | 238 | uint8_t packet_type = p_packet[0]; 239 | 240 | switch(packet_type) { 241 | 242 | case NETWORK_COMMAND_REMOTE_CALL: 243 | case NETWORK_COMMAND_REMOTE_SET: { 244 | 245 | ERR_FAIL_COND(p_packet_len<5); 246 | uint32_t target = decode_uint32(&p_packet[1]); 247 | 248 | 249 | Node *node=NULL; 250 | 251 | if (target&0x80000000) { 252 | 253 | int ofs = target&0x7FFFFFFF; 254 | ERR_FAIL_COND(ofs>=p_packet_len); 255 | 256 | String paths; 257 | paths.parse_utf8((const char*)&p_packet[ofs],p_packet_len-ofs); 258 | 259 | NodePath np = paths; 260 | 261 | node = get_root()->get_node(np); 262 | if (node==NULL) { 263 | ERR_EXPLAIN("Failed to get path from RPC: "+String(np)); 264 | ERR_FAIL_COND(node==NULL); 265 | } 266 | } else { 267 | 268 | int id = target; 269 | 270 | Map::Element *E=path_get_cache.find(p_from); 271 | ERR_FAIL_COND(!E); 272 | 273 | Map::Element *F=E->get().nodes.find(id); 274 | ERR_FAIL_COND(!F); 275 | 276 | PathGetCache::NodeInfo *ni = &F->get(); 277 | //do proper caching later 278 | 279 | node = get_root()->get_node(ni->path); 280 | if (node==NULL) { 281 | ERR_EXPLAIN("Failed to get cached path from RPC: "+String(ni->path)); 282 | ERR_FAIL_COND(node==NULL); 283 | } 284 | 285 | 286 | } 287 | 288 | ERR_FAIL_COND(p_packet_len<6); 289 | 290 | //detect cstring end 291 | int len_end=5; 292 | for(;len_end=p_packet_len); 299 | 300 | StringName name = String::utf8((const char*)&p_packet[5]); 301 | 302 | 303 | 304 | 305 | if (packet_type==NETWORK_COMMAND_REMOTE_CALL) { 306 | 307 | if (!node->can_call_rpc(name)) 308 | return; 309 | 310 | int ofs = len_end+1; 311 | 312 | ERR_FAIL_COND(ofs>=p_packet_len); 313 | 314 | int argc = p_packet[ofs]; 315 | Vector args; 316 | Vector argp; 317 | args.resize(argc); 318 | argp.resize(argc); 319 | 320 | ofs++; 321 | 322 | for(int i=0;i=p_packet_len); 325 | int vlen; 326 | Error err = decode_variant(args[i],&p_packet[ofs],p_packet_len-ofs,&vlen); 327 | ERR_FAIL_COND(err!=OK); 328 | //args[i]=p_packet[3+i]; 329 | argp[i]=&args[i]; 330 | ofs+=vlen; 331 | } 332 | 333 | Variant::CallError ce; 334 | 335 | node->call(name,argp.ptr(),argc,ce); 336 | if (ce.error!=Variant::CallError::CALL_OK) { 337 | String error = Variant::get_call_error_text(node,name,argp.ptr(),argc,ce); 338 | error="RPC - "+error; 339 | ERR_PRINTS(error); 340 | } 341 | 342 | } else { 343 | 344 | if (!node->can_call_rset(name)) 345 | return; 346 | 347 | int ofs = len_end+1; 348 | 349 | ERR_FAIL_COND(ofs>=p_packet_len); 350 | 351 | Variant value; 352 | decode_variant(value,&p_packet[ofs],p_packet_len-ofs); 353 | 354 | bool valid; 355 | 356 | node->set(name,value,&valid); 357 | if (!valid) { 358 | String error = "Error setting remote property '"+String(name)+"', not found in object of type "+node->get_type(); 359 | ERR_PRINTS(error); 360 | } 361 | } 362 | 363 | } break; 364 | case NETWORK_COMMAND_SIMPLIFY_PATH: { 365 | 366 | ERR_FAIL_COND(p_packet_len<5); 367 | int id = decode_uint32(&p_packet[1]); 368 | 369 | String paths; 370 | paths.parse_utf8((const char*)&p_packet[5],p_packet_len-5); 371 | 372 | NodePath path = paths; 373 | 374 | if (!path_get_cache.has(p_from)) { 375 | path_get_cache[p_from]=PathGetCache(); 376 | } 377 | 378 | PathGetCache::NodeInfo ni; 379 | ni.path=path; 380 | ni.instance=0; 381 | 382 | path_get_cache[p_from].nodes[id]=ni; 383 | 384 | 385 | { 386 | //send ack 387 | 388 | //encode path 389 | CharString pname = String(path).utf8(); 390 | int len = encode_cstring(pname.get_data(),NULL); 391 | 392 | Vector packet; 393 | 394 | packet.resize(1+len); 395 | packet[0]=NETWORK_COMMAND_CONFIRM_PATH; 396 | encode_cstring(pname.get_data(),&packet[1]); 397 | 398 | network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); 399 | network_peer->set_target_peer(p_from); 400 | network_peer->put_packet(packet.ptr(),packet.size(),0); 401 | } 402 | } break; 403 | case NETWORK_COMMAND_CONFIRM_PATH: { 404 | 405 | String paths; 406 | paths.parse_utf8((const char*)&p_packet[1],p_packet_len-1); 407 | 408 | NodePath path = paths; 409 | 410 | PathSentCache *psc = path_send_cache.getptr(path); 411 | ERR_FAIL_COND(!psc); 412 | 413 | Map::Element *E=psc->confirmed_peers.find(p_from); 414 | ERR_FAIL_COND(!E); 415 | E->get()=true; 416 | } break; 417 | } 418 | */ 419 | } 420 | 421 | void ENetNode::_bind_methods() { 422 | ADD_SIGNAL( MethodInfo("network_peer_connected",PropertyInfo(Variant::INT,"id"))); 423 | ADD_SIGNAL( MethodInfo("network_peer_disconnected",PropertyInfo(Variant::INT,"id"))); 424 | 425 | ADD_SIGNAL( MethodInfo("connected_to_server")); 426 | ADD_SIGNAL( MethodInfo("connection_failed")); 427 | ADD_SIGNAL( MethodInfo("server_disconnected")); 428 | 429 | ADD_SIGNAL( MethodInfo("server_packet",PropertyInfo(Variant::INT,"channel"),PropertyInfo(Variant::POOL_BYTE_ARRAY,"packet"))); 430 | ADD_SIGNAL( MethodInfo("peer_packet",PropertyInfo(Variant::INT,"peer"),PropertyInfo(Variant::INT,"channel"),PropertyInfo(Variant::POOL_BYTE_ARRAY,"packet"))); 431 | 432 | ClassDB::bind_method(D_METHOD("set_network_peer","peer"),&ENetNode::set_network_peer); 433 | ClassDB::bind_method(D_METHOD("_network_peer_connected"),&ENetNode::_network_peer_connected); 434 | ClassDB::bind_method(D_METHOD("_network_peer_disconnected"),&ENetNode::_network_peer_disconnected); 435 | ClassDB::bind_method(D_METHOD("_connected_to_server"),&ENetNode::_connected_to_server); 436 | ClassDB::bind_method(D_METHOD("_connection_failed"),&ENetNode::_connection_failed); 437 | ClassDB::bind_method(D_METHOD("_server_disconnected"),&ENetNode::_server_disconnected); 438 | 439 | // Basic infos 440 | ClassDB::bind_method(D_METHOD("is_network_server"),&ENetNode::is_network_server); 441 | ClassDB::bind_method(D_METHOD("get_network_unique_id"),&ENetNode::get_network_unique_id); 442 | 443 | 444 | // Signal Handling 445 | BIND_ENUM_CONSTANT(MODE_IDLE); 446 | BIND_ENUM_CONSTANT(MODE_PHYSICS); 447 | ClassDB::bind_method(D_METHOD("set_signal_mode","mode"),&ENetNode::set_signal_mode); 448 | ClassDB::bind_method(D_METHOD("get_signal_mode"),&ENetNode::get_signal_mode); 449 | ADD_PROPERTY( PropertyInfo(Variant::INT,"signal_mode",PROPERTY_HINT_ENUM,"Idle,Fixed"),"set_signal_mode","get_signal_mode"); 450 | ClassDB::bind_method(D_METHOD("set_poll_mode","mode"),&ENetNode::set_poll_mode); 451 | ClassDB::bind_method(D_METHOD("get_poll_mode"),&ENetNode::get_poll_mode); 452 | ADD_PROPERTY( PropertyInfo(Variant::INT,"poll_mode",PROPERTY_HINT_ENUM,"Idle,Fixed"),"set_poll_mode","get_poll_mode"); 453 | 454 | 455 | // General purpose method 456 | ClassDB::bind_method(D_METHOD("put_packet", "mode", "target", "pkt","channel"),&ENetNode::put_packet); 457 | ClassDB::bind_method(D_METHOD("kick_client", "id"),&ENetNode::kick_client); 458 | 459 | // Reliable 460 | ClassDB::bind_method(D_METHOD("broadcast", "pkt","channel"),&ENetNode::broadcast); 461 | ClassDB::bind_method(D_METHOD("send", "target", "pkt","channel"),&ENetNode::send); 462 | // Unreliable 463 | ClassDB::bind_method(D_METHOD("broadcast_unreliable", "pkt","channel"),&ENetNode::broadcast_unreliable); 464 | ClassDB::bind_method(D_METHOD("send_unreliable", "target", "pkt","channel"),&ENetNode::send_unreliable); 465 | // Ordered 466 | ClassDB::bind_method(D_METHOD("broadcast_ordered", "pkt","channel"),&ENetNode::broadcast_ordered); 467 | ClassDB::bind_method(D_METHOD("send_ordered", "target", "pkt","channel"),&ENetNode::send_ordered); 468 | } 469 | 470 | ENetNode::ENetNode() { 471 | poll_mode = MODE_IDLE; 472 | signal_mode = MODE_IDLE; 473 | 474 | network_peer = Ref(); 475 | 476 | _update_process_mode(); 477 | } 478 | 479 | ENetNode::~ENetNode() { 480 | 481 | } 482 | 483 | 484 | -------------------------------------------------------------------------------- /modules/benet/enet_node.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORKED_MULTIPLAYER_NODE_H 2 | #define NETWORKED_MULTIPLAYER_NODE_H 3 | 4 | #include "scene/main/node.h" 5 | #include "core/io/networked_multiplayer_peer.h" 6 | #include "modules/benet/enet_packet_peer.h" 7 | 8 | class ENetNode: public Node { 9 | 10 | GDCLASS( ENetNode, Node ); 11 | 12 | public: 13 | 14 | enum NetProcessMode { 15 | MODE_IDLE, 16 | MODE_PHYSICS 17 | }; 18 | 19 | private: 20 | 21 | Ref network_peer; 22 | Set connected_peers; 23 | NetProcessMode poll_mode; 24 | NetProcessMode signal_mode; 25 | 26 | void _network_poll(); 27 | void _network_process(); 28 | void _network_process_packet(int p_from, const uint8_t* p_packet, int p_packet_len); 29 | 30 | void _network_peer_connected(int p_id); 31 | void _network_peer_disconnected(int p_id); 32 | 33 | void _connected_to_server(); 34 | void _connection_failed(); 35 | void _server_disconnected(); 36 | void _update_process_mode(); 37 | 38 | protected: 39 | void _notification(int p_what); 40 | static void _bind_methods(); 41 | 42 | public: 43 | 44 | void set_network_peer(const Ref& p_network_peer); 45 | 46 | void set_signal_mode(NetProcessMode p_mode); 47 | NetProcessMode get_signal_mode() const; 48 | void set_poll_mode(NetProcessMode p_mode); 49 | NetProcessMode get_poll_mode() const; 50 | 51 | bool is_network_server() const; 52 | int get_network_unique_id() const; 53 | Error kick_client(int p_id); 54 | 55 | Error broadcast(const PoolVector &p_packet, int p_channel=0); 56 | Error send(int p_id, const PoolVector &p_packet, int p_channel=0); 57 | Error broadcast_unreliable(const PoolVector &p_packet, int p_channel=0); 58 | Error send_unreliable(int p_id, const PoolVector &p_packet, int p_channel=0); 59 | Error broadcast_ordered(const PoolVector &p_packet, int p_channel=0); 60 | Error send_ordered(int p_id, const PoolVector &p_packet, int p_channel=0); 61 | Error put_packet(NetworkedMultiplayerPeer::TransferMode p_mode, int p_target, const PoolVector &p_packet, int p_channel=0); 62 | 63 | ENetNode(); 64 | ~ENetNode(); 65 | 66 | }; 67 | 68 | VARIANT_ENUM_CAST(ENetNode::NetProcessMode); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /modules/benet/enet_packet_peer.cpp: -------------------------------------------------------------------------------- 1 | #include "enet_packet_peer.h" 2 | #include "core/io/marshalls.h" 3 | #include "core/os/os.h" 4 | 5 | void ENetPacketPeer::set_transfer_mode(TransferMode p_mode) { 6 | 7 | transfer_mode = p_mode; 8 | } 9 | 10 | NetworkedMultiplayerPeer::TransferMode ENetPacketPeer::get_transfer_mode() const { 11 | 12 | return transfer_mode; 13 | } 14 | 15 | void ENetPacketPeer::set_target_peer(int p_peer) { 16 | 17 | target_peer = p_peer; 18 | } 19 | 20 | int ENetPacketPeer::get_packet_peer() const { 21 | 22 | ERR_FAIL_COND_V(!active, 1); 23 | ERR_FAIL_COND_V(incoming_packets.size() == 0, 1); 24 | 25 | return incoming_packets.front()->get().from; 26 | } 27 | 28 | int ENetPacketPeer::get_packet_channel() const { 29 | 30 | ERR_FAIL_COND_V(!active, 1); 31 | ERR_FAIL_COND_V(incoming_packets.size() == 0, 1); 32 | 33 | return incoming_packets.front()->get().channel; 34 | } 35 | 36 | Error ENetPacketPeer::disconnect_peer(int p_id) { 37 | 38 | ERR_FAIL_COND_V(!active, ERR_UNCONFIGURED); 39 | ERR_FAIL_COND_V(!peer_map.has(p_id), ERR_DOES_NOT_EXIST); 40 | 41 | enet_peer_disconnect(peer_map[p_id], 0); 42 | return OK; 43 | } 44 | 45 | Error ENetPacketPeer::create_server(int p_port, int p_channels, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) { 46 | 47 | ERR_FAIL_COND_V(active, ERR_ALREADY_IN_USE); 48 | 49 | ENetAddress address; 50 | 51 | #ifdef GODOT_ENET 52 | if (bind_ip.is_wildcard()) { 53 | address.wildcard = 1; 54 | } else { 55 | enet_address_set_ip(&address, bind_ip.get_ipv6(), 16); 56 | } 57 | #else 58 | if (bind_ip.is_wildcard()) { 59 | address.host = 0; 60 | } else { 61 | ERR_FAIL_COND_V(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER); 62 | address.host = *(uint32_t *)bind_ip.get_ipv4(); 63 | } 64 | #endif 65 | address.port = p_port; 66 | 67 | host = enet_host_create(&address /* the address to bind the server host to */, 68 | p_max_clients /* allow up to 32 clients and/or outgoing connections */, 69 | p_channels + SYSCH_MAX /* allow up to SYSCH_MAX channels to be used */, 70 | p_in_bandwidth /* assume any amount of incoming bandwidth */, 71 | p_out_bandwidth /* assume any amount of outgoing bandwidth */); 72 | 73 | ERR_FAIL_COND_V(!host, ERR_CANT_CREATE); 74 | 75 | _setup_compressor(); 76 | active = true; 77 | server = true; 78 | refuse_connections = false; 79 | channels = p_channels + SYSCH_MAX; 80 | unique_id = 1; 81 | connection_status = CONNECTION_CONNECTED; 82 | return OK; 83 | } 84 | Error ENetPacketPeer::create_client(const IP_Address &p_ip, int p_port, int p_channels, int p_in_bandwidth, int p_out_bandwidth) { 85 | 86 | ERR_FAIL_COND_V(active, ERR_ALREADY_IN_USE); 87 | 88 | host = enet_host_create(NULL /* create a client host */, 89 | 1 /* only allow 1 outgoing connection */, 90 | p_channels + SYSCH_MAX /* allow up to SYSCH_MAX channels to be used */, 91 | p_in_bandwidth /* 56K modem with 56 Kbps downstream bandwidth */, 92 | p_out_bandwidth /* 56K modem with 14 Kbps upstream bandwidth */); 93 | 94 | ERR_FAIL_COND_V(!host, ERR_CANT_CREATE); 95 | 96 | _setup_compressor(); 97 | 98 | ENetAddress address; 99 | #ifdef GODOT_ENET 100 | enet_address_set_ip(&address, p_ip.get_ipv6(), 16); 101 | #else 102 | ERR_FAIL_COND_V(!p_ip.is_ipv4(), ERR_INVALID_PARAMETER); 103 | address.host = *(uint32_t *)p_ip.get_ipv4(); 104 | #endif 105 | address.port = p_port; 106 | 107 | //enet_address_set_host (& address, "localhost"); 108 | //address.port = p_port; 109 | 110 | unique_id = _gen_unique_id(); 111 | 112 | /* Initiate the connection, allocating the enough channels */ 113 | ENetPeer *peer = enet_host_connect(host, &address, p_channels + SYSCH_MAX, unique_id); 114 | 115 | if (peer == NULL) { 116 | enet_host_destroy(host); 117 | ERR_FAIL_COND_V(!peer, ERR_CANT_CREATE); 118 | } 119 | 120 | //technically safe to ignore the peer or anything else. 121 | 122 | connection_status = CONNECTION_CONNECTING; 123 | active = true; 124 | server = false; 125 | refuse_connections = false; 126 | channels = p_channels + SYSCH_MAX; 127 | 128 | return OK; 129 | } 130 | 131 | void ENetPacketPeer::poll() { 132 | 133 | ERR_FAIL_COND(!active); 134 | 135 | _pop_current_packet(); 136 | 137 | ENetEvent event; 138 | /* Wait up to 1000 milliseconds for an event. */ 139 | while (true) { 140 | 141 | if (!host || !active) //might have been disconnected while emitting a notification 142 | return; 143 | 144 | int ret = enet_host_service(host, &event, 1); 145 | 146 | if (ret < 0) { 147 | //error, do something? 148 | break; 149 | } else if (ret == 0) { 150 | break; 151 | } 152 | 153 | switch (event.type) { 154 | case ENET_EVENT_TYPE_CONNECT: { 155 | /* Store any relevant client information here. */ 156 | 157 | if (server && refuse_connections) { 158 | enet_peer_reset(event.peer); 159 | break; 160 | } 161 | 162 | int *new_id = memnew(int); 163 | *new_id = event.data; 164 | 165 | if (*new_id == 0) { //data zero is sent by server (enet won't let you configure this). Server is always 1 166 | *new_id = 1; 167 | } 168 | 169 | event.peer->data = new_id; 170 | 171 | peer_map[*new_id] = event.peer; 172 | 173 | connection_status = CONNECTION_CONNECTED; //if connecting, this means it connected t something! 174 | 175 | emit_signal("peer_connected", *new_id); 176 | 177 | if (server) { 178 | //someone connected, let it know of all the peers available 179 | for (Map::Element *E = peer_map.front(); E; E = E->next()) { 180 | 181 | if (E->key() == *new_id) 182 | continue; 183 | //send existing peers to new peer 184 | ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE); 185 | encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]); 186 | encode_uint32(E->key(), &packet->data[4]); 187 | enet_peer_send(event.peer, SYSCH_CONFIG, packet); 188 | //send the new peer to existing peers 189 | packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE); 190 | encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]); 191 | encode_uint32(*new_id, &packet->data[4]); 192 | enet_peer_send(E->get(), SYSCH_CONFIG, packet); 193 | } 194 | } else { 195 | 196 | emit_signal("connection_succeeded"); 197 | } 198 | 199 | } break; 200 | case ENET_EVENT_TYPE_DISCONNECT: { 201 | 202 | /* Reset the peer's client information. */ 203 | 204 | int *id = (int *)event.peer->data; 205 | 206 | if (!id) { 207 | if (!server) { 208 | emit_signal("connection_failed"); 209 | } 210 | } else { 211 | 212 | if (server) { 213 | //someone disconnected, let it know to everyone else 214 | for (Map::Element *E = peer_map.front(); E; E = E->next()) { 215 | 216 | if (E->key() == *id) 217 | continue; 218 | //send the new peer to existing peers 219 | ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE); 220 | encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]); 221 | encode_uint32(*id, &packet->data[4]); 222 | enet_peer_send(E->get(), SYSCH_CONFIG, packet); 223 | } 224 | } else if (!server) { 225 | emit_signal("server_disconnected"); 226 | close_connection(); 227 | return; 228 | } 229 | 230 | emit_signal("peer_disconnected", *id); 231 | peer_map.erase(*id); 232 | memdelete(id); 233 | } 234 | 235 | } break; 236 | case ENET_EVENT_TYPE_RECEIVE: { 237 | 238 | if (event.channelID == SYSCH_CONFIG) { 239 | //some config message 240 | ERR_CONTINUE(event.packet->dataLength < 8); 241 | 242 | // Only server can send config messages 243 | ERR_CONTINUE(server); 244 | 245 | int msg = decode_uint32(&event.packet->data[0]); 246 | int id = decode_uint32(&event.packet->data[4]); 247 | 248 | switch (msg) { 249 | case SYSMSG_ADD_PEER: { 250 | 251 | peer_map[id] = NULL; 252 | emit_signal("peer_connected", id); 253 | 254 | } break; 255 | case SYSMSG_REMOVE_PEER: { 256 | 257 | peer_map.erase(id); 258 | emit_signal("peer_disconnected", id); 259 | } break; 260 | } 261 | 262 | enet_packet_destroy(event.packet); 263 | } else { 264 | 265 | Packet packet; 266 | packet.packet = event.packet; 267 | packet.channel = -1; 268 | 269 | if (event.channelID >= SYSCH_MAX) { 270 | packet.channel = event.channelID - SYSCH_MAX; 271 | } 272 | 273 | uint32_t *id = (uint32_t *)event.peer->data; 274 | 275 | ERR_CONTINUE(event.packet->dataLength < 12) 276 | 277 | uint32_t source = decode_uint32(&event.packet->data[0]); 278 | int target = decode_uint32(&event.packet->data[4]); 279 | uint32_t flags = decode_uint32(&event.packet->data[8]); 280 | 281 | packet.from = source; 282 | 283 | if (server) { 284 | // Someone is cheating and trying to fake the source! 285 | ERR_CONTINUE(source != *id); 286 | 287 | packet.from = *id; 288 | 289 | if (target == 0) { 290 | //re-send the everyone but sender :| 291 | 292 | incoming_packets.push_back(packet); 293 | //and make copies for sending 294 | for (Map::Element *E = peer_map.front(); E; E = E->next()) { 295 | 296 | if (uint32_t(E->key()) == source) //do not resend to self 297 | continue; 298 | 299 | ENetPacket *packet2 = enet_packet_create(packet.packet->data, packet.packet->dataLength, flags); 300 | 301 | enet_peer_send(E->get(), event.channelID, packet2); 302 | } 303 | 304 | } else if (target < 0) { 305 | //to all but one 306 | 307 | //and make copies for sending 308 | for (Map::Element *E = peer_map.front(); E; E = E->next()) { 309 | 310 | if (uint32_t(E->key()) == source || E->key() == -target) //do not resend to self, also do not send to excluded 311 | continue; 312 | 313 | ENetPacket *packet2 = enet_packet_create(packet.packet->data, packet.packet->dataLength, flags); 314 | 315 | enet_peer_send(E->get(), event.channelID, packet2); 316 | } 317 | 318 | if (-target != 1) { 319 | //server is not excluded 320 | incoming_packets.push_back(packet); 321 | } else { 322 | //server is excluded, erase packet 323 | enet_packet_destroy(packet.packet); 324 | } 325 | 326 | } else if (target == 1) { 327 | //to myself and only myself 328 | incoming_packets.push_back(packet); 329 | } else { 330 | //to someone else, specifically 331 | ERR_CONTINUE(!peer_map.has(target)); 332 | enet_peer_send(peer_map[target], event.channelID, packet.packet); 333 | } 334 | } else { 335 | 336 | incoming_packets.push_back(packet); 337 | } 338 | //destroy packet later.. 339 | } 340 | } break; 341 | case ENET_EVENT_TYPE_NONE: { 342 | //do nothing 343 | } break; 344 | } 345 | } 346 | } 347 | 348 | bool ENetPacketPeer::is_server() const { 349 | ERR_FAIL_COND_V(!active, false); 350 | 351 | return server; 352 | } 353 | 354 | void ENetPacketPeer::close_connection() { 355 | 356 | if (!active) 357 | return; 358 | 359 | _pop_current_packet(); 360 | 361 | bool peers_disconnected = false; 362 | for (Map::Element *E = peer_map.front(); E; E = E->next()) { 363 | if (E->get()) { 364 | enet_peer_disconnect_now(E->get(), unique_id); 365 | peers_disconnected = true; 366 | } 367 | } 368 | 369 | if (peers_disconnected) { 370 | enet_host_flush(host); 371 | OS::get_singleton()->delay_usec(100); //wait 100ms for disconnection packets to send 372 | } 373 | 374 | enet_host_destroy(host); 375 | active = false; 376 | incoming_packets.clear(); 377 | unique_id = 1; //server is 1 378 | connection_status = CONNECTION_DISCONNECTED; 379 | } 380 | 381 | int ENetPacketPeer::get_available_packet_count() const { 382 | 383 | return incoming_packets.size(); 384 | } 385 | Error ENetPacketPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { 386 | 387 | ERR_FAIL_COND_V(incoming_packets.size() == 0, ERR_UNAVAILABLE); 388 | 389 | _pop_current_packet(); 390 | 391 | current_packet = incoming_packets.front()->get(); 392 | incoming_packets.pop_front(); 393 | 394 | *r_buffer = (const uint8_t *)(¤t_packet.packet->data[12]); 395 | r_buffer_size = current_packet.packet->dataLength - 12; 396 | 397 | return OK; 398 | } 399 | Error ENetPacketPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { 400 | 401 | int channel = SYSCH_RELIABLE; 402 | 403 | switch (transfer_mode) { 404 | case TRANSFER_MODE_UNRELIABLE: { 405 | channel = SYSCH_UNRELIABLE; 406 | } break; 407 | case TRANSFER_MODE_UNRELIABLE_ORDERED: { 408 | channel = SYSCH_UNRELIABLE; 409 | } break; 410 | case TRANSFER_MODE_RELIABLE: { 411 | channel = SYSCH_RELIABLE; 412 | } break; 413 | } 414 | 415 | return put_packet_channel(p_buffer, p_buffer_size, channel); 416 | } 417 | 418 | Error ENetPacketPeer::_put_packet_channel(const PoolVector &p_buffer, int p_channel) { 419 | 420 | int len = p_buffer.size(); 421 | if (len == 0) 422 | return OK; 423 | 424 | PoolVector::Read r = p_buffer.read(); 425 | return put_packet_channel(&r[0], len, p_channel + SYSCH_MAX); 426 | } 427 | 428 | Error ENetPacketPeer::put_packet_channel(const uint8_t *p_buffer, int p_buffer_size, int p_channel) { 429 | 430 | ERR_FAIL_COND_V(!active, ERR_UNCONFIGURED); 431 | ERR_FAIL_COND_V(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED); 432 | ERR_FAIL_COND_V(p_channel >= channels, ERR_INVALID_PARAMETER); 433 | 434 | int packet_flags = 0; 435 | 436 | switch (transfer_mode) { 437 | case TRANSFER_MODE_UNRELIABLE: { 438 | packet_flags = ENET_PACKET_FLAG_UNSEQUENCED; 439 | } break; 440 | case TRANSFER_MODE_UNRELIABLE_ORDERED: { 441 | packet_flags = 0; 442 | } break; 443 | case TRANSFER_MODE_RELIABLE: { 444 | packet_flags = ENET_PACKET_FLAG_RELIABLE; 445 | } break; 446 | } 447 | 448 | Map::Element *E = NULL; 449 | 450 | if (target_peer != 0) { 451 | 452 | E = peer_map.find(ABS(target_peer)); 453 | if (!E) { 454 | ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid Target Peer: " + itos(target_peer)); 455 | } 456 | } 457 | 458 | ENetPacket *packet = enet_packet_create(NULL, p_buffer_size + 12, packet_flags); 459 | encode_uint32(unique_id, &packet->data[0]); //source ID 460 | encode_uint32(target_peer, &packet->data[4]); //dest ID 461 | encode_uint32(packet_flags, &packet->data[8]); //dest ID 462 | copymem(&packet->data[12], p_buffer, p_buffer_size); 463 | 464 | if (server) { 465 | 466 | if (target_peer == 0) { 467 | enet_host_broadcast(host, p_channel, packet); 468 | } else if (target_peer < 0) { 469 | //send to all but one 470 | //and make copies for sending 471 | 472 | int exclude = -target_peer; 473 | 474 | for (Map::Element *F = peer_map.front(); F; F = F->next()) { 475 | 476 | if (F->key() == exclude) // exclude packet 477 | continue; 478 | 479 | ENetPacket *packet2 = enet_packet_create(packet->data, packet->dataLength, packet_flags); 480 | 481 | enet_peer_send(F->get(), p_channel, packet2); 482 | } 483 | 484 | enet_packet_destroy(packet); //original packet no longer needed 485 | } else { 486 | enet_peer_send(E->get(), p_channel, packet); 487 | } 488 | } else { 489 | 490 | ERR_FAIL_COND_V(!peer_map.has(1), ERR_BUG); 491 | enet_peer_send(peer_map[1], p_channel, packet); //send to server for broadcast.. 492 | } 493 | 494 | enet_host_flush(host); 495 | 496 | return OK; 497 | } 498 | 499 | int ENetPacketPeer::get_max_packet_size() const { 500 | 501 | return 1 << 24; //anything is good 502 | } 503 | 504 | void ENetPacketPeer::_pop_current_packet() { 505 | 506 | if (current_packet.packet) { 507 | enet_packet_destroy(current_packet.packet); 508 | current_packet.packet = NULL; 509 | current_packet.from = 0; 510 | } 511 | } 512 | 513 | NetworkedMultiplayerPeer::ConnectionStatus ENetPacketPeer::get_connection_status() const { 514 | 515 | return connection_status; 516 | } 517 | 518 | uint32_t ENetPacketPeer::_gen_unique_id() const { 519 | 520 | uint32_t hash = 0; 521 | 522 | while (hash == 0 || hash == 1) { 523 | 524 | hash = hash_djb2_one_32( 525 | (uint32_t)OS::get_singleton()->get_ticks_usec()); 526 | hash = hash_djb2_one_32( 527 | (uint32_t)OS::get_singleton()->get_unix_time(), hash); 528 | hash = hash_djb2_one_32( 529 | (uint32_t)OS::get_singleton()->get_data_path().hash64(), hash); 530 | /* 531 | hash = hash_djb2_one_32( 532 | (uint32_t)OS::get_singleton()->get_unique_ID().hash64(), hash ); 533 | */ 534 | hash = hash_djb2_one_32( 535 | (uint32_t)((uint64_t)this), hash); //rely on aslr heap 536 | hash = hash_djb2_one_32( 537 | (uint32_t)((uint64_t)&hash), hash); //rely on aslr stack 538 | 539 | hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negatie id is used for exclusion 540 | } 541 | 542 | return hash; 543 | } 544 | 545 | int ENetPacketPeer::get_unique_id() const { 546 | 547 | ERR_FAIL_COND_V(!active, 0); 548 | return unique_id; 549 | } 550 | 551 | void ENetPacketPeer::set_refuse_new_connections(bool p_enable) { 552 | 553 | refuse_connections = p_enable; 554 | } 555 | 556 | bool ENetPacketPeer::is_refusing_new_connections() const { 557 | 558 | return refuse_connections; 559 | } 560 | 561 | void ENetPacketPeer::set_compression_mode(CompressionMode p_mode) { 562 | 563 | compression_mode = p_mode; 564 | } 565 | 566 | ENetPacketPeer::CompressionMode ENetPacketPeer::get_compression_mode() const { 567 | 568 | return compression_mode; 569 | } 570 | 571 | size_t ENetPacketPeer::enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit) { 572 | 573 | ENetPacketPeer *enet = (ENetPacketPeer *)(context); 574 | 575 | if (size_t(enet->src_compressor_mem.size()) < inLimit) { 576 | enet->src_compressor_mem.resize(inLimit); 577 | } 578 | 579 | int total = inLimit; 580 | int ofs = 0; 581 | while (total) { 582 | for (size_t i = 0; i < inBufferCount; i++) { 583 | int to_copy = MIN(total, int(inBuffers[i].dataLength)); 584 | copymem(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy); 585 | ofs += to_copy; 586 | total -= to_copy; 587 | } 588 | } 589 | 590 | Compression::Mode mode; 591 | 592 | switch (enet->compression_mode) { 593 | case COMPRESS_FASTLZ: { 594 | mode = Compression::MODE_FASTLZ; 595 | } break; 596 | case COMPRESS_ZLIB: { 597 | mode = Compression::MODE_DEFLATE; 598 | } break; 599 | default: { ERR_FAIL_V(0); } 600 | } 601 | 602 | int req_size = Compression::get_max_compressed_buffer_size(ofs, mode); 603 | if (enet->dst_compressor_mem.size() < req_size) { 604 | enet->dst_compressor_mem.resize(req_size); 605 | } 606 | int ret = Compression::compress(enet->dst_compressor_mem.ptrw(), enet->src_compressor_mem.ptr(), ofs, mode); 607 | 608 | if (ret < 0) 609 | return 0; 610 | 611 | if (ret > int(outLimit)) 612 | return 0; //do not bother 613 | 614 | copymem(outData, enet->dst_compressor_mem.ptr(), ret); 615 | 616 | return ret; 617 | } 618 | 619 | size_t ENetPacketPeer::enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit) { 620 | 621 | ENetPacketPeer *enet = (ENetPacketPeer *)(context); 622 | int ret = -1; 623 | switch (enet->compression_mode) { 624 | case COMPRESS_FASTLZ: { 625 | 626 | ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_FASTLZ); 627 | } break; 628 | case COMPRESS_ZLIB: { 629 | 630 | ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_DEFLATE); 631 | } break; 632 | default: {} 633 | } 634 | if (ret < 0) { 635 | return 0; 636 | } else { 637 | return ret; 638 | } 639 | } 640 | 641 | void ENetPacketPeer::_setup_compressor() { 642 | 643 | switch (compression_mode) { 644 | 645 | case COMPRESS_NONE: { 646 | 647 | enet_host_compress(host, NULL); 648 | } break; 649 | case COMPRESS_RANGE_CODER: { 650 | enet_host_compress_with_range_coder(host); 651 | } break; 652 | case COMPRESS_FASTLZ: 653 | case COMPRESS_ZLIB: { 654 | 655 | enet_host_compress(host, &enet_compressor); 656 | } break; 657 | } 658 | } 659 | 660 | void ENetPacketPeer::enet_compressor_destroy(void *context) { 661 | 662 | //do none 663 | } 664 | 665 | void ENetPacketPeer::_bind_methods() { 666 | 667 | ClassDB::bind_method(D_METHOD("get_packet_channel"), &ENetPacketPeer::get_packet_channel); 668 | ClassDB::bind_method(D_METHOD("create_server", "port", "channels", "max_clients", "in_bandwidth", "out_bandwidth"), &ENetPacketPeer::create_server, DEFVAL(1), DEFVAL(32), DEFVAL(0), DEFVAL(0)); 669 | ClassDB::bind_method(D_METHOD("create_client", "ip", "port", "channels", "in_bandwidth", "out_bandwidth"), &ENetPacketPeer::create_client, DEFVAL(1), DEFVAL(0), DEFVAL(0)); 670 | ClassDB::bind_method(D_METHOD("close_connection"), &ENetPacketPeer::close_connection); 671 | ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &ENetPacketPeer::set_compression_mode); 672 | ClassDB::bind_method(D_METHOD("put_packet_channel", "pkt", "channel"), &ENetPacketPeer::_put_packet_channel); 673 | ClassDB::bind_method(D_METHOD("get_compression_mode"), &ENetPacketPeer::get_compression_mode); 674 | ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &ENetPacketPeer::set_bind_ip); 675 | 676 | BIND_ENUM_CONSTANT(COMPRESS_NONE); 677 | BIND_ENUM_CONSTANT(COMPRESS_RANGE_CODER); 678 | BIND_ENUM_CONSTANT(COMPRESS_FASTLZ); 679 | BIND_ENUM_CONSTANT(COMPRESS_ZLIB); 680 | } 681 | 682 | ENetPacketPeer::ENetPacketPeer() { 683 | 684 | active = false; 685 | server = false; 686 | refuse_connections = false; 687 | unique_id = 0; 688 | target_peer = 0; 689 | current_packet.packet = NULL; 690 | transfer_mode = TRANSFER_MODE_RELIABLE; 691 | connection_status = CONNECTION_DISCONNECTED; 692 | compression_mode = COMPRESS_NONE; 693 | enet_compressor.context = this; 694 | enet_compressor.compress = enet_compress; 695 | enet_compressor.decompress = enet_decompress; 696 | enet_compressor.destroy = enet_compressor_destroy; 697 | 698 | bind_ip = IP_Address("*"); 699 | } 700 | 701 | ENetPacketPeer::~ENetPacketPeer() { 702 | 703 | close_connection(); 704 | } 705 | 706 | // sets IP for ENet to bind when using create_server 707 | // if no IP is set, then ENet bind to ENET_HOST_ANY 708 | void ENetPacketPeer::set_bind_ip(const IP_Address &p_ip) { 709 | ERR_FAIL_COND(!p_ip.is_valid() && !p_ip.is_wildcard()); 710 | 711 | bind_ip = p_ip; 712 | } 713 | -------------------------------------------------------------------------------- /modules/benet/enet_packet_peer.h: -------------------------------------------------------------------------------- 1 | #ifndef ENET_PACKET_PEER_H 2 | #define ENET_PACKET_PEER_H 3 | 4 | #include "core/io/compression.h" 5 | #include "core/io/networked_multiplayer_peer.h" 6 | 7 | #include 8 | 9 | class ENetPacketPeer : public NetworkedMultiplayerPeer { 10 | 11 | GDCLASS(ENetPacketPeer, NetworkedMultiplayerPeer) 12 | public: 13 | enum CompressionMode { 14 | COMPRESS_NONE, 15 | COMPRESS_RANGE_CODER, 16 | COMPRESS_FASTLZ, 17 | COMPRESS_ZLIB 18 | }; 19 | 20 | private: 21 | enum { 22 | SYSMSG_ADD_PEER, 23 | SYSMSG_REMOVE_PEER 24 | }; 25 | 26 | enum { 27 | SYSCH_CONFIG, 28 | SYSCH_RELIABLE, 29 | SYSCH_UNRELIABLE, 30 | SYSCH_MAX 31 | }; 32 | 33 | bool active; 34 | bool server; 35 | 36 | uint32_t unique_id; 37 | 38 | int channels; 39 | int target_peer; 40 | TransferMode transfer_mode; 41 | 42 | ENetEvent event; 43 | ENetPeer *peer; 44 | ENetHost *host; 45 | 46 | bool refuse_connections; 47 | 48 | ConnectionStatus connection_status; 49 | 50 | Map peer_map; 51 | 52 | struct Packet { 53 | 54 | ENetPacket *packet; 55 | int from; 56 | int channel; 57 | }; 58 | 59 | CompressionMode compression_mode; 60 | 61 | List incoming_packets; 62 | 63 | Packet current_packet; 64 | 65 | uint32_t _gen_unique_id() const; 66 | void _pop_current_packet(); 67 | 68 | Vector src_compressor_mem; 69 | Vector dst_compressor_mem; 70 | 71 | ENetCompressor enet_compressor; 72 | static size_t enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit); 73 | static size_t enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit); 74 | static void enet_compressor_destroy(void *context); 75 | void _setup_compressor(); 76 | 77 | IP_Address bind_ip; 78 | 79 | protected: 80 | static void _bind_methods(); 81 | 82 | public: 83 | virtual void set_transfer_mode(TransferMode p_mode); 84 | virtual NetworkedMultiplayerPeer::TransferMode get_transfer_mode() const; 85 | virtual void set_target_peer(int p_peer); 86 | 87 | virtual int get_packet_peer() const; 88 | 89 | Error create_server(int p_port, int p_channels = 2, int p_max_peers = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0); 90 | Error create_client(const IP_Address &p_ip, int p_port, int p_channels = 2, int p_in_bandwidth = 0, int p_out_bandwidth = 0); 91 | 92 | void close_connection(); 93 | 94 | virtual void poll(); 95 | 96 | virtual bool is_server() const; 97 | 98 | virtual int get_available_packet_count() const; 99 | virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet 100 | virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); 101 | virtual Error put_packet_channel(const uint8_t *p_buffer, int p_buffer_size, int p_channel); 102 | Error _put_packet_channel(const PoolVector &p_buffer, int p_channel); 103 | 104 | virtual Error disconnect_peer(int p_id); 105 | 106 | virtual int get_packet_channel() const; 107 | virtual int get_max_packet_size() const; 108 | 109 | virtual ConnectionStatus get_connection_status() const; 110 | 111 | virtual void set_refuse_new_connections(bool p_enable); 112 | virtual bool is_refusing_new_connections() const; 113 | 114 | virtual int get_unique_id() const; 115 | 116 | void set_compression_mode(CompressionMode p_mode); 117 | CompressionMode get_compression_mode() const; 118 | 119 | ENetPacketPeer(); 120 | ~ENetPacketPeer(); 121 | 122 | void set_bind_ip(const IP_Address &p_ip); 123 | }; 124 | 125 | VARIANT_ENUM_CAST(ENetPacketPeer::CompressionMode); 126 | 127 | #endif // ENET_PACKET_PEER_H 128 | -------------------------------------------------------------------------------- /modules/benet/register_types.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "register_types.h" 3 | #include "core/error_macros.h" 4 | #include "enet_packet_peer.h" 5 | #include "enet_node.h" 6 | 7 | static bool enet_ok=false; 8 | 9 | void register_benet_types() { 10 | 11 | if (enet_initialize() !=0 ) { 12 | ERR_PRINT("ENet initialization failure"); 13 | } else { 14 | enet_ok=true; 15 | } 16 | 17 | ClassDB::register_class(); 18 | ClassDB::register_class(); 19 | } 20 | 21 | void unregister_benet_types() { 22 | 23 | if (enet_ok) 24 | enet_deinitialize(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /modules/benet/register_types.h: -------------------------------------------------------------------------------- 1 | 2 | void register_benet_types(); 3 | void unregister_benet_types(); 4 | --------------------------------------------------------------------------------