├── .gitattributes ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── Doxyfile ├── LICENSE.txt ├── README.md ├── addons └── mattoha_lobby_system │ ├── core │ ├── autoload │ │ └── MattohaSystem.tscn │ ├── enums │ │ ├── ClientRpc.cs │ │ └── ServerRpc.cs │ ├── misc │ │ └── MattohaServerMiddleware.cs │ ├── nodes │ │ ├── MattohaClient.cs │ │ ├── MattohaGameHolder.cs │ │ ├── MattohaPickable.cs │ │ ├── MattohaPositionSynchronizer.cs │ │ ├── MattohaRotationSynchronizer.cs │ │ ├── MattohaServer.cs │ │ ├── MattohaSpawner.cs │ │ ├── MattohaSynchronizerModifier.cs │ │ └── MattohaSystem.cs │ └── utils │ │ ├── MattohaLobbyKeys.cs │ │ ├── MattohaPlayerKeys.cs │ │ ├── MattohaSpawnKeys.cs │ │ └── MattohaUtils.cs │ ├── gd_bind │ └── nodes │ │ ├── mattoha_client.gd │ │ ├── mattoha_server.gd │ │ └── mattoha_system.gd │ ├── mattoha_lobby_system.gd │ └── plugin.cfg ├── csharp_demo_example ├── scenes │ ├── coin.tscn │ ├── create_lobby.tscn │ ├── game.tscn │ ├── game_holder.tscn │ ├── lobbies.tscn │ ├── lobby.tscn │ ├── main_menu.tscn │ ├── player.tscn │ ├── projectile.tscn │ ├── slots │ │ └── lobby_slot.tscn │ └── user_dialog.tscn └── scripts │ ├── Coin.cs │ ├── CreateLobby.cs │ ├── Lobbies.cs │ ├── Lobby.cs │ ├── LobbySlot.cs │ ├── MainMenu.cs │ ├── Player.cs │ ├── UserDialog.cs │ └── game.cs ├── docs ├── annotated.html ├── annotated_dup.js ├── bc_s.png ├── bc_sd.png ├── class_mattoha_1_1_core_1_1_mattoha_utils-members.html ├── class_mattoha_1_1_core_1_1_mattoha_utils.html ├── class_mattoha_1_1_core_1_1_utils_1_1_mattoha_spawn_keys-members.html ├── class_mattoha_1_1_core_1_1_utils_1_1_mattoha_spawn_keys.html ├── class_mattoha_1_1_misc_1_1_mattoha_server_middleware-members.html ├── class_mattoha_1_1_misc_1_1_mattoha_server_middleware.html ├── class_mattoha_1_1_misc_1_1_mattoha_server_middleware.js ├── class_mattoha_1_1_nodes_1_1_mattoha_client-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_client.html ├── class_mattoha_1_1_nodes_1_1_mattoha_client.js ├── class_mattoha_1_1_nodes_1_1_mattoha_game_holder-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_game_holder.html ├── class_mattoha_1_1_nodes_1_1_mattoha_game_holder.js ├── class_mattoha_1_1_nodes_1_1_mattoha_pickable-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_pickable.html ├── class_mattoha_1_1_nodes_1_1_mattoha_position_synchronizer-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_position_synchronizer.html ├── class_mattoha_1_1_nodes_1_1_mattoha_rotation_synchronizer-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_rotation_synchronizer.html ├── class_mattoha_1_1_nodes_1_1_mattoha_server-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_server.html ├── class_mattoha_1_1_nodes_1_1_mattoha_server.js ├── class_mattoha_1_1_nodes_1_1_mattoha_spawner-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_spawner.html ├── class_mattoha_1_1_nodes_1_1_mattoha_spawner.js ├── class_mattoha_1_1_nodes_1_1_mattoha_synchronizer_modifier-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_synchronizer_modifier.html ├── class_mattoha_1_1_nodes_1_1_mattoha_system-members.html ├── class_mattoha_1_1_nodes_1_1_mattoha_system.html ├── class_mattoha_1_1_nodes_1_1_mattoha_system.js ├── classes.html ├── clipboard.js ├── closed.png ├── cookie.js ├── dir_1233bc0a3e869c10318208e4553a4fcb.html ├── dir_36297c83ae5978a9304c4b762d87eb97.html ├── dir_49d5765286348fb7f1c9cf80cac193ac.html ├── dir_74692c01f9002aa62389637c1c9232ea.html ├── dir_7f419cdda9c6daa07ba2aaeece81858a.html ├── dir_cc749a7f66f4a92e949109e34944e902.html ├── dir_d42799d27da86c818c70090759027502.html ├── doc.svg ├── docd.svg ├── doxygen.css ├── doxygen.svg ├── doxygen_crawl.html ├── dynsections.js ├── folderclosed.svg ├── folderclosedd.svg ├── folderopen.svg ├── folderopend.svg ├── functions.html ├── functions_func.html ├── functions_prop.html ├── hierarchy.html ├── hierarchy.js ├── index.html ├── jquery.js ├── menu.js ├── menudata.js ├── minus.svg ├── minusd.svg ├── namespace_mattoha.html ├── namespace_mattoha.js ├── namespace_mattoha_1_1_core.html ├── namespace_mattoha_1_1_core.js ├── namespace_mattoha_1_1_core_1_1_demo.html ├── namespace_mattoha_1_1_core_1_1_utils.html ├── namespace_mattoha_1_1_core_1_1_utils.js ├── namespace_mattoha_1_1_misc.html ├── namespace_mattoha_1_1_misc.js ├── namespace_mattoha_1_1_nodes.html ├── namespace_mattoha_1_1_nodes.js ├── namespaces.html ├── namespaces_dup.js ├── nav_f.png ├── nav_fd.png ├── nav_g.png ├── nav_h.png ├── nav_hd.png ├── navtree.css ├── navtree.js ├── navtreedata.js ├── navtreeindex0.js ├── navtreeindex1.js ├── open.png ├── plus.svg ├── plusd.svg ├── resize.js ├── search │ ├── all_0.js │ ├── all_1.js │ ├── all_10.js │ ├── all_2.js │ ├── all_3.js │ ├── all_4.js │ ├── all_5.js │ ├── all_6.js │ ├── all_7.js │ ├── all_8.js │ ├── all_9.js │ ├── all_a.js │ ├── all_b.js │ ├── all_c.js │ ├── all_d.js │ ├── all_e.js │ ├── all_f.js │ ├── classes_0.js │ ├── close.svg │ ├── functions_0.js │ ├── functions_1.js │ ├── functions_2.js │ ├── functions_3.js │ ├── functions_4.js │ ├── functions_5.js │ ├── functions_6.js │ ├── functions_7.js │ ├── functions_8.js │ ├── functions_9.js │ ├── functions_a.js │ ├── functions_b.js │ ├── functions_c.js │ ├── functions_d.js │ ├── functions_e.js │ ├── mag.svg │ ├── mag_d.svg │ ├── mag_sel.svg │ ├── mag_seld.svg │ ├── namespaces_0.js │ ├── properties_0.js │ ├── properties_1.js │ ├── properties_2.js │ ├── properties_3.js │ ├── properties_4.js │ ├── properties_5.js │ ├── properties_6.js │ ├── properties_7.js │ ├── properties_8.js │ ├── search.css │ ├── search.js │ └── searchdata.js ├── splitbar.png ├── splitbard.png ├── sync_off.png ├── sync_on.png ├── tab_a.png ├── tab_ad.png ├── tab_b.png ├── tab_bd.png ├── tab_h.png ├── tab_hd.png ├── tab_s.png ├── tab_sd.png └── tabs.css ├── gd_demo_example ├── scenes │ ├── coin.tscn │ ├── create_lobby.tscn │ ├── game.tscn │ ├── game_holder.tscn │ ├── lobbies.tscn │ ├── lobby.gd │ ├── lobby.tscn │ ├── main_menu.tscn │ ├── player.tscn │ ├── projectile.tscn │ ├── slots │ │ └── lobby_slot.tscn │ └── user_dialog.tscn └── scripts │ ├── coin.gd │ ├── create_lobby.gd │ ├── game.gd │ ├── lobbies.gd │ ├── lobby_slot.gd │ ├── main_menu.gd │ ├── player.gd │ └── user_dialog.gd ├── icon.svg ├── icon.svg.import ├── main_icon.png ├── main_icon.png.import ├── mattoha_lobby_system.csproj ├── mattoha_lobby_system.csproj.user ├── mattoha_lobby_system.sln ├── pics ├── active_replication.png ├── active_replication.png.import ├── auto_load.png ├── auto_load.png.import ├── client_signals.png ├── client_signals.png.import ├── config.png ├── config.png.import ├── godot_instances.png ├── godot_instances.png.import ├── listener.png ├── listener.png.import ├── mattoha_nodes.png ├── mattoha_nodes.png.import ├── replicator_properties.png ├── replicator_properties.png.import ├── replicator_viewer.png └── replicator_viewer.png.import └── project.godot /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOL for all files that Git considers text files. 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ide ignores 2 | .vs 3 | # Godot 4+ specific ignores 4 | .godot/ 5 | 6 | #docs 7 | docs/**/*.import 8 | 9 | # Godot-specific ignores 10 | .import/ 11 | export.cfg 12 | export_presets.cfg 13 | 14 | # Imported translations (automatically generated from CSV files) 15 | *.translation 16 | 17 | # Mono-specific ignores 18 | .mono/ 19 | data_*/ 20 | mono_crash.*.json 21 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Godot - Debug", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | "program": "C:\\Users\\me\\Documents\\Apps\\Godot\\Godot.exe", 13 | "cwd": "${workspaceFolder}", 14 | "console": "integratedTerminal", 15 | "stopAtEntry": false, 16 | "args": ["--path", "${workspaceRoot}", "--verbose"] 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "dotnet", 6 | "task": "build", 7 | "group": { 8 | "kind": "build", 9 | "isDefault": true 10 | }, 11 | "problemMatcher": [], 12 | "label": "build" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/autoload/MattohaSystem.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://0pk7uurxseuh"] 2 | 3 | [ext_resource type="Script" path="res://addons/mattoha_lobby_system/core/nodes/MattohaSystem.cs" id="1_ii6u1"] 4 | [ext_resource type="Script" path="res://addons/mattoha_lobby_system/core/nodes/MattohaServer.cs" id="2_y71mf"] 5 | [ext_resource type="Script" path="res://addons/mattoha_lobby_system/core/nodes/MattohaClient.cs" id="3_emf05"] 6 | [ext_resource type="Script" path="res://addons/mattoha_lobby_system/core/misc/MattohaServerMiddleware.cs" id="3_uh60p"] 7 | 8 | [node name="MattohaSystem" type="Node" node_paths=PackedStringArray("Server", "Client")] 9 | script = ExtResource("1_ii6u1") 10 | Server = NodePath("MattohaServer") 11 | Client = NodePath("MattohaClient") 12 | 13 | [node name="MattohaServer" type="Node" parent="." node_paths=PackedStringArray("MiddlewareNode")] 14 | script = ExtResource("2_y71mf") 15 | MiddlewareNode = NodePath("ServerMiddleware") 16 | 17 | [node name="ServerMiddleware" type="Node" parent="MattohaServer"] 18 | script = ExtResource("3_uh60p") 19 | 20 | [node name="MattohaClient" type="Node" parent="."] 21 | script = ExtResource("3_emf05") 22 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/enums/ClientRpc.cs: -------------------------------------------------------------------------------- 1 | namespace Mattoha.Core.Demo; 2 | 3 | internal enum ClientRpc 4 | { 5 | RegisterPlayer, 6 | 7 | SetPlayerData, 8 | SetPlayerDataFailed, 9 | 10 | CreateLobby, 11 | CreateLobbyFailed, 12 | 13 | LoadAvailableLobbies, 14 | LoadAvailableLobbiesFailed, 15 | 16 | NewPlayerJoined, 17 | PlayerLeft, 18 | 19 | JoinLobby, 20 | JoinLobbyFailed, 21 | 22 | StartGame, 23 | StartGameFailed, 24 | 25 | LoadLobbyPlayers, 26 | LoadLobbyPlayersFailed, 27 | 28 | SpawnNode, 29 | SpawnNodeFailed, 30 | 31 | SpawnLobbyNodes, 32 | SpawnLobbyNodesFailed, 33 | 34 | DespawnNode, 35 | DespawnNodeFailed, 36 | 37 | DespawnRemovedSceneNodes, 38 | DespawnRemovedSceneNodesFailed, 39 | 40 | JoinedPlayerUpdated, 41 | 42 | SetLobbyData, 43 | SetLobbyDataFailed, 44 | 45 | SetLobbyOwner, 46 | SetLobbyOwnerFailed, 47 | 48 | JoinTeam, 49 | JoinTeamFailed, 50 | 51 | SendTeamMessage, 52 | SendTeamMessageFailed, 53 | 54 | SendLobbyMessage, 55 | SendLobbyMessageFailed, 56 | 57 | SendGlobalMessage, 58 | SendGlobalMessageFailed, 59 | PlayerChangedHisTeam, 60 | 61 | LeaveLobby, 62 | EndGame, 63 | EndGameFailed, 64 | SetPlayerIsInGame, 65 | } 66 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/enums/ServerRpc.cs: -------------------------------------------------------------------------------- 1 | namespace Mattoha.Core.Demo; 2 | 3 | internal enum ServerRpc 4 | { 5 | SetPlayerData, 6 | CreateLobby, 7 | LoadAvailableLobbies, 8 | JoinLobby, 9 | StartGame, 10 | LoadLobbyPlayers, 11 | SpawnNode, 12 | SpawnLobbyNodes, 13 | DespawnNode, 14 | DespawnRemovedSceneNodes, 15 | SetLobbyData, 16 | SetLobbyOwner, 17 | JoinTeam, 18 | SendTeamMessage, 19 | SendLobbyMessage, 20 | SendGlobalMessage, 21 | LeaveLobby, 22 | EndGame, 23 | SetPlayerIsInGame, 24 | } 25 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/nodes/MattohaGameHolder.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using Mattoha.Core.Utils; 3 | 4 | namespace Mattoha.Nodes; 5 | public partial class MattohaGameHolder : Node 6 | { 7 | 8 | /// 9 | /// when false, spawning lobby nodes should be done manually by you, when true, it will be automatically when game scene entered tree, 10 | /// 11 | [Export] public bool AutoSpawnLobbyNodes { get; set; } = true; 12 | 13 | /// 14 | /// when false, despawning removed scene nodes should be done manually by you, when true, it will be automatically when game scene entered tree, 15 | /// 16 | [Export] public bool AutoDespawnRemovedSceneNodes { get; set; } = true; 17 | 18 | 19 | public override void _Ready() 20 | { 21 | if (Multiplayer.IsServer()) 22 | return; 23 | MattohaSystem.Instance.Client.LoadLobbyPlayers(); 24 | AddGameScene(); 25 | base._Ready(); 26 | } 27 | 28 | private void AddGameScene() 29 | { 30 | var sceneFile = MattohaSystem.Instance.Client.CurrentLobby[MattohaLobbyKeys.LobbySceneFile].ToString(); 31 | var gameScene = GD.Load(sceneFile).Instantiate(); 32 | gameScene.Name = $"Lobby{MattohaSystem.Instance.Client.CurrentLobby[MattohaLobbyKeys.Id].AsString()}"; 33 | gameScene.TreeEntered += OnGameSceneTreeEntered; 34 | AddChild(gameScene); 35 | } 36 | 37 | private void OnGameSceneTreeEntered() 38 | { 39 | if (AutoSpawnLobbyNodes) 40 | { 41 | MattohaSystem.Instance.Client.SpawnLobbyNodes(); 42 | } 43 | 44 | if (AutoDespawnRemovedSceneNodes) 45 | { 46 | MattohaSystem.Instance.Client.DespawnRemovedSceneNodes(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/nodes/MattohaPickable.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using Godot.Collections; 3 | using Mattoha.Core.Utils; 4 | 5 | 6 | namespace Mattoha.Nodes; 7 | 8 | /// 9 | /// A script used to detect when an CharacterBody enter the Area2D, 10 | /// has a signal with a playerId, playerData, lobbyId and lobbyData, and a OnPickData dictionary. 11 | /// 12 | public partial class MattohaPickable : Node 13 | { 14 | [Export] public Area2D Area2DNode { get; set; } 15 | [Signal] public delegate void PickedEventHandler(long playerId, Dictionary playerData, int lobbyId, Dictionary lobbyData, Dictionary data); 16 | [Export] public Dictionary OnPickData { get; set; } = new(); 17 | [Export, ExportGroup("Server Side")] bool DetectOnServerOnly { get; set; } = true; 18 | [Export, ExportGroup("Client Side")] bool DetectForBodyOwnerOnly { get; set; } = false; 19 | 20 | 21 | 22 | 23 | public override void _Ready() 24 | { 25 | if (DetectOnServerOnly && Multiplayer.IsServer()) 26 | { 27 | Area2DNode.BodyEntered += OnBodyEntered; 28 | } 29 | else if (!DetectOnServerOnly && !Multiplayer.IsServer()) 30 | { 31 | Area2DNode.BodyEntered += OnBodyEntered; 32 | } 33 | } 34 | 35 | private void OnBodyEntered(Node2D body) 36 | { 37 | #if MATTOHA_SERVER 38 | if (Multiplayer.IsServer() && DetectOnServerOnly) 39 | { 40 | var playerId = body.GetMultiplayerAuthority(); 41 | var player = MattohaSystem.Instance.Server.GetPlayer(playerId); 42 | var lobby = MattohaSystem.Instance.Server.GetPlayerLobby(playerId); 43 | var lobbyId = lobby[MattohaLobbyKeys.Id].AsInt32(); 44 | 45 | EmitSignal(SignalName.Picked, playerId, player, lobbyId, lobby, OnPickData); 46 | } 47 | #endif 48 | 49 | #if MATTOHA_CLIENT 50 | if (!Multiplayer.IsServer() && ((DetectForBodyOwnerOnly && MattohaSystem.Instance.IsNodeOwner(body)) || !DetectForBodyOwnerOnly)) 51 | { 52 | var playerId = body.GetMultiplayerAuthority(); 53 | var player = MattohaSystem.Instance.Client.CurrentLobbyPlayers[playerId]; 54 | var lobby = MattohaSystem.Instance.Client.CurrentLobby; 55 | var lobbyId = lobby[MattohaLobbyKeys.Id].AsInt32(); 56 | 57 | EmitSignal(SignalName.Picked, playerId, player, lobbyId, lobby, OnPickData); 58 | } 59 | #endif 60 | } 61 | 62 | public override void _ExitTree() 63 | { 64 | Area2DNode.BodyEntered += OnBodyEntered; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/nodes/MattohaPositionSynchronizer.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | namespace Mattoha.Nodes; 5 | public partial class MattohaPositionSynchronizer : Node 6 | { 7 | [Export] public float InterpolationTime { get; set; } = 0.05f; 8 | 9 | private Variant _destinationPosition; 10 | private Node _parent; 11 | 12 | 13 | public override void _EnterTree() 14 | { 15 | MattohaSystem.Instance.Client.SetPlayerIsInGameSucceed += OnPlayerInGame; 16 | _parent = GetParent(); 17 | _destinationPosition = _parent.Get("position"); 18 | base._EnterTree(); 19 | } 20 | 21 | private void OnPlayerInGame(bool value) 22 | { 23 | if (!value) 24 | return; 25 | if (!MattohaSystem.Instance.IsNodeOwner(this)) 26 | { 27 | // this will be called from unonwer players so they can sync intial position 28 | RequestPosition(); 29 | } 30 | } 31 | 32 | public override void _Process(double delta) 33 | { 34 | if (MattohaSystem.Instance.IsNodeOwner(this) && MattohaSystem.Instance.Client.CanReplicate) 35 | { 36 | if (!Equals(_destinationPosition, _parent.Get("position"))) 37 | { 38 | SendPosition(); 39 | } 40 | 41 | } 42 | else 43 | { 44 | if (_parent is Node2D) 45 | { 46 | var pos = _destinationPosition.AsVector2(); 47 | (_parent as Node2D).Position = (_parent as Node2D).Position.Lerp(pos, InterpolationTime); 48 | } 49 | else if (_parent is Node3D) 50 | { 51 | var pos = _destinationPosition.AsVector3(); 52 | (_parent as Node3D).Position = (_parent as Node3D).Position.Lerp(pos, InterpolationTime); 53 | } 54 | } 55 | base._Process(delta); 56 | } 57 | 58 | 59 | void RequestPosition() 60 | { 61 | RpcId(GetMultiplayerAuthority(), nameof(RpcRequestPosition)); 62 | } 63 | 64 | 65 | // todo: performance & packets issue, send for only player requested the position 66 | [Rpc(MultiplayerApi.RpcMode.AnyPeer)] 67 | void RpcRequestPosition() 68 | { 69 | SendPosition(Multiplayer.GetRemoteSenderId()); 70 | } 71 | 72 | 73 | public void SendPosition(long onlyFor = 0) 74 | { 75 | _destinationPosition = _parent.Get("position"); 76 | var playersIds = MattohaSystem.Instance.Client.GetLobbyPlayersIds(); 77 | if (onlyFor == 0) // 0 = send to all 78 | { 79 | foreach (var id in playersIds) 80 | { 81 | if (id != Multiplayer.GetUniqueId()) 82 | { 83 | RpcId(id, nameof(RpcSentPosition), _parent.Get("position")); 84 | } 85 | } 86 | } 87 | else 88 | { 89 | RpcId(onlyFor, nameof(RpcSentPosition), _parent.Get("position")); 90 | } 91 | } 92 | 93 | 94 | [Rpc(MultiplayerApi.RpcMode.AnyPeer)] 95 | void RpcSentPosition(Variant position) 96 | { 97 | _destinationPosition = position; 98 | } 99 | 100 | public override void _ExitTree() 101 | { 102 | MattohaSystem.Instance.Client.SetPlayerIsInGameSucceed -= OnPlayerInGame; 103 | base._ExitTree(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/nodes/MattohaRotationSynchronizer.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | 4 | namespace Mattoha.Nodes; 5 | public partial class MattohaRotationSynchronizer : Node 6 | { 7 | [Export] public float InterpolationTime { get; set; } = 0.05f; 8 | 9 | private Variant _rot; 10 | private Node _parent; 11 | 12 | 13 | public override void _EnterTree() 14 | { 15 | MattohaSystem.Instance.Client.SetPlayerIsInGameSucceed += OnPlayerInGame; 16 | _parent = GetParent(); 17 | _rot = _parent.Get("rotation"); 18 | base._EnterTree(); 19 | } 20 | 21 | 22 | private void OnPlayerInGame(bool value) 23 | { 24 | if (!value) 25 | return; 26 | if (!MattohaSystem.Instance.IsNodeOwner(this)) 27 | { 28 | // this will be called from unonwer players so they can sync intial rotation 29 | RequestRotation(); 30 | } 31 | } 32 | 33 | 34 | public override void _Process(double delta) 35 | { 36 | if (MattohaSystem.Instance.IsNodeOwner(this) && MattohaSystem.Instance.Client.CanReplicate) 37 | { 38 | if (!Equals(_rot, _parent.Get("position"))) 39 | { 40 | SendRotation(); 41 | } 42 | 43 | } 44 | else 45 | { 46 | if (_parent is Node2D) 47 | { 48 | var rot = _rot.As(); 49 | (_parent as Node2D).Rotation = Mathf.Lerp(rot, (_parent as Node2D).Rotation, InterpolationTime); 50 | } 51 | else if (_parent is Node3D) 52 | { 53 | var rot = _rot.AsVector3(); 54 | (_parent as Node3D).Rotation = (_parent as Node3D).Rotation.Lerp(rot, InterpolationTime); 55 | } 56 | } 57 | base._Process(delta); 58 | } 59 | 60 | 61 | void RequestRotation() 62 | { 63 | RpcId(GetMultiplayerAuthority(), nameof(RpcRequestRotation)); 64 | } 65 | 66 | 67 | [Rpc(MultiplayerApi.RpcMode.AnyPeer)] 68 | void RpcRequestRotation() 69 | { 70 | SendRotation(Multiplayer.GetRemoteSenderId()); 71 | } 72 | 73 | 74 | public void SendRotation(long onlyFor = 0) 75 | { 76 | _rot = _parent.Get("position"); 77 | var playersIds = MattohaSystem.Instance.Client.GetLobbyPlayersIds(); 78 | if (onlyFor == 0) // 0 = send to all 79 | { 80 | foreach (var id in playersIds) 81 | { 82 | if (id != Multiplayer.GetUniqueId()) 83 | { 84 | RpcId(id, nameof(RpcSendRotation), _parent.Get("position")); 85 | } 86 | } 87 | } 88 | else 89 | { 90 | RpcId(onlyFor, nameof(RpcSendRotation), _parent.Get("position")); 91 | } 92 | } 93 | 94 | 95 | [Rpc(MultiplayerApi.RpcMode.AnyPeer)] 96 | void RpcSendRotation(Variant position) 97 | { 98 | _rot = position; 99 | } 100 | 101 | public override void _ExitTree() 102 | { 103 | MattohaSystem.Instance.Client.SetPlayerIsInGameSucceed -= OnPlayerInGame; 104 | base._ExitTree(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/nodes/MattohaSpawner.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using Godot.Collections; 3 | namespace Mattoha.Nodes; 4 | 5 | public partial class MattohaSpawner : Node 6 | { 7 | /// 8 | /// when true, will spawn node for other players on _ready(). 9 | /// 10 | [Export] public bool AutoSpawn { get; set; } = true; 11 | 12 | /// 13 | /// when true, will despawn node for others when queue_free(). 14 | /// 15 | [Export] public bool AutoDespawn { get; set; } = true; 16 | 17 | /// 18 | /// when true, spawning the node will be only for team members. 19 | /// 20 | [Export] public bool SpawnForTeamOnly { get; set; } = false; 21 | 22 | /// 23 | /// when true, the spawning and despawning will be handled by server, and nodes authority will be the server too. 24 | /// 25 | [Export] public bool HandleByServer { get; set; } = false; 26 | 27 | /// 28 | /// A properties list that should be replicated for other players during spawning, eg: "velocity", "motion_mode" or "Child1/Child2/Sprite2D:self_modulate" for nested node and "Sprite2D:scale" for direct child node. 29 | /// 30 | [Export] public Array AdditionalProps { get; set; } = new(); 31 | 32 | public override void _Ready() 33 | { 34 | if (AutoSpawn && HandleByServer && Multiplayer.IsServer()) 35 | { 36 | #if MATTOHA_SERVER 37 | MattohaSystem.Instance.Server.SpawnNode( 38 | MattohaSystem.Instance.GenerateNodePayloadData(GetParent(), AdditionalProps), 39 | MattohaSystem.ExtractLobbyId(GetParent().GetPath()) 40 | ); 41 | #endif 42 | } 43 | else if (AutoSpawn && !HandleByServer && !Multiplayer.IsServer() && Multiplayer.GetUniqueId() == GetMultiplayerAuthority()) 44 | { 45 | #if MATTOHA_CLIENT 46 | MattohaSystem.Instance.Client.SpawnNode(GetParent(), SpawnForTeamOnly, AdditionalProps); 47 | #endif 48 | } 49 | base._Ready(); 50 | } 51 | 52 | public override void _ExitTree() 53 | { 54 | if (AutoDespawn) 55 | { 56 | if (HandleByServer && Multiplayer.IsServer()) 57 | { 58 | #if MATTOHA_SERVER 59 | MattohaSystem.Instance.Server.DespawnNode(MattohaSystem.Instance.GenerateNodePayloadData(GetParent())); 60 | #endif 61 | } 62 | else if (!HandleByServer && !Multiplayer.IsServer() && Multiplayer.GetUniqueId() == GetMultiplayerAuthority()) 63 | { 64 | #if MATTOHA_CLIENT 65 | MattohaSystem.Instance.Client.DespawnNode(GetParent()); 66 | #endif 67 | } 68 | } 69 | base._ExitTree(); 70 | } 71 | } -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/utils/MattohaLobbyKeys.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Mattoha.Core.Utils; 4 | 5 | public static class MattohaLobbyKeys 6 | { 7 | public static string Id { get; private set; } = "Id"; 8 | public static string OwnerId { get; private set; } = "OwnerId"; 9 | public static string Name { get; private set; } = "Name"; 10 | public static string MaxPlayers { get; private set; } = "MaxPlayers"; 11 | public static string PlayersCount { get; private set; } = "PlayersCount"; 12 | public static string IsGameStarted { get; private set; } = "IsGameStarted"; 13 | public static string PrivateProps { get; private set; } = "PrivateProps"; 14 | public static string LobbySceneFile { get; private set; } = "LobbySceneFile"; 15 | 16 | public static List FreezedProperties { get; private set; } = new() { Id, OwnerId, PlayersCount, IsGameStarted }; 17 | 18 | } -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/utils/MattohaPlayerKeys.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Mattoha.Core.Utils; 4 | 5 | static class MattohaPlayerKeys 6 | { 7 | public static string Id { get; private set; } = "Id"; 8 | public static string Username { get; private set; } = "Username"; 9 | public static string JoinedLobbyId { get; private set; } = "JoinedLobbyId"; 10 | public static string TeamId { get; private set; } = "TeamId"; 11 | public static string IsInGame { get; private set; } = "IsInGame"; 12 | public static string PrivateProps { get; private set; } = "PrivateProps"; 13 | public static string ChatProps { get; private set; } = "ChatProps"; 14 | 15 | public static List FreezedProperties { get; private set; } = new() { Id, JoinedLobbyId, IsInGame }; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/core/utils/MattohaSpawnKeys.cs: -------------------------------------------------------------------------------- 1 | namespace Mattoha.Core.Utils; 2 | 3 | public class MattohaSpawnKeys 4 | { 5 | public static string SceneFile { get; private set; } = "SceneFile"; 6 | public static string NodeName { get; private set; } = "NodeName"; 7 | public static string ParentPath { get; private set; } = "ParentPath"; 8 | public static string Position { get; private set; } = "Position"; 9 | public static string Rotation { get; private set; } = "Rotation"; 10 | public static string Owner { get; private set; } = "Owner"; 11 | public static string TeamOnly { get; private set; } = "TeamOnly"; 12 | public static string TeamId { get; private set; } = "TeamId"; 13 | public static string AdditionalProps { get; private set; } = "AdditionalProps"; 14 | } -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/mattoha_lobby_system.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends EditorPlugin 3 | 4 | func _enter_tree(): 5 | add_custom_type("MattohaGameHolder", "Node2D", preload ("res://addons/mattoha_lobby_system/core/nodes/MattohaGameHolder.cs"), null) 6 | add_custom_type("MattohaSpawner", "Node2D", preload ("res://addons/mattoha_lobby_system/core/nodes/MattohaSpawner.cs"), null) 7 | add_custom_type("MattohaServer", "Node2D", preload ("res://addons/mattoha_lobby_system/core/nodes/MattohaServer.cs"), null) 8 | add_custom_type("MattohaClient", "Node2D", preload ("res://addons/mattoha_lobby_system/core/nodes/MattohaClient.cs"), null) 9 | add_custom_type("MattohaPositionSynchronizer", "Node2D", preload ("res://addons/mattoha_lobby_system/core/nodes/MattohaPositionSynchronizer.cs"), null) 10 | add_custom_type("MattohaRotationSynchronizer", "Node2D", preload ("res://addons/mattoha_lobby_system/core/nodes/MattohaRotationSynchronizer.cs"), null) 11 | add_custom_type("MattohaPickable", "Node2D", preload ("res://addons/mattoha_lobby_system/core/nodes/MattohaPickable.cs"), null) 12 | 13 | add_autoload_singleton("MattohaSystem", "res://addons/mattoha_lobby_system/core/autoload/MattohaSystem.tscn") 14 | add_autoload_singleton("MattohaSystemGD", "res://addons/mattoha_lobby_system/gd_bind/nodes/mattoha_system.gd") 15 | 16 | func _exit_tree(): 17 | # Clean-up of the plugin goes here. 18 | remove_custom_type("MattohaGameHolder") 19 | remove_custom_type("MattohaSpawner") 20 | remove_custom_type("MattohaServer") 21 | remove_custom_type("MattohaClient") 22 | remove_custom_type("MattohaPositionSynchronizer") 23 | remove_custom_type("MattohaRotationSynchronizer") 24 | remove_custom_type("MattohaPickable") 25 | 26 | remove_autoload_singleton("MattohaSystem") 27 | remove_autoload_singleton("MattohaSystemGD") 28 | -------------------------------------------------------------------------------- /addons/mattoha_lobby_system/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="MattohaLobbySystem" 4 | description="" 5 | author="Zer0xTJ" 6 | version="0.2.4" 7 | script="mattoha_lobby_system.gd" 8 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/coin.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://hnnapidqk1th"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://wcxowoxvkef7" path="res://icon.svg" id="1_2yae6"] 4 | [ext_resource type="Script" path="res://csharp_demo_example/scripts/Coin.cs" id="1_d1hfj"] 5 | [ext_resource type="Script" path="res://addons/mattoha_lobby_system/core/nodes/MattohaSpawner.cs" id="2_flket"] 6 | 7 | [sub_resource type="CircleShape2D" id="CircleShape2D_snnoe"] 8 | radius = 66.0 9 | 10 | [node name="Coin" type="Area2D"] 11 | modulate = Color(0.856132, 0.708794, 0, 1) 12 | position = Vector2(1, 1) 13 | scale = Vector2(0.329583, 0.317051) 14 | collision_layer = 2 15 | script = ExtResource("1_d1hfj") 16 | 17 | [node name="Sprite2D" type="Sprite2D" parent="."] 18 | texture = ExtResource("1_2yae6") 19 | 20 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 21 | shape = SubResource("CircleShape2D_snnoe") 22 | debug_color = Color(0.851468, 0.000855187, 0.896501, 0.42) 23 | 24 | [node name="MattohaSpawner" type="Node2D" parent="."] 25 | script = ExtResource("2_flket") 26 | AutoSpawn = false 27 | HandleByServer = true 28 | 29 | [connection signal="body_entered" from="." to="." method="OnBodyEntered"] 30 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/create_lobby.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://najc1uun72o3"] 2 | 3 | [ext_resource type="Script" path="res://csharp_demo_example/scripts/CreateLobby.cs" id="1_4w86w"] 4 | 5 | [node name="CreateLobby" type="Control"] 6 | layout_mode = 3 7 | anchors_preset = 15 8 | anchor_right = 1.0 9 | anchor_bottom = 1.0 10 | grow_horizontal = 2 11 | grow_vertical = 2 12 | script = ExtResource("1_4w86w") 13 | 14 | [node name="PanelContainer" type="PanelContainer" parent="."] 15 | layout_mode = 1 16 | anchors_preset = 8 17 | anchor_left = 0.5 18 | anchor_top = 0.5 19 | anchor_right = 0.5 20 | anchor_bottom = 0.5 21 | offset_left = -288.0 22 | offset_top = -136.0 23 | offset_right = 288.0 24 | offset_bottom = 136.0 25 | grow_horizontal = 2 26 | grow_vertical = 2 27 | 28 | [node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] 29 | layout_mode = 2 30 | theme_override_constants/margin_left = 10 31 | theme_override_constants/margin_top = 10 32 | theme_override_constants/margin_right = 10 33 | theme_override_constants/margin_bottom = 10 34 | 35 | [node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] 36 | layout_mode = 2 37 | 38 | [node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] 39 | layout_mode = 2 40 | theme_type_variation = &"HeaderMedium" 41 | text = "Create New Lobby" 42 | 43 | [node name="Spacer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer"] 44 | custom_minimum_size = Vector2(0, 10) 45 | layout_mode = 2 46 | 47 | [node name="Label2" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] 48 | layout_mode = 2 49 | text = "Lobby Name:" 50 | 51 | [node name="LobbyNameLineEdit" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer"] 52 | unique_name_in_owner = true 53 | layout_mode = 2 54 | placeholder_text = "Enter lobby name ..." 55 | 56 | [node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] 57 | layout_mode = 2 58 | size_flags_vertical = 10 59 | 60 | [node name="Spaceer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] 61 | layout_mode = 2 62 | size_flags_horizontal = 3 63 | 64 | [node name="CreateButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] 65 | unique_name_in_owner = true 66 | layout_mode = 2 67 | text = "Continue" 68 | 69 | [connection signal="pressed" from="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer/CreateButton" to="." method="OnCreateLobbyButtonPressed"] 70 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/game.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://bf5pnbm0fm7qi"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://hnnapidqk1th" path="res://csharp_demo_example/scenes/coin.tscn" id="1_bcx0l"] 4 | [ext_resource type="Script" path="res://csharp_demo_example/scripts/Game.cs" id="1_l4exr"] 5 | 6 | [node name="Game" type="Node2D"] 7 | script = ExtResource("1_l4exr") 8 | 9 | [node name="Camera2D" type="Camera2D" parent="."] 10 | position = Vector2(74, 44) 11 | 12 | [node name="Coin" parent="." instance=ExtResource("1_bcx0l")] 13 | position = Vector2(290, 138) 14 | 15 | [node name="Coin2" parent="." instance=ExtResource("1_bcx0l")] 16 | position = Vector2(-239, 161) 17 | 18 | [node name="Coin3" parent="." instance=ExtResource("1_bcx0l")] 19 | position = Vector2(-132, -84) 20 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/game_holder.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://ddr2vmfusqyqg"] 2 | 3 | [ext_resource type="Script" path="res://addons/mattoha_lobby_system/core/nodes/MattohaGameHolder.cs" id="1_1gxij"] 4 | 5 | [node name="GameHolder" type="Node2D"] 6 | script = ExtResource("1_1gxij") 7 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/lobbies.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://db78nr00o2o"] 2 | 3 | [ext_resource type="Script" path="res://csharp_demo_example/scripts/Lobbies.cs" id="1_t2ss4"] 4 | [ext_resource type="PackedScene" uid="uid://dlcdjul4fk705" path="res://csharp_demo_example/scenes/slots/lobby_slot.tscn" id="2_kswa7"] 5 | 6 | [node name="Lobbies" type="Control"] 7 | layout_mode = 3 8 | anchors_preset = 15 9 | anchor_right = 1.0 10 | anchor_bottom = 1.0 11 | grow_horizontal = 2 12 | grow_vertical = 2 13 | script = ExtResource("1_t2ss4") 14 | LobbySlot = ExtResource("2_kswa7") 15 | 16 | [node name="PanelContainer" type="PanelContainer" parent="."] 17 | layout_mode = 1 18 | anchors_preset = 8 19 | anchor_left = 0.5 20 | anchor_top = 0.5 21 | anchor_right = 0.5 22 | anchor_bottom = 0.5 23 | offset_left = -360.0 24 | offset_top = -170.0 25 | offset_right = 360.0 26 | offset_bottom = 170.0 27 | grow_horizontal = 2 28 | grow_vertical = 2 29 | 30 | [node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] 31 | layout_mode = 2 32 | theme_override_constants/margin_left = 10 33 | theme_override_constants/margin_top = 10 34 | theme_override_constants/margin_right = 10 35 | theme_override_constants/margin_bottom = 10 36 | 37 | [node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] 38 | layout_mode = 2 39 | 40 | [node name="HBoxContainer2" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] 41 | layout_mode = 2 42 | 43 | [node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer2"] 44 | layout_mode = 2 45 | size_flags_horizontal = 3 46 | theme_type_variation = &"HeaderMedium" 47 | text = "Lobbies List" 48 | 49 | [node name="CreateLobbyButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer2"] 50 | unique_name_in_owner = true 51 | layout_mode = 2 52 | text = "Create Lobby" 53 | 54 | [node name="Spacer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer"] 55 | custom_minimum_size = Vector2(0, 10) 56 | layout_mode = 2 57 | 58 | [node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] 59 | layout_mode = 2 60 | size_flags_vertical = 3 61 | 62 | [node name="LobbiesContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/ScrollContainer"] 63 | unique_name_in_owner = true 64 | layout_mode = 2 65 | size_flags_horizontal = 3 66 | size_flags_vertical = 3 67 | 68 | [connection signal="pressed" from="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer2/CreateLobbyButton" to="." method="OpenCreateLobbyScene"] 69 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/main_menu.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://ejnt53rqx4td"] 2 | 3 | [ext_resource type="Script" path="res://csharp_demo_example/scripts/MainMenu.cs" id="1_40jr6"] 4 | 5 | [node name="MainMenu" type="Control"] 6 | layout_mode = 3 7 | anchors_preset = 15 8 | anchor_right = 1.0 9 | anchor_bottom = 1.0 10 | grow_horizontal = 2 11 | grow_vertical = 2 12 | script = ExtResource("1_40jr6") 13 | 14 | [node name="PanelContainer" type="PanelContainer" parent="."] 15 | layout_mode = 1 16 | anchors_preset = 8 17 | anchor_left = 0.5 18 | anchor_top = 0.5 19 | anchor_right = 0.5 20 | anchor_bottom = 0.5 21 | offset_left = -201.0 22 | offset_top = -33.0 23 | offset_right = 201.0 24 | offset_bottom = 33.0 25 | grow_horizontal = 2 26 | grow_vertical = 2 27 | 28 | [node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer"] 29 | layout_mode = 2 30 | size_flags_vertical = 0 31 | 32 | [node name="ServerButton" type="Button" parent="PanelContainer/VBoxContainer"] 33 | layout_mode = 2 34 | text = "SERVER" 35 | 36 | [node name="ClientButton" type="Button" parent="PanelContainer/VBoxContainer"] 37 | layout_mode = 2 38 | text = "CLIENT" 39 | 40 | [connection signal="pressed" from="PanelContainer/VBoxContainer/ServerButton" to="." method="StartServer"] 41 | [connection signal="pressed" from="PanelContainer/VBoxContainer/ClientButton" to="." method="StartClient"] 42 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/player.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=7 format=3 uid="uid://c1xsajn74al37"] 2 | 3 | [ext_resource type="Script" path="res://csharp_demo_example/scripts/Player.cs" id="1_14vrl"] 4 | [ext_resource type="Texture2D" uid="uid://wcxowoxvkef7" path="res://icon.svg" id="2_pxpn8"] 5 | [ext_resource type="Script" path="res://addons/mattoha_lobby_system/core/nodes/MattohaSynchronizerModifier.cs" id="3_n4xde"] 6 | [ext_resource type="Script" path="res://addons/mattoha_lobby_system/core/nodes/MattohaSpawner.cs" id="4_brh8d"] 7 | 8 | [sub_resource type="CircleShape2D" id="CircleShape2D_4d5lc"] 9 | 10 | [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_ab1fq"] 11 | properties/0/path = NodePath(".:position") 12 | properties/0/spawn = true 13 | properties/0/replication_mode = 2 14 | 15 | [node name="Player" type="CharacterBody2D"] 16 | scale = Vector2(0.985431, 1.01452) 17 | collision_mask = 2 18 | script = ExtResource("1_14vrl") 19 | 20 | [node name="Sprite2D" type="Sprite2D" parent="."] 21 | scale = Vector2(0.4, 0.4) 22 | texture = ExtResource("2_pxpn8") 23 | 24 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 25 | shape = SubResource("CircleShape2D_4d5lc") 26 | 27 | [node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."] 28 | replication_config = SubResource("SceneReplicationConfig_ab1fq") 29 | public_visibility = false 30 | script = ExtResource("3_n4xde") 31 | 32 | [node name="MattohaSpawner" type="Node2D" parent="."] 33 | script = ExtResource("4_brh8d") 34 | AdditionalProps = ["Foo", "Sprite2D:scale"] 35 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/projectile.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://7otegvmwvo74"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://wcxowoxvkef7" path="res://icon.svg" id="1_6xgft"] 4 | 5 | [node name="Projectile" type="Node2D"] 6 | 7 | [node name="Sprite2D" type="Sprite2D" parent="."] 8 | modulate = Color(1, 0.392157, 1, 1) 9 | scale = Vector2(0.15, 0.15) 10 | texture = ExtResource("1_6xgft") 11 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/slots/lobby_slot.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://dlcdjul4fk705"] 2 | 3 | [ext_resource type="Script" path="res://csharp_demo_example/scripts/LobbySlot.cs" id="1_rmpdp"] 4 | 5 | [node name="LobbySlot" type="HBoxContainer"] 6 | scale = Vector2(-0.149272, 0.73052) 7 | script = ExtResource("1_rmpdp") 8 | 9 | [node name="LobbyNameLabel" type="Label" parent="."] 10 | unique_name_in_owner = true 11 | layout_mode = 2 12 | size_flags_horizontal = 3 13 | text = "Lobby Name" 14 | 15 | [node name="PlayersCountLabel" type="Label" parent="."] 16 | unique_name_in_owner = true 17 | layout_mode = 2 18 | size_flags_horizontal = 3 19 | size_flags_stretch_ratio = 1.5 20 | text = "Lobby Name" 21 | 22 | [node name="JoinButton" type="Button" parent="."] 23 | layout_mode = 2 24 | focus_mode = 0 25 | text = "JOIN" 26 | 27 | [connection signal="pressed" from="JoinButton" to="." method="JoinLobby"] 28 | -------------------------------------------------------------------------------- /csharp_demo_example/scenes/user_dialog.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://ckxna1a8ju0xy"] 2 | 3 | [ext_resource type="Script" path="res://csharp_demo_example/scripts/UserDialog.cs" id="1_v5uge"] 4 | 5 | [node name="UserDialog" type="Control"] 6 | layout_mode = 3 7 | anchors_preset = 15 8 | anchor_right = 1.0 9 | anchor_bottom = 1.0 10 | grow_horizontal = 2 11 | grow_vertical = 2 12 | script = ExtResource("1_v5uge") 13 | 14 | [node name="PanelContainer" type="PanelContainer" parent="."] 15 | layout_mode = 1 16 | anchors_preset = 8 17 | anchor_left = 0.5 18 | anchor_top = 0.5 19 | anchor_right = 0.5 20 | anchor_bottom = 0.5 21 | offset_left = -288.0 22 | offset_top = -136.0 23 | offset_right = 288.0 24 | offset_bottom = 136.0 25 | grow_horizontal = 2 26 | grow_vertical = 2 27 | 28 | [node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] 29 | layout_mode = 2 30 | theme_override_constants/margin_left = 10 31 | theme_override_constants/margin_top = 10 32 | theme_override_constants/margin_right = 10 33 | theme_override_constants/margin_bottom = 10 34 | 35 | [node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] 36 | layout_mode = 2 37 | 38 | [node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] 39 | layout_mode = 2 40 | theme_type_variation = &"HeaderMedium" 41 | text = "User info" 42 | 43 | [node name="Spacer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer"] 44 | custom_minimum_size = Vector2(0, 10) 45 | layout_mode = 2 46 | 47 | [node name="Label2" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] 48 | layout_mode = 2 49 | text = "Username :" 50 | 51 | [node name="UsernameLineEdit" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer"] 52 | unique_name_in_owner = true 53 | layout_mode = 2 54 | placeholder_text = "Enter a susername" 55 | 56 | [node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] 57 | layout_mode = 2 58 | size_flags_vertical = 10 59 | 60 | [node name="Spaceer" type="Control" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] 61 | layout_mode = 2 62 | size_flags_horizontal = 3 63 | 64 | [node name="ContinueButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] 65 | unique_name_in_owner = true 66 | layout_mode = 2 67 | focus_mode = 0 68 | text = "Continue" 69 | 70 | [connection signal="pressed" from="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer/ContinueButton" to="." method="OnContinueButtonPressed"] 71 | -------------------------------------------------------------------------------- /csharp_demo_example/scripts/Coin.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | 3 | namespace Mattoha.Demo; 4 | public partial class Coin : Area2D 5 | { 6 | 7 | public void OnBodyEntered(Node2D body) 8 | { 9 | if (Multiplayer.IsServer()) // despawn by server only 10 | { 11 | QueueFree(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /csharp_demo_example/scripts/CreateLobby.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using Godot.Collections; 3 | using Mattoha.Nodes; 4 | 5 | namespace Mattoha.Demo; 6 | public partial class CreateLobby : Control 7 | { 8 | private LineEdit _lineEdit; 9 | public override void _Ready() 10 | { 11 | MattohaSystem.Instance.Client.CreateLobbySucceed += OnCreateLobby; 12 | _lineEdit = GetNode("%LobbyNameLineEdit"); 13 | base._Ready(); 14 | } 15 | 16 | private void OnCreateLobby(Dictionary lobbyData) 17 | { 18 | GetTree().ChangeSceneToFile("res://csharp_demo_example/scenes/lobby.tscn"); 19 | } 20 | 21 | public void OnCreateLobbyButtonPressed() 22 | { 23 | var lobbyData = new Dictionary 24 | { 25 | { "Password", "123123" }, 26 | { "Name", _lineEdit.Text }, 27 | { "PrivateProps", new Array { "Password" } } 28 | }; 29 | MattohaSystem.Instance.Client.CreateLobby(lobbyData, "res://csharp_demo_example/scenes/game.tscn"); 30 | } 31 | 32 | public override void _ExitTree() 33 | { 34 | 35 | MattohaSystem.Instance.Client.CreateLobbySucceed -= OnCreateLobby; 36 | base._ExitTree(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /csharp_demo_example/scripts/Lobbies.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using Godot.Collections; 3 | using Mattoha.Core.Utils; 4 | using Mattoha.Nodes; 5 | 6 | namespace Mattoha.Demo; 7 | public partial class Lobbies : Control 8 | { 9 | [Export] public PackedScene LobbySlot { get; set; } 10 | private VBoxContainer _lobbiesContainer; 11 | 12 | public override void _Ready() 13 | { 14 | _lobbiesContainer = GetNode("%LobbiesContainer"); 15 | MattohaSystem.Instance.Client.LoadAvailableLobbiesSucceed += OnLoadLobbies; 16 | MattohaSystem.Instance.Client.JoinLobbySucceed += OnJoinLobby; 17 | MattohaSystem.Instance.Client.LoadAvailableLobbies(); 18 | base._Ready(); 19 | } 20 | 21 | private void OnJoinLobby(Dictionary lobbyData) 22 | { 23 | if (lobbyData[MattohaLobbyKeys.IsGameStarted].AsBool()) 24 | { 25 | GetTree().ChangeSceneToFile("res://csharp_demo_example/scenes/game_holder.tscn"); 26 | } 27 | else 28 | { 29 | GetTree().ChangeSceneToFile("res://csharp_demo_example/scenes/lobby.tscn"); 30 | } 31 | } 32 | 33 | private void OnLoadLobbies(Array> lobbies) 34 | { 35 | foreach (var slot in _lobbiesContainer.GetChildren()) 36 | { 37 | slot.QueueFree(); 38 | } 39 | 40 | foreach (var lobby in lobbies) 41 | { 42 | var lobbySlot = LobbySlot.Instantiate(); 43 | lobbySlot.LobbyData = lobby; 44 | _lobbiesContainer.AddChild(lobbySlot); 45 | } 46 | } 47 | 48 | public void OpenCreateLobbyScene() 49 | { 50 | GetTree().ChangeSceneToFile("res://csharp_demo_example/scenes/create_lobby.tscn"); 51 | } 52 | 53 | public override void _ExitTree() 54 | { 55 | MattohaSystem.Instance.Client.LoadAvailableLobbiesSucceed -= OnLoadLobbies; 56 | MattohaSystem.Instance.Client.JoinLobbySucceed -= OnJoinLobby; 57 | base._ExitTree(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /csharp_demo_example/scripts/LobbySlot.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using Godot.Collections; 3 | using Mattoha.Nodes; 4 | using Mattoha.Core.Utils; 5 | 6 | 7 | namespace Mattoha.Demo; 8 | public partial class LobbySlot : HBoxContainer 9 | { 10 | 11 | public Dictionary LobbyData { get; set; } 12 | 13 | private Label _lobbyNameLabel; 14 | private Label _playersCountLabel; 15 | 16 | public override void _Ready() 17 | { 18 | _lobbyNameLabel = GetNode