Compare commits

...

4 Commits

  1. 8
      Game.cs
  2. 4
      game.tscn
  3. 9
      player/Player.cs
  4. 11
      scenes/Workshop.cs
  5. 15
      scenes/workshop.tscn
  6. 7
      scripts/Players.cs
  7. 15
      scripts/Workshops.cs
  8. 10
      scripts/globals/PhysicsLayer.cs
  9. 3
      scripts/globals/RenderLayer.cs
  10. 38
      ui/LoadSaveMenu.cs
  11. 20
      ui/Menu.cs
  12. 119
      ui/menu.tscn

@ -4,9 +4,13 @@ public partial class Game : Node
{
public static Game Instance { get; private set; }
public static new MultiplayerManager Multiplayer { get; private set; }
public static Players Players { get; private set; }
public static Player LocalPlayer { get; private set; }
public static Workshops Workshops { get; private set; }
public static Workshop LocalWorkshop { get; private set; }
public override void _EnterTree()
{
// Set invariant culture so formatting is consistent.
@ -14,7 +18,11 @@ public partial class Game : Node
Instance = this;
Multiplayer = this.GetNodeOrThrow<MultiplayerManager>(nameof(MultiplayerManager));
Players = this.GetNodeOrThrow<Players>(nameof(Players));
LocalPlayer = Players.Single();
Workshops = this.GetNodeOrThrow<Workshops>(nameof(Workshops));
LocalWorkshop = Workshops.Single();
}
}

@ -1,4 +1,4 @@
[gd_scene load_steps=11 format=3 uid="uid://cqitgdxo33amx"]
[gd_scene load_steps=12 format=3 uid="uid://cqitgdxo33amx"]
[ext_resource type="Script" path="res://scripts/MultiplayerManager.cs" id="1_7shyh"]
[ext_resource type="Script" path="res://Game.cs" id="1_uywdd"]
@ -7,6 +7,7 @@
[ext_resource type="Script" path="res://scripts/Players.cs" id="4_l8q75"]
[ext_resource type="Material" uid="uid://c0q35rri3vb07" path="res://assets/shaders/outline_material.tres" id="5_a3fxj"]
[ext_resource type="Script" path="res://scripts/OutlineCamera.cs" id="5_qpc14"]
[ext_resource type="Script" path="res://scripts/Workshops.cs" id="5_rns2j"]
[ext_resource type="PackedScene" uid="uid://c5ooi36ibspfo" path="res://ui/menu.tscn" id="6_ol0j5"]
[ext_resource type="Texture2D" uid="uid://lxxfestfg2dt" path="res://assets/crosshair.png" id="7_0l5tv"]
[ext_resource type="Script" path="res://scripts/Crosshair.cs" id="8_mfhgr"]
@ -24,6 +25,7 @@ script = ExtResource("4_l8q75")
[node name="1" parent="Players" instance=ExtResource("2_iv2f7")]
[node name="Workshops" type="Node" parent="."]
script = ExtResource("5_rns2j")
[node name="1" parent="Workshops" instance=ExtResource("3_4u5ql")]

@ -1,8 +1,15 @@
public partial class Player : CharacterBody3D
{
public int PeerId => GetMultiplayerAuthority();
/// <summary> Returns whether is the local player. </summary>
public bool IsLocal => this.IsAuthority();
/// <summary> Gets the peer ID of this player. </summary>
public int PeerId => GetMultiplayerAuthority();
/// <summary> Gets the workshop owned by this player. </summary>
public Workshop Workshop => Game.Workshops.ByPeerId(PeerId);
public MovementController Movement { get; private set; }
public CameraController Camera { get; private set; }
public AnimationController Animation { get; private set; }

@ -0,0 +1,11 @@
public partial class Workshop : Area3D
{
/// <summary> Returns whether this workshop is owned by the local player. </summary>
public bool IsLocal => this.IsAuthority();
/// <summary> Gets the peer ID of the player owning this workshop. </summary>
public int PeerId => GetMultiplayerAuthority();
/// <summary> Gets the player that owns this workshop. </summary>
public Player Player => Game.Players.ByPeerId(PeerId);
}

@ -1,5 +1,6 @@
[gd_scene load_steps=14 format=3 uid="uid://bwfuet1irfi17"]
[gd_scene load_steps=16 format=3 uid="uid://bwfuet1irfi17"]
[ext_resource type="Script" path="res://scenes/Workshop.cs" id="1_i8qyc"]
[ext_resource type="Script" path="res://scenes/ItemManager.cs" id="1_l6hw6"]
[ext_resource type="PackedScene" uid="uid://yvy5vvaqgxy8" path="res://objects/crate.tscn" id="2_j6a20"]
[ext_resource type="Texture2D" uid="uid://dts3g3ivc4stn" path="res://assets/palettes/metal.png" id="3_kvstu"]
@ -9,6 +10,9 @@
[ext_resource type="PackedScene" uid="uid://bjgfm5x7a0dab" path="res://objects/bolt.tscn" id="5_r6ljd"]
[ext_resource type="PackedScene" uid="uid://54575e3ygpxl" path="res://objects/grid.tscn" id="6_okibm"]
[sub_resource type="BoxShape3D" id="BoxShape3D_q481w"]
size = Vector3(15, 5, 15)
[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_5erfn"]
[sub_resource type="PlaneMesh" id="PlaneMesh_tg4vq"]
@ -23,11 +27,18 @@ size = Vector3(2, 0.1, 1)
[sub_resource type="BoxMesh" id="BoxMesh_efbik"]
size = Vector3(0.1, 0.9, 0.1)
[node name="Workshop" type="Node3D"]
[node name="Workshop" type="Area3D"]
collision_layer = 0
collision_mask = 0
script = ExtResource("1_i8qyc")
[node name="ItemManager" type="Node" parent="."]
script = ExtResource("1_l6hw6")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
shape = SubResource("BoxShape3D_q481w")
[node name="Sun" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.866025, 0, -0.5, 0.25, 0.866025, 0.433013, 0.433013, -0.5, 0.75, 0, 5, 0)

@ -1,12 +1,13 @@
public partial class Players : Node
, IReadOnlyCollection<Player>
{
public int Count
=> GetChildCount();
public Player ByPeerId(int peerId)
=> this.GetNodeOrThrow<Player>(peerId.ToString());
// IReadOnlyCollection implementation
public int Count
=> GetChildCount();
public IEnumerator<Player> GetEnumerator()
=> GetChildren().Cast<Player>().GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()

@ -0,0 +1,15 @@
public partial class Workshops : Node
, IReadOnlyCollection<Workshop>
{
public Workshop ByPeerId(int peerId)
=> this.GetNodeOrThrow<Workshop>(peerId.ToString());
// IReadOnlyCollection implementation
public int Count
=> GetChildCount();
public IEnumerator<Workshop> GetEnumerator()
=> GetChildren().Cast<Workshop>().GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
=> GetEnumerator();
}

@ -1,15 +1,15 @@
[Flags]
public enum PhysicsLayer : uint {
public enum PhysicsLayer : uint
{
/// <summary> Objects that are part of the scene, and never move. </summary>
Static = 1 << 0,
/// <summary> Objects the player collides with, but may move. </summary>
/// <summary> Objects players collide with, but may move. </summary>
Dynamic = 1 << 1,
/// <summary> The player. </summary>
/// <summary> Any players, both local and remote. </summary>
Player = 1 << 2,
/// <summary> Small objects the player doesn't collide with, but collide with the player. </summary>
/// <summary> Small objects players don't collide with, but collide with players. </summary>
Item = 1 << 3,
/// <summary> Objects that may be picked up. </summary>
Pickup = 1 << 8,
/// <summary> Objects that other objects may be placed against. </summary>

@ -1,5 +1,6 @@
[Flags]
public enum RenderLayer : uint {
public enum RenderLayer : uint
{
Default = 1 << 0,
Outline = 1 << 1,
}

@ -0,0 +1,38 @@
public partial class LoadSaveMenu : MarginContainer
{
const string SAVES_FOLDER = "user://saves/";
[Export] public FileDialog LoadFileDialog { get; set; }
[Export] public FileDialog SaveFileDialog { get; set; }
public override void _EnterTree()
{
DirAccess.MakeDirAbsolute(SAVES_FOLDER);
LoadFileDialog.RootSubfolder = SAVES_FOLDER;
SaveFileDialog.RootSubfolder = SAVES_FOLDER;
}
public async void OnLoadPressed()
{
LoadFileDialog.Popup();
}
public void OnOverwriteSavePressed()
{
}
public void OnCreateSavePressed()
{
SaveFileDialog.Popup();
}
public void OnLoadFileDialogSelected(string path)
{
}
public void OnSaveFileDialogSelected(string path)
{
}
}

@ -5,15 +5,12 @@ public partial class Menu : CenterContainer
public override void _Ready()
{
foreach (var child in SideButtons.GetChildren())
if ((child is BaseButton button) && button.ToggleMode)
button.Pressed += () => {
for (var i = 0; i < Tabs.GetTabCount(); i++)
if (Tabs.GetTabControl(i).Name == button.Name)
Tabs.CurrentTab = i;
// Make sure you can't "detoggle" the button.
button.Disabled = true;
};
foreach (var button in SideButtons.GetChildren().OfType<Button>())
button.Pressed += () => {
for (var i = 0; i < Tabs.GetTabCount(); i++)
if (Tabs.GetTabControl(i).Name == button.Name)
Tabs.CurrentTab = i;
};
}
public override void _Input(InputEvent @event)
@ -36,9 +33,8 @@ public partial class Menu : CenterContainer
public void OnTabChanged(int tabIndex)
{
var tabName = Tabs.GetTabControl(tabIndex).Name;
foreach (var child in SideButtons.GetChildren())
if ((child is BaseButton button) && button.ToggleMode)
button.Disabled = button.ButtonPressed = button.Name == tabName;
foreach (var button in SideButtons.GetChildren().OfType<Button>())
button.Disabled = button.Name == tabName;
}
public void OnReturnPressed()

@ -1,6 +1,7 @@
[gd_scene load_steps=12 format=3 uid="uid://c5ooi36ibspfo"]
[gd_scene load_steps=13 format=3 uid="uid://c5ooi36ibspfo"]
[ext_resource type="Script" path="res://ui/Menu.cs" id="1_5qxrt"]
[ext_resource type="Script" path="res://ui/LoadSaveMenu.cs" id="2_0yqy1"]
[ext_resource type="Script" path="res://ui/MultiplayerMenu.cs" id="2_3ulcb"]
[ext_resource type="Script" path="res://ui/ControlsMenu.cs" id="3_jnj0g"]
@ -62,50 +63,125 @@ columns = 2
custom_minimum_size = Vector2(160, 0)
layout_mode = 2
[node name="Gameplay" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
[node name="LoadSave" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
layout_mode = 2
toggle_mode = true
text = "Gameplay"
disabled = true
text = "Load / Save"
[node name="Multiplayer" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
layout_mode = 2
toggle_mode = true
text = "Multiplayer"
[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
custom_minimum_size = Vector2(0, 40)
layout_mode = 2
text = "Options"
horizontal_alignment = 1
vertical_alignment = 2
[node name="HSeparator" type="HSeparator" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
layout_mode = 2
[node name="Gameplay" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
layout_mode = 2
text = "Gameplay"
[node name="Controls" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
layout_mode = 2
toggle_mode = true
text = "Controls"
[node name="Graphics" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
layout_mode = 2
toggle_mode = true
text = "Graphics"
[node name="Audio" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/SideButtons"]
layout_mode = 2
toggle_mode = true
text = "Audio"
[node name="TabContainer" type="TabContainer" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer"]
custom_minimum_size = Vector2(400, 300)
layout_mode = 2
size_flags_vertical = 3
current_tab = 1
tabs_visible = false
use_hidden_tabs_for_min_size = true
[node name="Gameplay" type="CenterContainer" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer"]
visible = false
[node name="LoadSave" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer" node_paths=PackedStringArray("LoadFileDialog", "SaveFileDialog")]
layout_mode = 2
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 8
script = ExtResource("2_0yqy1")
LoadFileDialog = NodePath("LoadFileDialog")
SaveFileDialog = NodePath("SaveFileDialog")
[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/Gameplay"]
[node name="LoadFileDialog" type="FileDialog" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave"]
title = "Open a File"
initial_position = 2
size = Vector2i(480, 400)
popup_window = true
ok_button_text = "Open"
file_mode = 0
access = 1
use_native_dialog = true
[node name="SaveFileDialog" type="FileDialog" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave"]
initial_position = 2
size = Vector2i(480, 400)
popup_window = true
ok_button_text = "Save"
access = 1
use_native_dialog = true
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave"]
layout_mode = 2
text = "Gameplay
(nothing here yet)"
[node name="Load" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer"]
layout_mode = 2
text = "Load existing Save File"
[node name="GridContainer" type="GridContainer" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer"]
layout_mode = 2
columns = 2
[node name="Label1" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer/GridContainer"]
custom_minimum_size = Vector2(112, 0)
layout_mode = 2
text = "Filename: "
horizontal_alignment = 2
[node name="Filename" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "<none>"
label_settings = SubResource("LabelSettings_nmchh")
horizontal_alignment = 1
text_overrun_behavior = 3
[node name="Label2" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer/GridContainer"]
custom_minimum_size = Vector2(112, 0)
layout_mode = 2
text = "Last Saved: "
horizontal_alignment = 2
[node name="LastSaved" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer/GridContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "never"
label_settings = SubResource("LabelSettings_nmchh")
horizontal_alignment = 1
[node name="OverwriteSave" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer"]
layout_mode = 2
disabled = true
text = "Overwrite current Save File"
[node name="CreateSave" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer"]
layout_mode = 2
text = "Create new Save File ..."
[node name="Multiplayer" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer" node_paths=PackedStringArray("StatusLabel", "WhenDisconnected", "AddressInput", "PortInput", "ConnectButton", "HostButton", "WhenServer", "PortDisplay", "WhenConnected", "PlayersLabel", "DisconnectButton")]
visible = false
layout_mode = 2
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
@ -256,6 +332,16 @@ layout_mode = 2
size_flags_horizontal = 3
text = "Disconnect"
[node name="Gameplay" type="CenterContainer" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer"]
visible = false
layout_mode = 2
[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/Gameplay"]
layout_mode = 2
text = "Gameplay
(nothing here yet)"
horizontal_alignment = 1
[node name="Controls" type="MarginContainer" parent="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer" node_paths=PackedStringArray("DisplayX", "DisplayY", "SliderX", "SliderY", "InvertX", "InvertY")]
visible = false
layout_mode = 2
@ -368,6 +454,11 @@ text = "Return to Game
"
[connection signal="tab_changed" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer" to="." method="OnTabChanged"]
[connection signal="file_selected" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/LoadFileDialog" to="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave" method="OnLoadFileDialogSelected"]
[connection signal="file_selected" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/SaveFileDialog" to="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave" method="OnSaveFileDialogSelected"]
[connection signal="pressed" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer/Load" to="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave" method="OnLoadPressed"]
[connection signal="pressed" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer/OverwriteSave" to="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave" method="OnOverwriteSavePressed"]
[connection signal="pressed" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave/VBoxContainer/CreateSave" to="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/LoadSave" method="OnCreateSavePressed"]
[connection signal="toggled" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/Multiplayer/VBoxContainer/WhenDisconnected/HBoxContainer/ShowAddress" to="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/Multiplayer" method="OnShowAddressToggled"]
[connection signal="pressed" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/Multiplayer/VBoxContainer/WhenDisconnected/HBoxContainer/Connect" to="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/Multiplayer" method="OnConnectPressed"]
[connection signal="pressed" from="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/Multiplayer/VBoxContainer/WhenDisconnected/HBoxContainer2/Create" to="PanelContainer/MarginContainer/VBoxContainer/GridContainer/TabContainer/Multiplayer" method="OnHostPressed"]

Loading…
Cancel
Save