Added MainMenu, Bootstrap and Factory scenes

This commit is contained in:
2026-08-04 18:04:42 +03:00
parent bca1cbb323
commit a259a64e80
43 changed files with 1991 additions and 10 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a940c46e5ab12f347a2eddcc30785021
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,64 @@
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
/// <summary>
/// Server-authoritative prototype movement.
/// The owner reads input, the server applies it, and NetworkTransform replicates the result.
/// </summary>
[RequireComponent(typeof(NetworkObject))]
public sealed class FriendslopPlayerMotor : NetworkBehaviour
{
[SerializeField, Min(0.1f)] private float moveSpeed = 4.5f;
private void Update()
{
if (!IsOwner || !IsSpawned || Keyboard.current == null)
{
return;
}
Vector2 input = ReadMoveInput();
if (IsServer)
{
MoveOnServer(input);
}
else
{
MoveServerRpc(input);
}
}
[ServerRpc]
private void MoveServerRpc(Vector2 input)
{
MoveOnServer(input);
}
private void MoveOnServer(Vector2 input)
{
if (input.sqrMagnitude > 1f)
{
input.Normalize();
}
Vector3 direction = new Vector3(input.x, 0f, input.y);
transform.position += direction * (moveSpeed * Time.deltaTime);
if (direction.sqrMagnitude > 0.001f)
{
transform.forward = Vector3.Slerp(transform.forward, direction, 14f * Time.deltaTime);
}
}
private static Vector2 ReadMoveInput()
{
Keyboard keyboard = Keyboard.current;
float horizontal = (keyboard.dKey.isPressed || keyboard.rightArrowKey.isPressed ? 1f : 0f)
- (keyboard.aKey.isPressed || keyboard.leftArrowKey.isPressed ? 1f : 0f);
float vertical = (keyboard.wKey.isPressed || keyboard.upArrowKey.isPressed ? 1f : 0f)
- (keyboard.sKey.isPressed || keyboard.downArrowKey.isPressed ? 1f : 0f);
return new Vector2(horizontal, vertical);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fa9cb02e9bb4c4542aeeb0d7024b2d9d
@@ -0,0 +1,60 @@
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using UnityEngine;
using UnityEngine.SceneManagement;
[RequireComponent(typeof(NetworkManager), typeof(UnityTransport))]
public sealed class FriendslopSession : MonoBehaviour
{
public static FriendslopSession Instance { get; private set; }
[SerializeField] private NetworkObject playerPrefab;
[SerializeField] private string menuScene = "MainMenu";
[SerializeField] private string gameplayScene = "Factory";
public string Status { get; private set; } = "Ready.";
public bool IsOnline => NetworkManager.Singleton != null && NetworkManager.Singleton.IsListening;
private NetworkManager manager;
private UnityTransport transport;
private void Awake()
{
if (Instance != null) { Destroy(gameObject); return; }
Instance = this;
DontDestroyOnLoad(gameObject);
manager = GetComponent<NetworkManager>();
transport = GetComponent<UnityTransport>();
manager.NetworkConfig.NetworkTransport = transport;
manager.NetworkConfig.PlayerPrefab = playerPrefab.gameObject;
manager.NetworkConfig.EnableSceneManagement = true;
manager.OnServerStarted += LoadGameplayForHost;
}
private void Start() => SceneManager.LoadScene(menuScene);
private void OnDestroy()
{
if (manager != null) manager.OnServerStarted -= LoadGameplayForHost;
if (Instance == this) Instance = null;
}
public bool StartHost(ushort port)
{
transport.SetConnectionData("0.0.0.0", port, "0.0.0.0");
Status = manager.StartHost() ? $"Host started on {port}." : "Host failed to start.";
return manager.IsHost;
}
public bool StartClient(string address, ushort port)
{
transport.SetConnectionData(address.Trim(), port);
bool started = manager.StartClient();
Status = started ? $"Connecting to {address}:{port}..." : "Client failed to start.";
return started;
}
private void LoadGameplayForHost()
{
Status = "Loading factory...";
manager.SceneManager.LoadScene(gameplayScene, LoadSceneMode.Single);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 885bc2a800341c0479b5e41a114f3948
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6cc579f5c1f6e6a41b2fa6d4de3fd5fb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,42 @@
using UnityEngine;
public sealed class FriendslopMainMenu : MonoBehaviour
{
private string address = "127.0.0.1";
private string portText = "7777";
private void OnGUI()
{
var session = FriendslopSession.Instance;
GUI.Box(new Rect(24, 24, 380, 285), string.Empty);
GUILayout.BeginArea(new Rect(44, 44, 340, 245));
GUILayout.Label("FRIENDSLOP // MOUNTAIN FACTORY");
GUILayout.Space(10);
if (session == null) { GUILayout.Label("Bootstrap is unavailable."); GUILayout.EndArea(); return; }
if (session.IsOnline) { GUILayout.Label(session.Status); GUILayout.EndArea(); return; }
GUILayout.Label("Host LAN IP");
address = GUILayout.TextField(address);
GUILayout.Label("Port");
portText = GUILayout.TextField(portText);
GUILayout.Space(12);
if (GUILayout.Button("Start Host", GUILayout.Height(36))) StartHost(session);
if (GUILayout.Button("Join Factory", GUILayout.Height(36))) StartClient(session);
GUILayout.FlexibleSpace();
GUILayout.Label(session.Status);
GUILayout.EndArea();
}
private void StartHost(FriendslopSession session)
{
if (TryReadPort(out ushort port)) session.StartHost(port);
else Debug.LogWarning("Friendslop: invalid port.");
}
private void StartClient(FriendslopSession session)
{
if (TryReadPort(out ushort port) && !string.IsNullOrWhiteSpace(address)) session.StartClient(address, port);
else Debug.LogWarning("Friendslop: enter a valid IP and port.");
}
private bool TryReadPort(out ushort port) => ushort.TryParse(portText, out port) && port > 0;
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: eaf978c3df4c1364083bd8a1f7d08861