commit c402c5513bcb8f19da42ffe45f25f762f45065f1 Author: Jan Ráček Date: Tue Jan 27 21:36:29 2026 +0100 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9eb70ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,99 @@ +# This .gitignore file should be placed at the root of your Unity project directory +# +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore +# +.utmp/ +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ +*.log + +# By default unity supports Blender asset imports, *.blend1 blender files do not need to be commited to version control. +*.blend1 +*.blend1.meta + +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data +/[Mm]emoryCaptures/ + +# Recordings can get excessive in size +/[Rr]ecordings/ + +# Uncomment this line if you wish to ignore the asset store tools plugin +# /[Aa]ssets/AssetStoreTools* + +# Autogenerated Jetbrains Rider plugin +/[Aa]ssets/Plugins/Editor/JetBrains* +# Jetbrains Rider personal-layer settings +*.DotSettings.user + +# Visual Studio cache directory +.vs/ + +# Gradle cache directory +.gradle/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.mdb +*.opendb +*.VC.db + +# Unity3D generated meta files +*.pidb.meta +*.pdb.meta +*.mdb.meta + +# Unity3D generated file on crash reports +sysinfo.txt + +# Mono auto generated files +mono_crash.* + +# Builds +*.apk +*.aab +*.unitypackage +*.unitypackage.meta +*.app + +# Crashlytics generated file +crashlytics-build.properties + +# TestRunner generated files +InitTestScene*.unity* + +# Addressables default ignores, before user customizations +/ServerData +/[Aa]ssets/StreamingAssets/aa* +/[Aa]ssets/AddressableAssetsData/link.xml* +/[Aa]ssets/Addressables_Temp* +# By default, Addressables content builds will generate addressables_content_state.bin +# files in platform-specific subfolders, for example: +# /Assets/AddressableAssetsData/OSX/addressables_content_state.bin +/[Aa]ssets/AddressableAssetsData/*/*.bin* + +# Visual Scripting auto-generated files +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db.meta +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers.meta + +# Auto-generated scenes by play mode tests +/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity* diff --git a/.vsconfig b/.vsconfig new file mode 100644 index 0000000..f019fd0 --- /dev/null +++ b/.vsconfig @@ -0,0 +1,6 @@ +{ + "version": "1.0", + "components": [ + "Microsoft.VisualStudio.Workload.ManagedGame" + ] +} diff --git a/Assets/ClientSDK.meta b/Assets/ClientSDK.meta new file mode 100644 index 0000000..28d2c00 --- /dev/null +++ b/Assets/ClientSDK.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1d7531f2b0dd1c44a811f5704eeed90 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/ClientSDK.csproj.meta b/Assets/ClientSDK/ClientSDK.csproj.meta new file mode 100644 index 0000000..94c70c7 --- /dev/null +++ b/Assets/ClientSDK/ClientSDK.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7009ccbbf5326044c8f2df72a309d093 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/Encryption.cs b/Assets/ClientSDK/Encryption.cs new file mode 100644 index 0000000..3def88a --- /dev/null +++ b/Assets/ClientSDK/Encryption.cs @@ -0,0 +1,285 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace GeoSus.Client +{ + // Klientská strana šifrování - generuje session key, šifruje RSA, AES-CBC session + // Používá AES-CBC místo AES-GCM pro kompatibilitu s Unity + public class ClientEncryption : IDisposable + { + private byte[] _sessionKey; + private byte[] _sessionIv; + private long _nonceCounter; + private readonly object _lock = new object(); + + // Kontrola, zda je session key nastaven + public bool HasSessionKey => _sessionKey != null && _sessionIv != null; + + // Generuje nový session key a IV + public void GenerateSessionKey() + { + _sessionKey = new byte[32]; // AES-256 + _sessionIv = new byte[16]; // CBC IV (16 bytes) + + using (var rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(_sessionKey); + rng.GetBytes(_sessionIv); + } + } + + public byte[] SessionKey => _sessionKey ?? throw new InvalidOperationException("Session key not generated"); + public byte[] SessionIV => _sessionIv ?? throw new InvalidOperationException("Session IV not generated"); + + // Zašifruje session key pomocí RSA public key serveru + public (string EncryptedKey, string EncryptedIV) EncryptSessionKeyForServer(string rsaPublicKeyPem) + { + if (_sessionKey == null || _sessionIv == null) + throw new InvalidOperationException("Session key not generated"); + + using (var rsa = RSA.Create()) + { + // Parse PEM - extrahuj Base64 obsah + var pemLines = rsaPublicKeyPem.Split('\n'); + var base64 = new StringBuilder(); + foreach (var line in pemLines) + { + var trimmed = line.Trim(); + if (!trimmed.StartsWith("-----") && !string.IsNullOrEmpty(trimmed)) + { + base64.Append(trimmed); + } + } + + var keyBytes = Convert.FromBase64String(base64.ToString()); + + // Unity kompatibilní import - parsujeme SubjectPublicKeyInfo ručně + ImportSubjectPublicKeyInfoManual(rsa, keyBytes); + + // Používáme OaepSHA1 pro Unity kompatibilitu (OaepSHA256 není podporován) + var encryptedKey = rsa.Encrypt(_sessionKey, RSAEncryptionPadding.OaepSHA1); + var encryptedIv = rsa.Encrypt(_sessionIv, RSAEncryptionPadding.OaepSHA1); + + return (Convert.ToBase64String(encryptedKey), Convert.ToBase64String(encryptedIv)); + } + } + + // Ručně parsuje SubjectPublicKeyInfo (DER) a importuje RSA klíč - Unity kompatibilní + private static void ImportSubjectPublicKeyInfoManual(RSA rsa, byte[] subjectPublicKeyInfo) + { + // SubjectPublicKeyInfo ::= SEQUENCE { + // algorithm AlgorithmIdentifier, + // subjectPublicKey BIT STRING } + // RSAPublicKey ::= SEQUENCE { modulus INTEGER, publicExponent INTEGER } + + int index = 0; + + // Outer SEQUENCE + if (subjectPublicKeyInfo[index++] != 0x30) + throw new InvalidOperationException("Invalid SubjectPublicKeyInfo"); + ReadLength(subjectPublicKeyInfo, ref index); + + // AlgorithmIdentifier SEQUENCE - skip it + if (subjectPublicKeyInfo[index++] != 0x30) + throw new InvalidOperationException("Invalid AlgorithmIdentifier"); + int algLen = ReadLength(subjectPublicKeyInfo, ref index); + index += algLen; + + // BIT STRING containing RSAPublicKey + if (subjectPublicKeyInfo[index++] != 0x03) + throw new InvalidOperationException("Invalid BIT STRING"); + ReadLength(subjectPublicKeyInfo, ref index); + index++; // Skip unused bits byte (should be 0) + + // RSAPublicKey SEQUENCE + if (subjectPublicKeyInfo[index++] != 0x30) + throw new InvalidOperationException("Invalid RSAPublicKey"); + ReadLength(subjectPublicKeyInfo, ref index); + + // Modulus INTEGER + byte[] modulus = ReadInteger(subjectPublicKeyInfo, ref index); + + // Exponent INTEGER + byte[] exponent = ReadInteger(subjectPublicKeyInfo, ref index); + + var parameters = new RSAParameters + { + Modulus = modulus, + Exponent = exponent + }; + rsa.ImportParameters(parameters); + } + + private static int ReadLength(byte[] data, ref int index) + { + int length = data[index++]; + if ((length & 0x80) != 0) + { + int numBytes = length & 0x7F; + length = 0; + for (int i = 0; i < numBytes; i++) + { + length = (length << 8) | data[index++]; + } + } + return length; + } + + private static byte[] ReadInteger(byte[] data, ref int index) + { + if (data[index++] != 0x02) + throw new InvalidOperationException("Expected INTEGER"); + int length = ReadLength(data, ref index); + + // Skip leading zero if present (used for positive sign in DER) + int originalLength = length; + int start = index; + if (length > 1 && data[start] == 0x00) + { + start++; + length--; + } + + byte[] result = new byte[length]; + Buffer.BlockCopy(data, start, result, 0, length); + index += originalLength; + + return result; + } + + // Šifruje zprávu pomocí AES-256-CBC s HMAC + public byte[] Encrypt(byte[] plaintext) + { + if (_sessionKey == null || _sessionIv == null) + throw new InvalidOperationException("Session key not set"); + + lock (_lock) + { + // Generuj unikátní IV pro tuto zprávu + var iv = GetNextIV(); + + using (var aes = Aes.Create()) + { + aes.Key = _sessionKey; + aes.IV = iv; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + byte[] ciphertext; + using (var encryptor = aes.CreateEncryptor()) + using (var ms = new MemoryStream()) + { + using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) + { + cs.Write(plaintext, 0, plaintext.Length); + } + ciphertext = ms.ToArray(); + } + + // Compute HMAC pro integritu + byte[] hmac; + using (var hmacSha = new HMACSHA256(_sessionKey)) + { + var toSign = new byte[iv.Length + ciphertext.Length]; + Buffer.BlockCopy(iv, 0, toSign, 0, iv.Length); + Buffer.BlockCopy(ciphertext, 0, toSign, iv.Length, ciphertext.Length); + hmac = hmacSha.ComputeHash(toSign); + } + + // Výstup: [16 bytes IV][32 bytes HMAC][ciphertext] + var result = new byte[16 + 32 + ciphertext.Length]; + Buffer.BlockCopy(iv, 0, result, 0, 16); + Buffer.BlockCopy(hmac, 0, result, 16, 32); + Buffer.BlockCopy(ciphertext, 0, result, 48, ciphertext.Length); + + return result; + } + } + } + + // Dešifruje zprávu pomocí AES-256-CBC s HMAC ověřením + public byte[] Decrypt(byte[] encrypted) + { + if (_sessionKey == null) + throw new InvalidOperationException("Session key not set"); + + if (encrypted.Length < 48) return null; + + try + { + var iv = new byte[16]; + var hmac = new byte[32]; + var ciphertext = new byte[encrypted.Length - 48]; + + Buffer.BlockCopy(encrypted, 0, iv, 0, 16); + Buffer.BlockCopy(encrypted, 16, hmac, 0, 32); + Buffer.BlockCopy(encrypted, 48, ciphertext, 0, ciphertext.Length); + + // Ověř HMAC + byte[] expectedHmac; + using (var hmacSha = new HMACSHA256(_sessionKey)) + { + var toVerify = new byte[iv.Length + ciphertext.Length]; + Buffer.BlockCopy(iv, 0, toVerify, 0, iv.Length); + Buffer.BlockCopy(ciphertext, 0, toVerify, iv.Length, ciphertext.Length); + expectedHmac = hmacSha.ComputeHash(toVerify); + } + + // Constant-time compare + var diff = 0; + for (int i = 0; i < 32; i++) + { + diff |= hmac[i] ^ expectedHmac[i]; + } + if (diff != 0) return null; // HMAC mismatch + + using (var aes = Aes.Create()) + { + aes.Key = _sessionKey; + aes.IV = iv; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + using (var decryptor = aes.CreateDecryptor()) + using (var ms = new MemoryStream(ciphertext)) + using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) + using (var output = new MemoryStream()) + { + cs.CopyTo(output); + return output.ToArray(); + } + } + } + catch (CryptographicException) + { + return null; + } + } + + private byte[] GetNextIV() + { + if (_sessionIv == null) + throw new InvalidOperationException("Session IV not set"); + + var iv = new byte[16]; + Buffer.BlockCopy(_sessionIv, 0, iv, 0, 8); + + var counter = System.Threading.Interlocked.Increment(ref _nonceCounter); + var counterBytes = BitConverter.GetBytes(counter); + Buffer.BlockCopy(counterBytes, 0, iv, 8, 8); + + return iv; + } + + public void Dispose() + { + if (_sessionKey != null) + { + Array.Clear(_sessionKey, 0, _sessionKey.Length); + _sessionKey = null; + } + } + } +} diff --git a/Assets/ClientSDK/Encryption.cs.meta b/Assets/ClientSDK/Encryption.cs.meta new file mode 100644 index 0000000..f850920 --- /dev/null +++ b/Assets/ClientSDK/Encryption.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bc06bb57786c7e142b06ec231e5cf709 \ No newline at end of file diff --git a/Assets/ClientSDK/EventDispatcher.cs b/Assets/ClientSDK/EventDispatcher.cs new file mode 100644 index 0000000..839def1 --- /dev/null +++ b/Assets/ClientSDK/EventDispatcher.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace GeoSus.Client +{ + // Event dispatcher pro Unity main thread +// Unity může přidat SynchronizationContext, nebo polling z Update() +public class EventDispatcher +{ + private readonly Queue _pendingActions = new Queue(); + private readonly object _lock = new object(); + private SynchronizationContext? _syncContext; + + public EventDispatcher() + { + // Pokusíme se zachytit aktuální synchronization context (Unity main thread) + _syncContext = SynchronizationContext.Current; + } + + // Volat z networking vlákna - naplánuje callback na main thread + public void Post(Action action) + { + if (_syncContext != null) + { + _syncContext.Post(_ => action(), null); + } + else + { + // Fallback - přidáme do fronty pro polling + lock (_lock) + { + _pendingActions.Enqueue(action); + } + } + } + + // Volat z Unity Update() pokud není SynchronizationContext + public void ProcessPendingActions() + { + Action[] actions; + lock (_lock) + { + if (_pendingActions.Count == 0) return; + actions = _pendingActions.ToArray(); + _pendingActions.Clear(); + } + + foreach (var action in actions) + { + try + { + action(); + } + catch (Exception ex) + { + Console.WriteLine($"EventDispatcher error: {ex}"); + } + } + } + + public int PendingCount + { + get + { + lock (_lock) + { + return _pendingActions.Count; + } + } + } +} +} diff --git a/Assets/ClientSDK/EventDispatcher.cs.meta b/Assets/ClientSDK/EventDispatcher.cs.meta new file mode 100644 index 0000000..2eaf448 --- /dev/null +++ b/Assets/ClientSDK/EventDispatcher.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1d2251b279edb0147bd274a884ac878b \ No newline at end of file diff --git a/Assets/ClientSDK/GameClient.cs b/Assets/ClientSDK/GameClient.cs new file mode 100644 index 0000000..09fa7f1 --- /dev/null +++ b/Assets/ClientSDK/GameClient.cs @@ -0,0 +1,607 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace GeoSus.Client +{ + // Hlavní klientská třída pro připojení k serveru +public class GameClient : IDisposable +{ + private TcpClient? _tcpClient; + private NetworkStream? _stream; + private ClientEncryption? _encryption; + private CancellationTokenSource? _cts; + private Task? _receiveTask; + private int _clientSeq; + private readonly object _sendLock = new object(); + private bool _handshakeComplete; + + public string ClientUuid { get; } + public string DisplayName { get; set; } + public bool IsConnected => _tcpClient?.Connected ?? false; + public bool IsReady => IsConnected && _handshakeComplete && (_encryption?.HasSessionKey ?? false); + public EventDispatcher Dispatcher { get; } + + // Events - voláno na main thread přes dispatcher + public event Action? OnConnected; + public event Action? OnDisconnected; + public event Action? OnError; + public event Action? OnMessage; + public event Action? OnGameEvent; + + // Lobby state + public string? LobbyId { get; private set; } + public string? JoinCode { get; private set; } + public LobbyState? CurrentLobbyState { get; private set; } + public PlayerRole? MyRole { get; private set; } + public List MyTasks { get; } = new List(); + public Position MyPosition { get; set; } + public Dictionary PlayerPositions { get; } = new Dictionary(); + public List Bodies { get; } = new List(); + public int Ping { get; private set; } + public long LastEventId { get; private set; } + + /// Returns true if this client is the current lobby owner + public bool IsOwner => CurrentLobbyState?.OwnerId == ClientUuid; + + public GameClient(string clientUuid, string displayName) + { + ClientUuid = clientUuid; + DisplayName = displayName; + Dispatcher = new EventDispatcher(); + } + + #region Connection + + public async Task ConnectAsync(string host, int port) + { + try + { + _tcpClient = new TcpClient(); + await _tcpClient.ConnectAsync(host, port); + _stream = _tcpClient.GetStream(); + _encryption = new ClientEncryption(); + _cts = new CancellationTokenSource(); + + // Handshake + if (!await PerformHandshakeAsync()) + { + Disconnect("Handshake failed"); + return false; + } + + // Spustíme příjem zpráv + _receiveTask = Task.Run(() => ReceiveLoopAsync(_cts.Token)); + + Dispatcher.Post(() => OnConnected?.Invoke()); + return true; + } + catch (Exception ex) + { + Dispatcher.Post(() => OnError?.Invoke(ex.Message)); + return false; + } + } + + private async Task PerformHandshakeAsync() + { + if (_stream == null || _encryption == null) return false; + + // 1. ClientHello + var hello = new ClientHello + { + ClientUuid = ClientUuid, + DisplayName = DisplayName + }; + await SendPlainAsync(hello); + + // 2. ServerHello + var serverHelloData = await ReadMessageAsync(); + if (serverHelloData == null) return false; + + var serverHello = MessageSerializer.Deserialize(serverHelloData) as ServerHello; + if (serverHello == null) return false; + + // 3. Generujeme session key a šifrujeme RSA + _encryption.GenerateSessionKey(); + var (encKey, encIv) = _encryption.EncryptSessionKeyForServer(serverHello.RsaPublicKeyPem); + + var keyExchange = new KeyExchange + { + EncryptedSessionKey = encKey, + EncryptedIV = encIv + }; + await SendPlainAsync(keyExchange); + + // 4. KeyExchangeAck (šifrovaně) + var ackData = await ReadMessageAsync(); + if (ackData == null) return false; + + var decrypted = _encryption.Decrypt(ackData); + if (decrypted == null) return false; + + var ack = MessageSerializer.Deserialize(decrypted) as KeyExchangeAck; + if (ack?.Status == "success") + { + _handshakeComplete = true; + return true; + } + return false; + } + + public void Disconnect(string reason = "User disconnected") + { + _cts?.Cancel(); + _tcpClient?.Close(); + _tcpClient = null; + _stream = null; + _encryption?.Dispose(); + _encryption = null; + + LobbyId = null; + JoinCode = null; + CurrentLobbyState = null; + MyRole = null; + MyTasks.Clear(); + PlayerPositions.Clear(); + Bodies.Clear(); + + Dispatcher.Post(() => OnDisconnected?.Invoke(reason)); + } + + #endregion + + #region Sending + + public void Send(Message message) + { + if (_stream == null || _encryption == null || !IsConnected) return; + + message.ClientSeq = Interlocked.Increment(ref _clientSeq); + if (string.IsNullOrEmpty(message.ActionId)) + { + message.ActionId = Guid.NewGuid().ToString("N").Substring(0, 8); + } + + var plain = MessageSerializer.Serialize(message); + var encrypted = _encryption.Encrypt(plain); + + lock (_sendLock) + { + try + { + SendData(encrypted); + } + catch (Exception ex) + { + Dispatcher.Post(() => OnError?.Invoke($"Send error: {ex.Message}")); + } + } + } + + private async Task SendPlainAsync(Message message) + { + if (_stream == null) return; + var data = MessageSerializer.Serialize(message); + await SendDataAsync(data); + } + + private void SendData(byte[] data) + { + if (_stream == null) return; + + var lengthBuffer = BitConverter.GetBytes(data.Length); + if (BitConverter.IsLittleEndian) + Array.Reverse(lengthBuffer); + + _stream.Write(lengthBuffer, 0, 4); + _stream.Write(data, 0, data.Length); + _stream.Flush(); + } + + private async Task SendDataAsync(byte[] data) + { + if (_stream == null) return; + + var lengthBuffer = BitConverter.GetBytes(data.Length); + if (BitConverter.IsLittleEndian) + Array.Reverse(lengthBuffer); + + await _stream.WriteAsync(lengthBuffer, 0, 4); + await _stream.WriteAsync(data, 0, data.Length); + await _stream.FlushAsync(); + } + + #endregion + + #region Receiving + + private async Task ReceiveLoopAsync(CancellationToken ct) + { + int decryptFailures = 0; + + try + { + while (!ct.IsCancellationRequested && IsConnected) + { + var data = await ReadMessageAsync(); + if (data == null) break; + + var decrypted = _encryption?.Decrypt(data); + if (decrypted == null) + { + decryptFailures++; + if (decryptFailures >= 3) + { + Disconnect("Too many decryption failures"); + return; + } + continue; + } + + decryptFailures = 0; + + var message = MessageSerializer.Deserialize(decrypted); + if (message != null) + { + ProcessMessage(message); + } + } + } + catch (Exception ex) when (!ct.IsCancellationRequested) + { + Disconnect($"Connection error: {ex.Message}"); + } + } + + private async Task ReadMessageAsync() + { + if (_stream == null) return null; + + var lengthBuffer = new byte[4]; + var read = await _stream.ReadAsync(lengthBuffer, 0, 4); + if (read < 4) return null; + + if (BitConverter.IsLittleEndian) + Array.Reverse(lengthBuffer); + var length = BitConverter.ToInt32(lengthBuffer, 0); + + if (length <= 0 || length > 1048576) return null; + + var buffer = new byte[length]; + var totalRead = 0; + while (totalRead < length) + { + read = await _stream.ReadAsync(buffer, totalRead, length - totalRead); + if (read == 0) return null; + totalRead += read; + } + + return buffer; + } + + private void ProcessMessage(Message message) + { + // Zpracujeme speciální typy + switch (message) + { + case CreateLobbyResponse r: + if (r.Success) + { + LobbyId = r.LobbyId; + JoinCode = r.JoinCode; + CurrentLobbyState = r.LobbyState; + } + break; + + case JoinLobbyResponse r: + if (r.Success) + { + LobbyId = r.LobbyId; + CurrentLobbyState = r.LobbyState; + JoinCode = r.LobbyState?.JoinCode; + } + break; + + case PositionBroadcast b: + ProcessPositionBroadcast(b); + break; + + case Pong p: + var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + Ping = (int)(now - p.ClientTime); + break; + + case GameEvent evt: + ProcessGameEvent(evt); + Dispatcher.Post(() => OnGameEvent?.Invoke(evt)); + break; + } + + Dispatcher.Post(() => OnMessage?.Invoke(message)); + } + + private void ProcessPositionBroadcast(PositionBroadcast broadcast) + { + PlayerPositions.Clear(); + foreach (var player in broadcast.Players) + { + PlayerPositions[player.ClientUuid] = player; + } + } + + private void ProcessGameEvent(GameEvent evt) + { + LastEventId = evt.EventId; + + switch (evt.EventType) + { + case "PlayerJoined": + // Add player to lobby state + var joinedPayload = evt.GetPayload(); + if (joinedPayload != null && CurrentLobbyState?.Players != null) + { + // Check if player already exists + bool exists = CurrentLobbyState.Players.Any(p => p.ClientUuid == joinedPayload.ClientUuid); + if (!exists) + { + CurrentLobbyState.Players.Add(new PlayerInfo + { + ClientUuid = joinedPayload.ClientUuid, + DisplayName = joinedPayload.DisplayName, + IsOwner = false, + IsReady = false, + State = PlayerState.Alive + }); + } + } + break; + + case "PlayerLeft": + // Remove player from lobby state + var leftPayload = evt.GetPayload(); + if (leftPayload != null && CurrentLobbyState?.Players != null) + { + CurrentLobbyState.Players.RemoveAll(p => p.ClientUuid == leftPayload.ClientUuid); + } + break; + + case "HostChanged": + // Update lobby owner + var hostPayload = evt.GetPayload(); + if (hostPayload != null && CurrentLobbyState != null) + { + CurrentLobbyState.OwnerId = hostPayload.NewHostId; + // Update IsOwner flag on all players + foreach (var player in CurrentLobbyState.Players) + { + player.IsOwner = player.ClientUuid == hostPayload.NewHostId; + } + } + break; + + case "GameStarting": + // Game is entering loading phase - update lobby state if available + if (CurrentLobbyState != null) + { + CurrentLobbyState.Phase = GamePhase.Loading; + } + break; + + case "MapDataReady": + // Map data received - store it and send confirmation + var mapDataPayload = evt.GetPayload(); + if (mapDataPayload != null && CurrentLobbyState != null) + { + CurrentLobbyState.MapData = mapDataPayload.MapData; + CurrentLobbyState.MapDataReady = true; + } + // Send confirmation to server + Send(new MapDataReceived()); + break; + + case "GameStarted": + // Game officially started - update phase + if (CurrentLobbyState != null) + { + CurrentLobbyState.Phase = GamePhase.Playing; + } + break; + + case "RoleAssigned": + var rolePayload = evt.GetPayload(); + if (rolePayload != null && rolePayload.ClientUuid == ClientUuid) + { + MyRole = rolePayload.Role; + MyTasks.Clear(); + if (rolePayload.Tasks != null) + { + MyTasks.AddRange(rolePayload.Tasks); + } + } + break; + + case "PlayerKilled": + var killPayload = evt.GetPayload(); + if (killPayload != null) + { + Bodies.Add(new Body + { + BodyId = killPayload.BodyId, + VictimId = killPayload.VictimId, + Location = killPayload.Location + }); + } + break; + + case "MeetingStarted": + if (CurrentLobbyState != null) + { + CurrentLobbyState.Phase = GamePhase.Meeting; + } + break; + + case "VotingClosed": + Bodies.Clear(); // Bodies zmizí po meetingu + if (CurrentLobbyState != null) + { + CurrentLobbyState.Phase = GamePhase.Playing; + } + break; + + case "GameEnded": + if (CurrentLobbyState != null) + { + CurrentLobbyState.Phase = GamePhase.Ended; + } + break; + } + } + + #endregion + + #region Game Actions + + public void CreateLobby(Position? center = null, int impostorCount = 1, int taskCount = 5, string? password = null, double playAreaRadius = 500) + { + Send(new CreateLobby + { + PlayAreaCenter = center, + PlayAreaRadius = playAreaRadius, + ImpostorCount = impostorCount, + TaskCount = taskCount, + Password = password + }); + } + + public void JoinLobby(string joinCode, string? password = null) + { + Send(new JoinLobby + { + JoinCode = joinCode.ToUpperInvariant(), + Password = password + }); + } + + public void LeaveLobby() + { + Send(new LeaveLobby()); + LobbyId = null; + JoinCode = null; + } + + public void StartGame() + { + Send(new StartGame()); + } + + public void ReturnToLobby() + { + Send(new ReturnToLobby()); + } + + public void UpdatePosition(Position position) + { + MyPosition = position; + Send(new UpdatePosition { Position = position }); + } + + public void Kill(string targetUuid) + { + Send(new KillAttempt { TargetClientUuid = targetUuid }); + } + + public void ReportBody(string bodyId) + { + Send(new ReportBody { BodyId = bodyId }); + } + + public void CallEmergencyMeeting() + { + Send(new CallEmergencyMeeting()); + } + + public void Vote(string? targetUuid) + { + Send(new CastVote { TargetClientUuid = targetUuid }); + } + + /// + /// Pokus o dokončení tasku. Server ověří že hráč je na správné pozici. + /// + public void CompleteTask(string taskId) + { + Send(new TaskComplete { TaskId = taskId }); + } + + public void SendPing() + { + Send(new Ping { ClientTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }); + } + + public void Reconnect(string lobbyId) + { + Send(new Reconnect { LobbyId = lobbyId, LastEventId = LastEventId }); + } + + #endregion + + #region Helpers + + public Body? FindNearbyBody(double maxDistance) + { + foreach (var body in Bodies) + { + if (MyPosition.DistanceTo(body.Location) <= maxDistance) + { + return body; + } + } + return null; + } + + public string? FindNearbyPlayer(double maxDistance, bool aliveOnly = true) + { + foreach (var (uuid, info) in PlayerPositions) + { + if (uuid == ClientUuid) continue; + if (aliveOnly && info.State != PlayerState.Alive) continue; + + if (MyPosition.DistanceTo(info.Position) <= maxDistance) + { + return uuid; + } + } + return null; + } + + public GameTask? FindNearbyTask(double maxDistance) + { + foreach (var task in MyTasks) + { + if (MyPosition.DistanceTo(task.Location) <= maxDistance) + { + return task; + } + } + return null; + } + + // Volat z Unity Update() pro zpracování callbacků + public void Update() + { + Dispatcher.ProcessPendingActions(); + } + + #endregion + + public void Dispose() + { + Disconnect("Disposed"); + _encryption?.Dispose(); + } +} +} diff --git a/Assets/ClientSDK/GameClient.cs.meta b/Assets/ClientSDK/GameClient.cs.meta new file mode 100644 index 0000000..b454c2d --- /dev/null +++ b/Assets/ClientSDK/GameClient.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 91e0f647c37b0b94b83f53bb854db28c \ No newline at end of file diff --git a/Assets/ClientSDK/Protocol.cs b/Assets/ClientSDK/Protocol.cs new file mode 100644 index 0000000..f6d4d04 --- /dev/null +++ b/Assets/ClientSDK/Protocol.cs @@ -0,0 +1,1054 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Converters; +using System.Collections.Generic; +using System.Text; + +namespace GeoSus.Client +{ + #region Základní typy + +public struct Position +{ + [JsonProperty("lat")] + public double Lat { get; set; } + + [JsonProperty("lon")] + public double Lon { get; set; } + + public Position(double lat, double lon) + { + Lat = lat; + Lon = lon; + } + + // Haversine vzdálenost v metrech + public double DistanceTo(Position other) + { + const double R = 6371000; + var lat1 = Lat * Math.PI / 180; + var lat2 = other.Lat * Math.PI / 180; + var dLat = (other.Lat - Lat) * Math.PI / 180; + var dLon = (other.Lon - Lon) * Math.PI / 180; + + var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + + Math.Cos(lat1) * Math.Cos(lat2) * + Math.Sin(dLon / 2) * Math.Sin(dLon / 2); + var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); + + return R * c; + } +} + +[JsonConverter(typeof(StringEnumConverter))] +public enum PlayerRole { Crew, Impostor } + +[JsonConverter(typeof(StringEnumConverter))] +public enum PlayerState { Alive, Dead } + +[JsonConverter(typeof(StringEnumConverter))] +public enum GamePhase { Lobby, Loading, Playing, Meeting, Voting, Ended } + +[JsonConverter(typeof(StringEnumConverter))] +public enum TaskType { Instant } + +[JsonConverter(typeof(StringEnumConverter))] +public enum MeetingType { BodyReport, Emergency } + +[JsonConverter(typeof(StringEnumConverter))] +public enum SabotageType { CommsBlackout, CriticalMeltdown } + +[JsonConverter(typeof(StringEnumConverter))] +public enum SabotageState { Inactive, Active, Repaired } + +// Map data types for Overpass integration +[JsonConverter(typeof(StringEnumConverter))] +public enum PathType +{ + Footway, + Path, + Steps, + Cycleway, + Pedestrian, + Road, + Service, + Residential, + Track, + Other +} + +[JsonConverter(typeof(StringEnumConverter))] +public enum MapAreaType +{ + Park, + Garden, + Playground, + Forest, + Grass, + Water, + Other +} + +[JsonConverter(typeof(StringEnumConverter))] +public enum MapPOIType +{ + FoodDrink, // Restaurants, cafes, bars + Shop, // Shops + Health, // Pharmacies, hospitals + Transport, // Bus stops, parking + Culture, // Museums, theaters + Landmark, // Churches, monuments + Recreation, // Parks, playgrounds + Other +} + +#endregion + +#region Zprávy + +public abstract class Message +{ + [JsonProperty("type")] + public abstract string Type { get; } + + [JsonProperty("clientSeq")] + public int ClientSeq { get; set; } + + [JsonProperty("actionId")] + public string? ActionId { get; set; } +} + +// Handshake +public class ClientHello : Message +{ + public override string Type => "ClientHello"; + + [JsonProperty("protocolVersion")] + public string ProtocolVersion { get; set; } = "1.0"; + + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("displayName")] + public string? DisplayName { get; set; } +} + +public class ServerHello : Message +{ + public override string Type => "ServerHello"; + + [JsonProperty("rsaPublicKeyPem")] + public string RsaPublicKeyPem { get; set; } = ""; + + [JsonProperty("serverId")] + public string ServerId { get; set; } = ""; +} + +public class KeyExchange : Message +{ + public override string Type => "KeyExchange"; + + [JsonProperty("encryptedSessionKey")] + public string EncryptedSessionKey { get; set; } = ""; + + [JsonProperty("encryptedIV")] + public string EncryptedIV { get; set; } = ""; +} + +public class KeyExchangeAck : Message +{ + public override string Type => "KeyExchangeAck"; + + [JsonProperty("status")] + public string Status { get; set; } = ""; +} + +// Lobby +public class CreateLobby : Message +{ + public override string Type => "CreateLobby"; + + [JsonProperty("password")] + public string? Password { get; set; } + + [JsonProperty("playAreaCenter")] + public Position? PlayAreaCenter { get; set; } + + [JsonProperty("playAreaRadius")] + public double PlayAreaRadius { get; set; } = 500; + + [JsonProperty("impostorCount")] + public int ImpostorCount { get; set; } = 1; + + [JsonProperty("taskCount")] + public int TaskCount { get; set; } = 5; +} + +public class CreateLobbyResponse : Message +{ + public override string Type => "CreateLobbyResponse"; + + [JsonProperty("success")] + public bool Success { get; set; } + + [JsonProperty("joinCode")] + public string? JoinCode { get; set; } + + [JsonProperty("lobbyId")] + public string? LobbyId { get; set; } + + [JsonProperty("error")] + public string? Error { get; set; } + + [JsonProperty("lobbyState")] + public LobbyState? LobbyState { get; set; } +} + +public class JoinLobby : Message +{ + public override string Type => "JoinLobby"; + + [JsonProperty("joinCode")] + public string JoinCode { get; set; } = ""; + + [JsonProperty("password")] + public string? Password { get; set; } +} + +public class JoinLobbyResponse : Message +{ + public override string Type => "JoinLobbyResponse"; + + [JsonProperty("success")] + public bool Success { get; set; } + + [JsonProperty("lobbyId")] + public string? LobbyId { get; set; } + + [JsonProperty("error")] + public string? Error { get; set; } + + [JsonProperty("lobbyState")] + public LobbyState? LobbyState { get; set; } +} + +public class LeaveLobby : Message +{ + public override string Type => "LeaveLobby"; +} + +public class ReturnToLobby : Message +{ + public override string Type => "ReturnToLobby"; +} + +public class StartGame : Message +{ + public override string Type => "StartGame"; +} + +// Client confirmation that map data was received +public class MapDataReceived : Message +{ + public override string Type => "MapDataReceived"; +} + +// Hra +public class UpdatePosition : Message +{ + public override string Type => "UpdatePosition"; + + [JsonProperty("position")] + public Position Position { get; set; } +} + +public class PositionBroadcast : Message +{ + public override string Type => "PositionBroadcast"; + + [JsonProperty("players")] + public List Players { get; set; } = new List(); +} + +public class PlayerPositionInfo +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("position")] + public Position Position { get; set; } + + [JsonProperty("state")] + public PlayerState State { get; set; } +} + +public class KillAttempt : Message +{ + public override string Type => "KillAttempt"; + + [JsonProperty("targetClientUuid")] + public string TargetClientUuid { get; set; } = ""; +} + +public class ReportBody : Message +{ + public override string Type => "ReportBody"; + + [JsonProperty("bodyId")] + public string BodyId { get; set; } = ""; +} + +public class CallEmergencyMeeting : Message +{ + public override string Type => "CallEmergencyMeeting"; +} + +public class CastVote : Message +{ + public override string Type => "CastVote"; + + [JsonProperty("targetClientUuid")] + public string? TargetClientUuid { get; set; } +} + +public class TaskStart : Message +{ + public override string Type => "TaskStart"; + + [JsonProperty("taskId")] + public string TaskId { get; set; } = ""; +} + +public class TaskProgress : Message +{ + public override string Type => "TaskProgress"; + + [JsonProperty("taskId")] + public string TaskId { get; set; } = ""; + + [JsonProperty("step")] + public int Step { get; set; } = 1; +} + +public class TaskComplete : Message +{ + public override string Type => "TaskComplete"; + + [JsonProperty("taskId")] + public string TaskId { get; set; } = ""; +} + +public class Ping : Message +{ + public override string Type => "Ping"; + + [JsonProperty("clientTime")] + public long ClientTime { get; set; } +} + +public class Pong : Message +{ + public override string Type => "Pong"; + + [JsonProperty("clientTime")] + public long ClientTime { get; set; } + + [JsonProperty("serverTime")] + public long ServerTime { get; set; } +} + +public class Reconnect : Message +{ + public override string Type => "Reconnect"; + + [JsonProperty("lobbyId")] + public string LobbyId { get; set; } = ""; + + [JsonProperty("lastEventId")] + public long LastEventId { get; set; } +} + +public class Ack : Message +{ + public override string Type => "Ack"; + + [JsonProperty("ackedSeq")] + public int AckedSeq { get; set; } + + [JsonProperty("success")] + public bool Success { get; set; } + + [JsonProperty("error")] + public string? Error { get; set; } +} + +public class ErrorMessage : Message +{ + public override string Type => "Error"; + + [JsonProperty("errorCode")] + public string ErrorCode { get; set; } = ""; + + [JsonProperty("errorText")] + public string ErrorText { get; set; } = ""; +} + +// Sabotage messages +public class StartSabotage : Message +{ + public override string Type => "StartSabotage"; + + [JsonProperty("sabotageType")] + public SabotageType SabotageType { get; set; } +} + +public class ActivateRepairStation : Message +{ + public override string Type => "ActivateRepairStation"; + + [JsonProperty("stationId")] + public string StationId { get; set; } = ""; +} + +public class DeactivateRepairStation : Message +{ + public override string Type => "DeactivateRepairStation"; + + [JsonProperty("stationId")] + public string StationId { get; set; } = ""; +} + +#endregion + +#region Eventy + +public class GameEvent : Message +{ + public override string Type => "GameEvent"; + + [JsonProperty("eventId")] + public long EventId { get; set; } + + [JsonProperty("serverSeq")] + public long ServerSeq { get; set; } + + [JsonProperty("timestamp")] + public DateTime Timestamp { get; set; } + + [JsonProperty("actor")] + public string? Actor { get; set; } + + [JsonProperty("eventType")] + public string EventType { get; set; } = ""; + + [JsonProperty("payload")] + public JObject? Payload { get; set; } + + public T? GetPayload() where T : class + { + if (Payload == null) return null; + return Payload.ToObject(JsonSerializer.Create(JsonOptions.Default)); + } +} + +// Payload typy +public class HostChangedPayload +{ + [JsonProperty("newHostId")] + public string NewHostId { get; set; } = ""; + + [JsonProperty("previousHostId")] + public string PreviousHostId { get; set; } = ""; +} + +public class PlayerJoinedPayload +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("displayName")] + public string DisplayName { get; set; } = ""; +} + +public class PlayerLeftPayload +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("reason")] + public string? Reason { get; set; } +} + +// Loading phase payloads +public class GameStartingPayload +{ + [JsonProperty("message")] + public string Message { get; set; } = ""; +} + +public class MapDataReadyPayload +{ + [JsonProperty("mapData")] + public MapDataPayload? MapData { get; set; } +} + +public class PlayerMapDataReceivedPayload +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("displayName")] + public string DisplayName { get; set; } = ""; + + [JsonProperty("playersReady")] + public int PlayersReady { get; set; } + + [JsonProperty("totalPlayers")] + public int TotalPlayers { get; set; } +} + +public class GameStartedPayload +{ + [JsonProperty("impostorCount")] + public int ImpostorCount { get; set; } + + [JsonProperty("taskCount")] + public int TaskCount { get; set; } +} + +public class RoleAssignedPayload +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("role")] + public PlayerRole Role { get; set; } + + [JsonProperty("tasks")] + public List? Tasks { get; set; } +} + +public class PlayerKilledPayload +{ + [JsonProperty("victimId")] + public string VictimId { get; set; } = ""; + + [JsonProperty("killerId")] + public string KillerId { get; set; } = ""; + + [JsonProperty("bodyId")] + public string BodyId { get; set; } = ""; + + [JsonProperty("location")] + public Position Location { get; set; } +} + +public class BodyReportedPayload +{ + [JsonProperty("reporterId")] + public string ReporterId { get; set; } = ""; + + [JsonProperty("bodyId")] + public string BodyId { get; set; } = ""; + + [JsonProperty("victimId")] + public string VictimId { get; set; } = ""; +} + +public class EmergencyMeetingCalledPayload +{ + [JsonProperty("callerId")] + public string CallerId { get; set; } = ""; +} + +public class MeetingStartedPayload +{ + [JsonProperty("meetingId")] + public string MeetingId { get; set; } = ""; + + [JsonProperty("type")] + public MeetingType Type { get; set; } + + [JsonProperty("meetingLocation")] + public Position MeetingLocation { get; set; } + + [JsonProperty("arrivalDeadline")] + public DateTime ArrivalDeadline { get; set; } + + [JsonProperty("discussionEndTime")] + public DateTime? DiscussionEndTime { get; set; } + + [JsonProperty("votingEndTime")] + public DateTime VotingEndTime { get; set; } +} + +public class PlayerArrivedAtMeetingPayload +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("meetingId")] + public string MeetingId { get; set; } = ""; +} + +public class PlayerVotedPayload +{ + [JsonProperty("voterId")] + public string VoterId { get; set; } = ""; + + [JsonProperty("targetId")] + public string? TargetId { get; set; } +} + +public class VotingClosedPayload +{ + [JsonProperty("voteCounts")] + public Dictionary VoteCounts { get; set; } = new Dictionary(); + + [JsonProperty("ejectedPlayerId")] + public string? EjectedPlayerId { get; set; } + + [JsonProperty("wasTie")] + public bool WasTie { get; set; } +} + +public class PlayerEjectedPayload +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("role")] + public PlayerRole Role { get; set; } +} + +public class TaskCompletedPayload +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("taskId")] + public string TaskId { get; set; } = ""; + + [JsonProperty("totalCompleted")] + public int TotalCompleted { get; set; } + + [JsonProperty("totalTasks")] + public int TotalTasks { get; set; } +} + +public class GameEndedPayload +{ + [JsonProperty("winningFaction")] + public string WinningFaction { get; set; } = ""; + + [JsonProperty("reason")] + public string Reason { get; set; } = ""; + + [JsonProperty("winners")] + public List Winners { get; set; } = new List(); +} + +public class ReturnedToLobbyPayload +{ + [JsonProperty("message")] + public string Message { get; set; } = ""; +} + +// System message payload (admin broadcast) +public class SystemMessagePayload +{ + [JsonProperty("message")] + public string Message { get; set; } = ""; + + [JsonProperty("timestamp")] + public DateTime Timestamp { get; set; } +} + +// Sabotage event payloads +public class SabotageStartedPayload +{ + [JsonProperty("sabotageId")] + public string SabotageId { get; set; } = ""; + + [JsonProperty("type")] + public SabotageType Type { get; set; } + + [JsonProperty("initiatorId")] + public string InitiatorId { get; set; } = ""; + + [JsonProperty("deadline")] + public DateTime? Deadline { get; set; } + + [JsonProperty("repairStations")] + public List RepairStations { get; set; } = new List(); + + [JsonProperty("requiredSimultaneousRepairs")] + public int RequiredSimultaneousRepairs { get; set; } +} + +public class RepairStationInfo +{ + [JsonProperty("stationId")] + public string StationId { get; set; } = ""; + + [JsonProperty("name")] + public string Name { get; set; } = ""; + + [JsonProperty("location")] + public Position Location { get; set; } + + [JsonProperty("repairDurationMs")] + public int RepairDurationMs { get; set; } + + /// + /// Track locally if this station has been repaired + /// + [JsonIgnore] + public bool IsRepaired { get; set; } +} + +public class RepairStartedPayload +{ + [JsonProperty("sabotageId")] + public string SabotageId { get; set; } = ""; + + [JsonProperty("stationId")] + public string StationId { get; set; } = ""; + + [JsonProperty("playerId")] + public string PlayerId { get; set; } = ""; +} + +public class RepairStoppedPayload +{ + [JsonProperty("sabotageId")] + public string SabotageId { get; set; } = ""; + + [JsonProperty("stationId")] + public string StationId { get; set; } = ""; + + [JsonProperty("playerId")] + public string PlayerId { get; set; } = ""; +} + +public class SabotageRepairedPayload +{ + [JsonProperty("sabotageId")] + public string SabotageId { get; set; } = ""; + + [JsonProperty("type")] + public SabotageType Type { get; set; } + + [JsonProperty("repairerIds")] + public List RepairerIds { get; set; } = new List(); +} + +public class SabotageMeltdownPayload +{ + [JsonProperty("sabotageId")] + public string SabotageId { get; set; } = ""; +} + +#endregion + +#region State + +public class LobbyState +{ + [JsonProperty("lobbyId")] + public string LobbyId { get; set; } = ""; + + [JsonProperty("joinCode")] + public string JoinCode { get; set; } = ""; + + [JsonProperty("ownerId")] + public string? OwnerId { get; set; } + + [JsonProperty("phase")] + public GamePhase Phase { get; set; } + + [JsonProperty("players")] + public List Players { get; set; } = new List(); + + [JsonProperty("playAreaCenter")] + public Position PlayAreaCenter { get; set; } + + [JsonProperty("playAreaRadius")] + public double PlayAreaRadius { get; set; } + + [JsonProperty("impostorCount")] + public int ImpostorCount { get; set; } + + [JsonProperty("hasPassword")] + public bool HasPassword { get; set; } + + [JsonProperty("mapData")] + public MapDataPayload? MapData { get; set; } + + /// True if map data has been loaded (or Overpass is disabled) + [JsonProperty("mapDataReady")] + public bool MapDataReady { get; set; } = true; +} + +// Map data classes for rendering - compact format from server +public class MapDataPayload +{ + [JsonProperty("center")] + public Position Center { get; set; } + + [JsonProperty("radiusMeters")] + public double RadiusMeters { get; set; } + + /// Buildings: [[lat,lon,lat,lon,...], ...] + [JsonProperty("buildings")] + public List Buildings { get; set; } = new List(); + + /// Building types: ["residential", "commercial", ...] + [JsonProperty("buildingTypes")] + public List BuildingTypes { get; set; } = new List(); + + /// Pathways: [[lat,lon,lat,lon,...], ...] + [JsonProperty("pathways")] + public List Pathways { get; set; } = new List(); + + /// Pathway types: [0=footway, 1=steps, ...] + [JsonProperty("pathwayTypes")] + public List PathwayTypes { get; set; } = new List(); + + /// Areas (parks): [[lat,lon,lat,lon,...], ...] + [JsonProperty("areas")] + public List Areas { get; set; } = new List(); + + /// Area types + [JsonProperty("areaTypes")] + public List AreaTypes { get; set; } = new List(); + + /// POIs: [lat, lon, type, lat, lon, type, ...] + [JsonProperty("pOIs")] + public List POIs { get; set; } = new List(); + + // Helper methods for extracting structured data + public List GetBuildings() + { + var result = new List(); + for (int i = 0; i < Buildings.Count; i++) + { + var coords = Buildings[i]; + var outline = new List(); + for (int j = 0; j < coords.Length - 1; j += 2) + { + outline.Add(new Position(coords[j], coords[j + 1])); + } + result.Add(new MapBuilding + { + Id = i, + Outline = outline, + BuildingType = i < BuildingTypes.Count ? BuildingTypes[i] : "yes" + }); + } + return result; + } + + public List GetPathways() + { + var result = new List(); + for (int i = 0; i < Pathways.Count; i++) + { + var coords = Pathways[i]; + var points = new List(); + for (int j = 0; j < coords.Length - 1; j += 2) + { + points.Add(new Position(coords[j], coords[j + 1])); + } + result.Add(new MapPathway + { + Id = i, + Points = points, + PathType = i < PathwayTypes.Count ? (PathType)PathwayTypes[i] : PathType.Other + }); + } + return result; + } + + public List GetAreas() + { + var result = new List(); + for (int i = 0; i < Areas.Count; i++) + { + var coords = Areas[i]; + var outline = new List(); + for (int j = 0; j < coords.Length - 1; j += 2) + { + outline.Add(new Position(coords[j], coords[j + 1])); + } + result.Add(new MapArea + { + Id = i, + Outline = outline, + AreaType = i < AreaTypes.Count ? (MapAreaType)AreaTypes[i] : MapAreaType.Other + }); + } + return result; + } + + public List GetPOIs() + { + var result = new List(); + for (int i = 0; i < POIs.Count - 2; i += 3) + { + result.Add(new MapPOI + { + Id = i / 3, + Location = new Position(POIs[i], POIs[i + 1]), + POIType = (MapPOIType)(int)POIs[i + 2] + }); + } + return result; + } +} + +public class MapBuilding +{ + public long Id { get; set; } + public List Outline { get; set; } = new List(); + public string? Name { get; set; } + public string? BuildingType { get; set; } +} + +public class MapPathway +{ + public long Id { get; set; } + public List Points { get; set; } = new List(); + public PathType PathType { get; set; } + public string? Name { get; set; } +} + +public class MapArea +{ + public long Id { get; set; } + public List Outline { get; set; } = new List(); + public MapAreaType AreaType { get; set; } + public string? Name { get; set; } +} + +public class MapPOI +{ + public long Id { get; set; } + public Position Location { get; set; } + public string? Name { get; set; } + public MapPOIType POIType { get; set; } +} + +public class PlayerInfo +{ + [JsonProperty("clientUuid")] + public string ClientUuid { get; set; } = ""; + + [JsonProperty("displayName")] + public string DisplayName { get; set; } = ""; + + [JsonProperty("isOwner")] + public bool IsOwner { get; set; } + + [JsonProperty("isReady")] + public bool IsReady { get; set; } + + [JsonProperty("state")] + public PlayerState State { get; set; } +} + +public class GameTask +{ + [JsonProperty("taskId")] + public string TaskId { get; set; } = ""; + + [JsonProperty("name")] + public string Name { get; set; } = ""; + + [JsonProperty("location")] + public Position Location { get; set; } + + [JsonProperty("type")] + public TaskType Type { get; set; } = TaskType.Instant; +} + +public class Body +{ + [JsonProperty("bodyId")] + public string BodyId { get; set; } = ""; + + [JsonProperty("victimId")] + public string VictimId { get; set; } = ""; + + [JsonProperty("location")] + public Position Location { get; set; } +} + +#endregion + +#region Serializace + +public static class JsonOptions +{ + public static readonly JsonSerializerSettings Default = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Converters = { new StringEnumConverter() } + }; +} + +public static class MessageSerializer +{ + private static readonly Dictionary MessageTypes = new Dictionary + { + ["ClientHello"] = typeof(ClientHello), + ["ServerHello"] = typeof(ServerHello), + ["KeyExchange"] = typeof(KeyExchange), + ["KeyExchangeAck"] = typeof(KeyExchangeAck), + ["CreateLobby"] = typeof(CreateLobby), + ["CreateLobbyResponse"] = typeof(CreateLobbyResponse), + ["JoinLobby"] = typeof(JoinLobby), + ["JoinLobbyResponse"] = typeof(JoinLobbyResponse), + ["LeaveLobby"] = typeof(LeaveLobby), + ["ReturnToLobby"] = typeof(ReturnToLobby), + ["StartGame"] = typeof(StartGame), + ["MapDataReceived"] = typeof(MapDataReceived), + ["UpdatePosition"] = typeof(UpdatePosition), + ["PositionBroadcast"] = typeof(PositionBroadcast), + ["KillAttempt"] = typeof(KillAttempt), + ["ReportBody"] = typeof(ReportBody), + ["CallEmergencyMeeting"] = typeof(CallEmergencyMeeting), + ["CastVote"] = typeof(CastVote), + ["TaskStart"] = typeof(TaskStart), + ["TaskProgress"] = typeof(TaskProgress), + ["TaskComplete"] = typeof(TaskComplete), + ["Ping"] = typeof(Ping), + ["Pong"] = typeof(Pong), + ["Reconnect"] = typeof(Reconnect), + ["Ack"] = typeof(Ack), + ["Error"] = typeof(ErrorMessage), + ["GameEvent"] = typeof(GameEvent) + }; + + public static byte[] Serialize(Message msg) + { + var json = JsonConvert.SerializeObject(msg, JsonOptions.Default); + return Encoding.UTF8.GetBytes(json); + } + + public static Message? Deserialize(byte[] data) + { + var json = Encoding.UTF8.GetString(data); + var jObj = JObject.Parse(json); + + var typeName = jObj["type"]?.Value(); + if (typeName == null || !MessageTypes.TryGetValue(typeName, out var type)) + return null; + + return (Message?)JsonConvert.DeserializeObject(json, type, JsonOptions.Default); + } +} + + #endregion +} diff --git a/Assets/ClientSDK/Protocol.cs.meta b/Assets/ClientSDK/Protocol.cs.meta new file mode 100644 index 0000000..719b429 --- /dev/null +++ b/Assets/ClientSDK/Protocol.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 14463228dfea2264ebfc36c3a7dc4b99 \ No newline at end of file diff --git a/Assets/ClientSDK/SimulatorClient.cs b/Assets/ClientSDK/SimulatorClient.cs new file mode 100644 index 0000000..733418a --- /dev/null +++ b/Assets/ClientSDK/SimulatorClient.cs @@ -0,0 +1,1992 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace GeoSus.Client +{ + /// +/// Comprehensive headless simulator client for testing all game aspects. +/// Supports both autonomous simulation and step-by-step controlled testing. +/// +public class SimulatorClient : IDisposable +{ + private readonly GameClient _client; + private readonly Random _random = new Random(); + private CancellationTokenSource? _cts; + private Task? _simulationTask; + private PlayerState _myState = PlayerState.Alive; + + #region Public Properties + + public string ClientUuid => _client.ClientUuid; + public string DisplayName => _client.DisplayName; + public bool IsConnected => _client.IsConnected; + public LobbyState? LobbyState => _client.CurrentLobbyState; + public string? LobbyId => _client.LobbyId; + public string? JoinCode => _client.JoinCode; + public PlayerRole? Role => _client.MyRole; + public PlayerState State => _myState; + public Position Position => _client.MyPosition; + public bool IsAlive => _myState == PlayerState.Alive; + public bool IsDead => _myState == PlayerState.Dead; + public bool IsImpostor => _client.MyRole == PlayerRole.Impostor; + public bool IsCrew => _client.MyRole == PlayerRole.Crew; + + // Tasks + public List MyTasks => _client.MyTasks; + public HashSet CompletedTaskIds { get; } = new HashSet(); + public string? CurrentTaskId { get; private set; } + + // Game state tracking + public int TotalKills { get; private set; } + public int TasksCompleted { get; private set; } + public int MeetingsAttended { get; private set; } + public int VotesCast { get; private set; } + public int BodiesReported { get; private set; } + public bool WasEjected { get; private set; } + public bool WasKilled { get; private set; } + public string? LastError { get; private set; } + public string? GameResult { get; private set; } + public string? WinningFaction { get; private set; } + public bool GameEnded => GameResult != null; + + // Nearby entities + public Dictionary NearbyPlayers => _client.PlayerPositions; + public List NearbyBodies => _client.Bodies; + + // Meeting state + public bool InMeeting { get; private set; } + public bool HasVotedThisMeeting { get; private set; } + public string? CurrentMeetingId { get; private set; } + public Position? MeetingLocation { get; private set; } + public DateTime? MeetingVotingEndTime { get; private set; } + public DateTime? MeetingDiscussionEndTime { get; private set; } + + /// + /// Returns true if the discussion phase has ended and voting can begin. + /// + public bool CanVote => InMeeting && + (!MeetingDiscussionEndTime.HasValue || DateTime.UtcNow >= MeetingDiscussionEndTime.Value); + + // Current game phase from lobby state + public string GamePhase => _client.CurrentLobbyState?.Phase.ToString() ?? "Unknown"; + + // Sabotage state + public bool SabotageActive { get; private set; } + public string? CurrentSabotageId { get; private set; } + public SabotageType? CurrentSabotageType { get; private set; } + public DateTime? SabotageDeadline { get; private set; } + public List RepairStations { get; private set; } = new List(); + public int SabotagesStarted { get; private set; } + public int SabotagesRepaired { get; private set; } + public bool IsRepairing { get; private set; } + public string? RepairingStationId { get; private set; } + + /// + /// Returns true if comms are blocked (can't report/meeting) + /// + public bool IsCommsBlocked => SabotageActive && CurrentSabotageType == SabotageType.CommsBlackout; + + /// + /// Returns true if there's a critical meltdown countdown + /// + public bool IsMeltdownActive => SabotageActive && CurrentSabotageType == SabotageType.CriticalMeltdown; + + #endregion + + #region Events + + public event Action? OnLog; + public event Action? OnError; + public event Action? OnGameEvent; + public event Action? OnKilled; + public event Action? OnEjected; + public event Action? OnGameEnded; + public event Action? OnMeetingStarted; + public event Action? OnMeetingEnded; + public event Action? OnSabotageStarted; + public event Action? OnSabotageRepaired; + public event Action? OnMeltdown; + + #endregion + + #region Constructor + + public SimulatorClient(string clientUuid, string displayName) + { + _client = new GameClient(clientUuid, displayName); + + _client.OnConnected += () => Log("Připojen k serveru"); + _client.OnDisconnected += (reason) => Log($"Odpojen: {reason}"); + _client.OnError += (error) => + { + LastError = error; + Log($"Chyba: {error}"); + OnError?.Invoke(error); + }; + + _client.OnMessage += HandleMessage; + _client.OnGameEvent += HandleGameEvent; + } + + #endregion + + #region Message Handlers + + private void HandleMessage(Message msg) + { + switch (msg) + { + case CreateLobbyResponse r: + if (r.Success) + Log($"Lobby vytvořeno: {r.JoinCode}"); + else + LogError($"Lobby creation failed"); + break; + + case JoinLobbyResponse r: + if (r.Success) + Log($"Připojen do lobby: {r.LobbyId}"); + else + LogError("Join lobby failed"); + break; + + case Ack a when !a.Success: + LastError = a.Error; + Log($"Akce zamítnuta: {a.Error}"); + break; + } + } + + private void HandleGameEvent(GameEvent evt) + { + OnGameEvent?.Invoke(evt.EventType, evt.Payload); + + switch (evt.EventType) + { + case "GameStarting": + Log("Game loading - fetching map data..."); + break; + + case "MapDataReady": + var mapPayload = evt.GetPayload(); + var buildingCount = mapPayload?.MapData?.Buildings?.Count ?? 0; + var pathwayCount = mapPayload?.MapData?.Pathways?.Count ?? 0; + Log($"Map data received: {buildingCount} buildings, {pathwayCount} pathways - sending confirmation"); + break; + + case "PlayerMapDataReceived": + var progressPayload = evt.GetPayload(); + if (progressPayload != null) + { + Log($"Player {progressPayload.DisplayName} ready ({progressPayload.PlayersReady}/{progressPayload.TotalPlayers})"); + } + break; + + case "GameStarted": + Log("Hra začala!"); + break; + + case "RoleAssigned": + var rolePayload = evt.GetPayload(); + if (rolePayload?.ClientUuid == ClientUuid) + { + Log($"Moje role: {rolePayload.Role}"); + } + break; + + case "PlayerKilled": + var killPayload = evt.GetPayload(); + Log($"Hráč {killPayload?.VictimId} byl zabit"); + if (killPayload?.VictimId == ClientUuid) + { + WasKilled = true; + _myState = PlayerState.Dead; + Log("BYL JSEM ZABIT!"); + OnKilled?.Invoke(); + } + break; + + case "MeetingStarted": + var meetingPayload = evt.GetPayload(); + InMeeting = true; + HasVotedThisMeeting = false; + CurrentMeetingId = meetingPayload?.MeetingId; + MeetingLocation = meetingPayload?.MeetingLocation; + MeetingVotingEndTime = meetingPayload?.VotingEndTime; + MeetingDiscussionEndTime = meetingPayload?.DiscussionEndTime; + Log($"MEETING ZAČAL! Typ: {meetingPayload?.Type}, Lokace: {MeetingLocation?.Lat:F4},{MeetingLocation?.Lon:F4}"); + if (MeetingDiscussionEndTime.HasValue) + { + var discussionMs = (MeetingDiscussionEndTime.Value - DateTime.UtcNow).TotalMilliseconds; + Log($" Diskuze do: {MeetingDiscussionEndTime.Value:HH:mm:ss} ({discussionMs:F0}ms)"); + } + OnMeetingStarted?.Invoke(); + break; + + case "VotingStarted": + Log("Hlasování začalo!"); + break; + + case "PlayerVoted": + var voteInfoPayload = evt.GetPayload(); + Log($"Hráč {voteInfoPayload?.VoterId} hlasoval"); + break; + + case "VotingClosed": + var votePayload = evt.GetPayload(); + InMeeting = false; + CurrentMeetingId = null; + MeetingLocation = null; + MeetingVotingEndTime = null; + MeetingDiscussionEndTime = null; + if (votePayload?.EjectedPlayerId != null) + { + Log($"Hráč {votePayload.EjectedPlayerId} byl VYHOZEN! (remíza: {votePayload.WasTie})"); + if (votePayload.EjectedPlayerId == ClientUuid) + { + WasEjected = true; + _myState = PlayerState.Dead; + Log("BYL JSEM VYHOZEN!"); + OnEjected?.Invoke(); + } + } + else + { + Log("Nikdo nebyl vyhozen (skip nebo remíza)"); + } + OnMeetingEnded?.Invoke(); + break; + + case "TaskCompleted": + var taskPayload = evt.GetPayload(); + if (taskPayload?.ClientUuid == ClientUuid) + { + TasksCompleted++; + CompletedTaskIds.Add(taskPayload.TaskId); + CurrentTaskId = null; + Log($"TASK DOKONČEN: {taskPayload.TaskId} (celkem: {TasksCompleted})"); + } + break; + + case "GameEnded": + var endPayload = evt.GetPayload(); + GameResult = endPayload?.Reason; + WinningFaction = endPayload?.WinningFaction; + Log($"=== HRA SKONČILA! Vítěz: {endPayload?.WinningFaction} - {endPayload?.Reason} ==="); + OnGameEnded?.Invoke(endPayload?.WinningFaction ?? "Unknown"); + break; + + // Sabotage events + case "SabotageStarted": + var sabStartPayload = evt.GetPayload(); + if (sabStartPayload != null) + { + SabotageActive = true; + CurrentSabotageId = sabStartPayload.SabotageId; + CurrentSabotageType = sabStartPayload.Type; + SabotageDeadline = sabStartPayload.Deadline; + RepairStations = sabStartPayload.RepairStations; + + Log($"⚠ SABOTÁŽ SPUŠTĚNA: {sabStartPayload.Type}!"); + if (sabStartPayload.Deadline.HasValue) + { + var remaining = (sabStartPayload.Deadline.Value - DateTime.UtcNow).TotalSeconds; + Log($" ⏱ DEADLINE: {remaining:F0}s - musíte opravit nebo prohrajete!"); + } + foreach (var station in sabStartPayload.RepairStations) + { + Log($" 📍 Stanice {station.Name}: {station.Location.Lat:F4},{station.Location.Lon:F4}"); + } + OnSabotageStarted?.Invoke(sabStartPayload.Type); + } + break; + + case "RepairStarted": + var repStartPayload = evt.GetPayload(); + if (repStartPayload?.PlayerId == ClientUuid) + { + IsRepairing = true; + RepairingStationId = repStartPayload.StationId; + Log($"🔧 Zahájil jsem opravu stanice {repStartPayload.StationId}"); + } + else + { + Log($"🔧 Hráč {repStartPayload?.PlayerId} opravuje {repStartPayload?.StationId}"); + } + break; + + case "RepairStopped": + var repStopPayload = evt.GetPayload(); + if (repStopPayload?.PlayerId == ClientUuid) + { + IsRepairing = false; + RepairingStationId = null; + Log($"❌ Oprava přerušena: {repStopPayload.StationId}"); + } + break; + + case "SabotageRepaired": + case "SabotageExpired": + var sabRepPayload = evt.GetPayload(); + if (sabRepPayload != null) + { + SabotageActive = false; + CurrentSabotageId = null; + CurrentSabotageType = null; + SabotageDeadline = null; + RepairStations.Clear(); + IsRepairing = false; + RepairingStationId = null; + SabotagesRepaired++; + + var repairers = sabRepPayload.RepairerIds.Count > 0 + ? string.Join(", ", sabRepPayload.RepairerIds) + : "auto-expire"; + Log($"✅ SABOTÁŽ OPRAVENA: {sabRepPayload.Type} (opravili: {repairers})"); + OnSabotageRepaired?.Invoke(sabRepPayload.Type); + } + break; + + case "SabotageMeltdown": + var meltdownPayload = evt.GetPayload(); + Log($"💥 MELTDOWN! Sabotáž nebyla opravena včas - Impostoři vyhráli!"); + OnMeltdown?.Invoke(); + break; + } + } + + #endregion + + #region Connection & Lobby + + public async Task ConnectAsync(string host, int port) + { + return await _client.ConnectAsync(host, port); + } + + public void Disconnect() + { + StopSimulation(); + _client.Disconnect(); + } + + public void Update() + { + _client.Update(); + } + + public void CreateLobby(Position center, int impostorCount = 1, int taskCount = 5, string? password = null) + { + _client.CreateLobby(center, impostorCount, taskCount, password); + } + + /// + /// Async wrapper for CreateLobby - waits for lobby to be created + /// + public async Task CreateLobbyAsync(string? password, Position center, double radius = 500, int impostorCount = 1, int taskCount = 5) + { + _client.CreateLobby(center, impostorCount, taskCount, password, radius); + + // Wait for lobby creation response + for (int i = 0; i < 50; i++) // 5 seconds timeout + { + Update(); + if (!string.IsNullOrEmpty(JoinCode)) + return true; + if (LastError != null && LastError.Contains("lobby")) + return false; + await Task.Delay(100); + } + return false; + } + + public void JoinLobby(string joinCode, string? password = null) + { + _client.JoinLobby(joinCode, password); + } + + /// + /// Async wrapper for JoinLobby - waits for join confirmation + /// + public async Task JoinLobbyAsync(string joinCode, string? password = null) + { + _client.JoinLobby(joinCode, password); + + // Wait for join response + for (int i = 0; i < 50; i++) + { + Update(); + if (!string.IsNullOrEmpty(LobbyId)) + return true; + if (LastError != null && LastError.Contains("join")) + return false; + await Task.Delay(100); + } + return false; + } + + public void LeaveLobby() + { + _client.LeaveLobby(); + } + + public void StartGame() + { + _client.StartGame(); + } + + /// + /// Async wrapper for StartGame - waits for game to start + /// + public async Task StartGameAsync() + { + _client.StartGame(); + + // Wait for game start + for (int i = 0; i < 50; i++) + { + Update(); + if (Role.HasValue) + return true; + await Task.Delay(100); + } + return false; + } + + #endregion + + #region Movement + + public void MoveTo(Position position) + { + _client.UpdatePosition(position); + } + + public void MoveTowards(Position target, double maxDistanceMeters) + { + var current = Position; + var distance = current.DistanceTo(target); + + if (distance <= maxDistanceMeters) + { + MoveTo(target); + } + else + { + var ratio = maxDistanceMeters / distance; + var newPos = new Position( + current.Lat + (target.Lat - current.Lat) * ratio, + current.Lon + (target.Lon - current.Lon) * ratio + ); + MoveTo(newPos); + } + } + + public Position GetRandomPositionNear(Position center, double radiusMeters) + { + var angle = _random.NextDouble() * 2 * Math.PI; + var distance = _random.NextDouble() * radiusMeters; + var lat = center.Lat + (distance / 111000) * Math.Cos(angle); + var lon = center.Lon + (distance / (111000 * Math.Cos(center.Lat * Math.PI / 180))) * Math.Sin(angle); + return new Position(lat, lon); + } + + #endregion + + #region Kill Actions (Impostor) + + public bool TryKill(string targetUuid) + { + if (!IsImpostor || !IsAlive) + { + Log("Nemohu zabíjet - nejsem živý impostor"); + return false; + } + + Log($">>> POKUS O ZABITÍ: {targetUuid}"); + _client.Kill(targetUuid); + TotalKills++; + return true; + } + + public string? FindKillTarget(double maxDistance = 5.0) + { + return _client.FindNearbyPlayer(maxDistance, aliveOnly: true); + } + + public bool TryKillNearby(double maxDistance = 5.0) + { + var target = FindKillTarget(maxDistance); + if (target != null) + { + return TryKill(target); + } + return false; + } + + #endregion + + #region Report & Meeting Actions + + public bool TryReportBody(string bodyId) + { + if (!IsAlive) + { + Log("Nemohu reportovat - jsem mrtvý"); + return false; + } + + Log($">>> REPORTUJI TĚLO: {bodyId}"); + _client.ReportBody(bodyId); + BodiesReported++; + return true; + } + + public Body? FindNearbyBody(double maxDistance = 5.0) + { + return _client.FindNearbyBody(maxDistance); + } + + public bool TryReportNearbyBody(double maxDistance = 5.0) + { + var body = FindNearbyBody(maxDistance); + if (body != null) + { + return TryReportBody(body.BodyId); + } + return false; + } + + public bool TryCallEmergencyMeeting() + { + if (!IsAlive) + { + Log("Nemohu svolat meeting - jsem mrtvý"); + return false; + } + + Log(">>> SVOLÁVÁM EMERGENCY MEETING!"); + _client.CallEmergencyMeeting(); + return true; + } + + #endregion + + #region Voting Actions + + public bool TryVote(string? targetUuid) + { + if (!IsAlive) + { + Log("Nemohu hlasovat - jsem mrtvý"); + return false; + } + + if (!InMeeting) + { + Log("Nemohu hlasovat - není meeting"); + return false; + } + + var voteTarget = targetUuid ?? "SKIP"; + Log($">>> HLASUJI PRO: {voteTarget}"); + _client.Vote(targetUuid); + VotesCast++; + HasVotedThisMeeting = true; + MeetingsAttended++; + return true; + } + + public bool TryVoteSkip() + { + return TryVote(null); + } + + public bool TryVoteRandom() + { + if (!InMeeting || !IsAlive) return false; + + // Pick a random alive player (or skip) + var alivePlayers = NearbyPlayers.Values + .Where(p => p.State == PlayerState.Alive && p.ClientUuid != ClientUuid) + .ToList(); + + if (alivePlayers.Count == 0 || _random.NextDouble() < 0.3) + { + return TryVoteSkip(); + } + + var target = alivePlayers[_random.Next(alivePlayers.Count)]; + return TryVote(target.ClientUuid); + } + + /// + /// Vote for the player with the most suspicion (for crew) or a random crew (for impostor) + /// + public bool TryVoteSmart() + { + if (!InMeeting || !IsAlive) return false; + + var alivePlayers = NearbyPlayers.Values + .Where(p => p.State == PlayerState.Alive && p.ClientUuid != ClientUuid) + .ToList(); + + if (alivePlayers.Count == 0) + { + return TryVoteSkip(); + } + + // Impostors vote randomly among non-impostors or skip + if (IsImpostor) + { + if (_random.NextDouble() < 0.5) + { + return TryVoteSkip(); + } + var target = alivePlayers[_random.Next(alivePlayers.Count)]; + return TryVote(target.ClientUuid); + } + + // Crew votes randomly for now (could be smarter with suspicion tracking) + if (_random.NextDouble() < 0.2) + { + return TryVoteSkip(); + } + var crewTarget = alivePlayers[_random.Next(alivePlayers.Count)]; + return TryVote(crewTarget.ClientUuid); + } + + #endregion + + #region Task Actions + + public bool TryCompleteTask(string taskId) + { + if (IsImpostor) + { + Log($"Nemohu dělat tasky - jsem impostor"); + return false; + } + + if (CompletedTaskIds.Contains(taskId)) + { + Log($"Task {taskId} již dokončen"); + return false; + } + + Log($">>> DOKONČUJI TASK: {taskId}"); + _client.CompleteTask(taskId); + return true; + } + + public GameTask? FindNearbyTask(double maxDistance = 5.0) + { + foreach (var task in MyTasks) + { + if (CompletedTaskIds.Contains(task.TaskId)) continue; + + if (Position.DistanceTo(task.Location) <= maxDistance) + { + return task; + } + } + return null; + } + + public GameTask? GetNextIncompleteTask() + { + return MyTasks.FirstOrDefault(t => !CompletedTaskIds.Contains(t.TaskId)); + } + + public int GetRemainingTaskCount() + { + return MyTasks.Count - CompletedTaskIds.Count; + } + + #endregion + + #region Sabotage Actions (Impostor) + + /// + /// Start a sabotage (impostor only) + /// + public bool TrySabotage(SabotageType sabotageType) + { + if (!IsImpostor) + { + Log("Nemohu sabotovat - nejsem impostor"); + return false; + } + + if (!IsAlive) + { + Log("Nemohu sabotovat - jsem mrtvý"); + return false; + } + + if (SabotageActive) + { + Log($"Nemohu sabotovat - již probíhá sabotáž: {CurrentSabotageType}"); + return false; + } + + if (InMeeting) + { + Log("Nemohu sabotovat - probíhá meeting"); + return false; + } + + Log($">>> SPOUŠTÍM SABOTÁŽ: {sabotageType}"); + _client.Send(new StartSabotage { SabotageType = sabotageType }); + SabotagesStarted++; + return true; + } + + /// + /// Start repairing at a repair station (crew or impostor can repair) + /// + public bool TryStartRepair(string stationId) + { + if (!IsAlive) + { + Log("Nemohu opravovat - jsem mrtvý"); + return false; + } + + if (!SabotageActive) + { + Log("Nemohu opravovat - není aktivní sabotáž"); + return false; + } + + if (IsRepairing) + { + Log($"Již opravuji stanici: {RepairingStationId}"); + return false; + } + + var station = RepairStations.FirstOrDefault(s => s.StationId == stationId); + if (station == null) + { + Log($"Opravná stanice {stationId} neexistuje"); + return false; + } + + var distance = Position.DistanceTo(station.Location); + if (distance > 5.0) + { + Log($"Opravná stanice {stationId} je příliš daleko: {distance:F1}m"); + return false; + } + + Log($">>> ZAČÍNÁM OPRAVU stanice: {stationId}"); + _client.Send(new ActivateRepairStation { StationId = stationId }); + return true; + } + + /// + /// Stop repairing current station + /// + public bool TryStopRepair() + { + if (!IsRepairing || RepairingStationId == null) + { + Log("Nejsem u opravné stanice"); + return false; + } + + Log($">>> UKONČUJI OPRAVU stanice: {RepairingStationId}"); + _client.Send(new DeactivateRepairStation { StationId = RepairingStationId }); + return true; + } + + /// + /// Find nearest repair station for current sabotage + /// + public RepairStationInfo? FindNearestRepairStation(double maxDistance = double.MaxValue) + { + if (!SabotageActive) return null; + + RepairStationInfo? nearest = null; + double nearestDist = maxDistance; + + foreach (var station in RepairStations) + { + if (station.IsRepaired) continue; + + var dist = Position.DistanceTo(station.Location); + if (dist < nearestDist) + { + nearestDist = dist; + nearest = station; + } + } + + return nearest; + } + + /// + /// Move to nearest repair station + /// + public bool MoveTowardsNearestRepairStation(double speed = 1.0) + { + var station = FindNearestRepairStation(); + if (station == null) return false; + + MoveTowards(station.Location, speed); + return true; + } + + /// + /// Check if at repair station and can start repair + /// + public bool IsAtRepairStation(string stationId, double maxDistance = 5.0) + { + var station = RepairStations.FirstOrDefault(s => s.StationId == stationId); + if (station == null) return false; + + return Position.DistanceTo(station.Location) <= maxDistance; + } + + /// + /// Automatic repair: find nearest station, move to it, and start repair + /// + public bool TryAutoRepair() + { + if (!SabotageActive) return false; + if (IsRepairing) return false; + + var station = FindNearestRepairStation(5.0); + if (station != null && !station.IsRepaired) + { + return TryStartRepair(station.StationId); + } + + return false; + } + + #endregion + + #region Autonomous Simulation + + public void StartSimulation() + { + if (_simulationTask != null) return; + + _cts = new CancellationTokenSource(); + _simulationTask = Task.Run(() => SimulationLoopAsync(_cts.Token)); + Log("Simulace spuštěna"); + } + + public void StopSimulation() + { + if (_cts == null) return; + + _cts.Cancel(); + try { _simulationTask?.Wait(1000); } catch { } + _simulationTask = null; + _cts = null; + Log("Simulace zastavena"); + } + + private async Task SimulationLoopAsync(CancellationToken ct) + { + var center = LobbyState?.PlayAreaCenter ?? new Position(50.0, 14.0); + var radius = LobbyState?.PlayAreaRadius ?? 500; + + MoveTo(center); + + while (!ct.IsCancellationRequested && !GameEnded) + { + try + { + Update(); + + // In meeting - handle voting + if (InMeeting) + { + // First move to meeting location + if (MeetingLocation.HasValue && IsAlive) + { + var meetLoc = MeetingLocation.Value; + var distToMeeting = Position.DistanceTo(meetLoc); + if (distToMeeting > 5) + { + MoveTowards(meetLoc, 20); + await Task.Delay(200, ct); + continue; + } + } + + if (IsAlive && !HasVotedThisMeeting) + { + // Wait a bit before voting (simulate discussion) + await Task.Delay(500 + _random.Next(1500), ct); + Update(); + + if (InMeeting && !HasVotedThisMeeting) + { + TryVoteSmart(); + } + } + + // Wait for meeting to end + await Task.Delay(300, ct); + continue; + } + + // Impostor logic + if (IsImpostor && IsAlive) + { + await ImpostorActionAsync(center, radius, ct); + } + // Alive Crew logic + else if (IsCrew && IsAlive) + { + await CrewActionAsync(center, radius, ct); + } + // Dead player (ghost) - can still do tasks + else if (IsCrew && IsDead) + { + await GhostTaskActionAsync(center, radius, ct); + } + // Dead impostor - just watch + else if (IsImpostor && IsDead) + { + await Task.Delay(1000, ct); + } + + await Task.Delay(300, ct); + } + catch (OperationCanceledException) + { + break; + } + catch (Exception ex) + { + Log($"Simulation error: {ex.Message}"); + await Task.Delay(1000, ct); + } + } + + Log("Simulace dokončena"); + } + + private async Task ImpostorActionAsync(Position center, double radius, CancellationToken ct) + { + // Try to kill nearby player + var target = FindKillTarget(8.0); + if (target != null) + { + // Higher chance to kill if alone with victim + var nearbyCount = NearbyPlayers.Values.Count(p => + p.State == PlayerState.Alive && + p.ClientUuid != ClientUuid && + Position.DistanceTo(p.Position) < 20); + + var killChance = nearbyCount <= 1 ? 0.9 : 0.3; + + if (_random.NextDouble() < killChance) + { + TryKill(target); + await Task.Delay(300, ct); + + // Move away from body + var escapePos = GetRandomPositionNear(Position, 30); + MoveTowards(escapePos, 15); + await Task.Delay(500, ct); + return; + } + } + + // Wander around looking for isolated targets + var wanderPos = GetRandomPositionNear(center, radius * 0.6); + MoveTowards(wanderPos, 5); + } + + private async Task CrewActionAsync(Position center, double radius, CancellationToken ct) + { + // Priority 1: Report nearby bodies + var body = FindNearbyBody(8.0); + if (body != null) + { + Log($"NAŠEL JSEM TĚLO: {body.BodyId}"); + // Move closer if needed + if (Position.DistanceTo(body.Location) > 3) + { + MoveTowards(body.Location, 3); + await Task.Delay(200, ct); + } + TryReportBody(body.BodyId); + await Task.Delay(500, ct); + return; + } + + // Priority 2: Do tasks (instant completion) + var nearbyTask = FindNearbyTask(5.0); + if (nearbyTask != null) + { + TryCompleteTask(nearbyTask.TaskId); + await Task.Delay(500, ct); + return; + } + + // Priority 3: Move to next task + var nextTask = GetNextIncompleteTask(); + if (nextTask != null) + { + MoveTowards(nextTask.Location, 5); + } + else + { + // All tasks done, wander + var wanderPos = GetRandomPositionNear(center, radius * 0.5); + MoveTowards(wanderPos, 3); + } + } + + private async Task GhostTaskActionAsync(Position center, double radius, CancellationToken ct) + { + // Ghosts can complete tasks faster (no danger) + var nearbyTask = FindNearbyTask(10.0); + if (nearbyTask != null) + { + TryCompleteTask(nearbyTask.TaskId); + await Task.Delay(100, ct); + return; + } + + // Move to next task + var nextTask = GetNextIncompleteTask(); + if (nextTask != null) + { + // Ghosts move much faster + MoveTowards(nextTask.Location, 20); + } + } + + #endregion + + #region Logging + + private void Log(string message) + { + OnLog?.Invoke(message); + } + + private void LogError(string message) + { + LastError = message; + OnError?.Invoke(message); + Log($"ERROR: {message}"); + } + + #endregion + + #region Stats + + public string GetStats() + { + return $"[{DisplayName}] Role={Role}, State={State}, Kills={TotalKills}, Tasks={TasksCompleted}/{MyTasks.Count}, " + + $"Reports={BodiesReported}, Votes={VotesCast}, Meetings={MeetingsAttended}, " + + $"Killed={WasKilled}, Ejected={WasEjected}"; + } + + public void PrintDetailedStats() + { + Log("========== DETAILED STATS =========="); + Log($" Display Name: {DisplayName}"); + Log($" Client UUID: {ClientUuid}"); + Log($" Role: {Role}"); + Log($" Final State: {State}"); + Log($" --- Actions ---"); + Log($" Kills Attempted: {TotalKills}"); + Log($" Tasks Completed: {TasksCompleted}/{MyTasks.Count}"); + Log($" Bodies Reported: {BodiesReported}"); + Log($" Votes Cast: {VotesCast}"); + Log($" Meetings Attended: {MeetingsAttended}"); + Log($" --- Fate ---"); + Log($" Was Killed: {WasKilled}"); + Log($" Was Ejected: {WasEjected}"); + Log($" --- Game Result ---"); + Log($" Winning Faction: {WinningFaction}"); + Log($" Result: {GameResult}"); + Log("====================================="); + } + + #endregion + + public void Dispose() + { + StopSimulation(); + _client.Dispose(); + } + + #region Map Data Access + + /// + /// Get the map data payload from the current lobby state (if available) + /// + public MapDataPayload? MapData => _client.CurrentLobbyState?.MapData; + + /// + /// Check if map data is available for the current lobby + /// + public bool HasMapData => MapData != null; + + /// + /// Check if map data loading is complete (true if loaded or Overpass disabled) + /// + public bool IsMapDataReady => _client.CurrentLobbyState?.MapDataReady ?? false; + + /// + /// Get the play area center from lobby state + /// + public Position? PlayAreaCenter => _client.CurrentLobbyState?.PlayAreaCenter; + + /// + /// Get the play area radius from lobby state + /// + public double PlayAreaRadius => _client.CurrentLobbyState?.PlayAreaRadius ?? 500; + + #endregion +} + +/// +/// Comprehensive test suite for Overpass API and reachability testing +/// +public class OverpassApiTests +{ + private readonly string _serverHost; + private readonly int _serverPort; + private readonly Action? _logger; + + public OverpassApiTests(string serverHost = "localhost", int serverPort = 7777, Action? logger = null) + { + _serverHost = serverHost; + _serverPort = serverPort; + _logger = logger; + } + + private void Log(string message) + { + _logger?.Invoke(message); + Console.WriteLine(message); + } + + /// + /// Run all Overpass API tests + /// + public async Task RunAllTestsAsync(Position testCenter, double testRadius = 500) + { + var results = new OverpassTestResults(); + + Log("═══════════════════════════════════════════════════════════════"); + Log(" OVERPASS API & REACHABILITY TEST SUITE"); + Log("═══════════════════════════════════════════════════════════════"); + Log($"Test Center: {testCenter.Lat:F6}, {testCenter.Lon:F6}"); + Log($"Test Radius: {testRadius}m"); + Log(""); + + // Test 1: Create lobby and verify map data is fetched + Log("TEST 1: Map Data Fetch on Lobby Creation"); + Log("─────────────────────────────────────────"); + results.MapDataFetchTest = await TestMapDataFetchAsync(testCenter, testRadius); + LogTestResult("Map Data Fetch", results.MapDataFetchTest); + await Task.Delay(1000); // Delay between tests + + // Test 2: Verify map data structure + Log(""); + Log("TEST 2: Map Data Structure Validation"); + Log("─────────────────────────────────────────"); + results.MapDataStructureTest = await TestMapDataStructureAsync(testCenter, testRadius); + LogTestResult("Map Data Structure", results.MapDataStructureTest); + await Task.Delay(1000); // Delay between tests + + // Test 3: Verify task positions are on reachable paths + Log(""); + Log("TEST 3: Task Position Reachability"); + Log("─────────────────────────────────────────"); + results.TaskReachabilityTest = await TestTaskReachabilityAsync(testCenter, testRadius); + LogTestResult("Task Reachability", results.TaskReachabilityTest); + await Task.Delay(1000); // Delay between tests + + // Test 4: Verify repair station positions are reachable + Log(""); + Log("TEST 4: Repair Station Reachability (Sabotage)"); + Log("─────────────────────────────────────────"); + results.RepairStationReachabilityTest = await TestRepairStationReachabilityAsync(testCenter, testRadius); + LogTestResult("Repair Station Reachability", results.RepairStationReachabilityTest); + await Task.Delay(1000); // Delay between tests + + // Test 5: Verify positions are within play area + Log(""); + Log("TEST 5: Play Area Boundary Validation"); + Log("─────────────────────────────────────────"); + results.PlayAreaBoundaryTest = await TestPlayAreaBoundaryAsync(testCenter, testRadius); + LogTestResult("Play Area Boundary", results.PlayAreaBoundaryTest); + await Task.Delay(1000); // Delay between tests + + // Test 6: Test multiple lobby creations for consistency + Log(""); + Log("TEST 6: Map Data Consistency Across Lobbies"); + Log("─────────────────────────────────────────"); + results.ConsistencyTest = await TestMapDataConsistencyAsync(testCenter, testRadius); + LogTestResult("Map Data Consistency", results.ConsistencyTest); + + // Summary + Log(""); + Log("═══════════════════════════════════════════════════════════════"); + Log(" TEST SUMMARY"); + Log("═══════════════════════════════════════════════════════════════"); + results.PrintSummary(Log); + + return results; + } + + private void LogTestResult(string testName, TestResult result) + { + var status = result.Passed ? "✓ PASS" : "✗ FAIL"; + Log($" [{status}] {testName}"); + if (!string.IsNullOrEmpty(result.Details)) + { + foreach (var line in result.Details.Split('\n')) + { + Log($" {line}"); + } + } + if (!result.Passed && !string.IsNullOrEmpty(result.Error)) + { + Log($" ERROR: {result.Error}"); + } + } + + /// + /// Wait for map data to be loaded with polling and timeout + /// Note: Map data is now fetched when game starts, not on lobby creation + /// + private async Task WaitForMapDataAsync(SimulatorClient client, SimulatorClient? otherClient, int timeoutMs = 10000, int pollIntervalMs = 500) + { + var sw = System.Diagnostics.Stopwatch.StartNew(); + + while (sw.ElapsedMilliseconds < timeoutMs) + { + // Update client to receive any pending messages + client.Update(); + otherClient?.Update(); + + // Check if client has map data loaded + if (client.HasMapData) + { + Log($" Map data loaded after {sw.ElapsedMilliseconds}ms"); + return true; + } + + // Also check if MapDataReady indicates no data expected (Overpass disabled) + if (client.IsMapDataReady && !client.HasMapData) + { + Log($" Map data not available (Overpass may be disabled)"); + return false; + } + + await Task.Delay(pollIntervalMs); + } + + Log($" Timeout waiting for map data ({timeoutMs}ms)"); + return false; + } + + /// + /// Wait for game to start after map data is received (Loading phase complete) + /// + private async Task WaitForGameStartAfterMapDataAsync(SimulatorClient owner, SimulatorClient player, int timeoutMs = 20000, int pollIntervalMs = 500) + { + var sw = System.Diagnostics.Stopwatch.StartNew(); + + while (sw.ElapsedMilliseconds < timeoutMs) + { + owner.Update(); + player.Update(); + + // Game is fully started when phase is Playing and roles are assigned + if (owner.GamePhase == "Playing" && owner.Role.HasValue) + { + Log($" Game started after {sw.ElapsedMilliseconds}ms"); + return true; + } + + await Task.Delay(pollIntervalMs); + } + + Log($" Timeout waiting for game start ({timeoutMs}ms) - Phase: {owner.GamePhase}"); + return false; + } + + /// + /// Start a game and wait for map data to be loaded + /// The new flow is: StartGame -> Loading phase -> MapData fetched -> All confirm -> Playing + /// + private async Task StartGameAndWaitForMapDataAsync(SimulatorClient owner, SimulatorClient player, int timeoutMs = 25000) + { + Log(" Starting game (this will trigger map data fetch)..."); + owner.StartGame(); + + // Wait for map data first (update both clients so both send confirmations) + if (!await WaitForMapDataAsync(owner, player, timeoutMs)) + { + return false; + } + + // Ensure both clients update to send MapDataReceived confirmation + for (int i = 0; i < 10; i++) + { + owner.Update(); + player.Update(); + await Task.Delay(100); + } + + // Wait for game to actually start (after all confirmations) + return await WaitForGameStartAfterMapDataAsync(owner, player, 10000); + } + + private async Task TestMapDataFetchAsync(Position center, double radius) + { + var result = new TestResult { TestName = "MapDataFetch" }; + SimulatorClient? owner = null; + SimulatorClient? player = null; + + try + { + // Create owner and player (need 2 players to start game) + owner = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "MapOwner"); + player = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "MapPlayer"); + + // Connect owner + Log(" Connecting owner to server..."); + if (!await owner.ConnectAsync(_serverHost, _serverPort)) + { + result.Error = $"Failed to connect owner to server at {_serverHost}:{_serverPort}"; + return result; + } + + // Create lobby with specific center + Log($" Creating lobby at {center.Lat:F6}, {center.Lon:F6} with radius {radius}m..."); + if (!await owner.CreateLobbyAsync(null, center, radius)) + { + result.Error = $"Failed to create lobby: {owner.LastError ?? "Unknown error"}"; + return result; + } + Log($" Lobby created: {owner.JoinCode}"); + + // Connect player + Log(" Connecting player to server..."); + if (!await player.ConnectAsync(_serverHost, _serverPort)) + { + result.Error = "Failed to connect player"; + return result; + } + + // Join player to lobby + if (!await player.JoinLobbyAsync(owner.JoinCode!)) + { + result.Error = "Failed to join player to lobby"; + return result; + } + + // Start game - this triggers map data fetch + Log(" Starting game (triggers Overpass API fetch)..."); + if (!await StartGameAndWaitForMapDataAsync(owner, player, timeoutMs: 25000)) + { + result.Error = "Timeout waiting for map data (Overpass API may be slow or unavailable)"; + return result; + } + + if (owner.HasMapData) + { + var mapData = owner.MapData!; + var buildings = mapData.GetBuildings(); + var pathways = mapData.GetPathways(); + var areas = mapData.GetAreas(); + var pois = mapData.GetPOIs(); + result.Passed = true; + result.Details = $"Buildings: {buildings.Count}\n" + + $"Pathways: {pathways.Count}\n" + + $"Areas: {areas.Count}\n" + + $"POIs: {pois.Count}"; + } + else + { + result.Error = "Map data was not received after game start"; + } + } + catch (Exception ex) + { + result.Error = ex.Message; + } + finally + { + owner?.Dispose(); + player?.Dispose(); + } + + return result; + } + + private async Task TestMapDataStructureAsync(Position center, double radius) + { + var result = new TestResult { TestName = "MapDataStructure" }; + SimulatorClient? owner = null; + SimulatorClient? player = null; + + try + { + owner = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "StructOwner"); + player = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "StructPlayer"); + + if (!await owner.ConnectAsync(_serverHost, _serverPort)) + { + result.Error = "Failed to connect owner"; + return result; + } + + if (!await owner.CreateLobbyAsync(null, center, radius)) + { + result.Error = "Failed to create lobby"; + return result; + } + + if (!await player.ConnectAsync(_serverHost, _serverPort)) + { + result.Error = "Failed to connect player"; + return result; + } + + if (!await player.JoinLobbyAsync(owner.JoinCode!)) + { + result.Error = "Failed to join player to lobby"; + return result; + } + + // Start game to trigger map data fetch + Log(" Starting game (triggers Overpass API fetch)..."); + if (!await StartGameAndWaitForMapDataAsync(owner, player, timeoutMs: 25000)) + { + result.Error = "Timeout waiting for map data"; + return result; + } + + if (!owner.HasMapData) + { + result.Error = "No map data available"; + return result; + } + + var mapData = owner.MapData!; + var buildings = mapData.GetBuildings(); + var pathways = mapData.GetPathways(); + var areas = mapData.GetAreas(); + var pois = mapData.GetPOIs(); + var issues = new List(); + var stats = new List(); + + // Check buildings have valid outlines + int validBuildings = 0; + foreach (var building in buildings) + { + if (building.Outline == null || building.Outline.Count < 3) + { + issues.Add($"Building {building.Id}: Invalid outline (< 3 points)"); + } + else + { + validBuildings++; + } + } + stats.Add($"Valid buildings: {validBuildings}/{buildings.Count}"); + + // Check pathways have valid points + int validPathways = 0; + foreach (var pathway in pathways) + { + if (pathway.Points == null || pathway.Points.Count < 2) + { + issues.Add($"Pathway {pathway.Id}: Invalid points (< 2)"); + } + else + { + validPathways++; + } + } + stats.Add($"Valid pathways: {validPathways}/{pathways.Count}"); + + // Check areas + int validAreas = 0; + foreach (var area in areas) + { + if (area.Outline == null || area.Outline.Count < 3) + { + issues.Add($"Area {area.Id}: Invalid outline"); + } + else + { + validAreas++; + } + } + stats.Add($"Valid areas: {validAreas}/{areas.Count}"); + + // Check POIs have valid positions + int validPOIs = 0; + foreach (var poi in pois) + { + if (poi.Location.Lat != 0 || poi.Location.Lon != 0) + { + validPOIs++; + } + } + stats.Add($"Valid POIs: {validPOIs}/{pois.Count}"); + + result.Passed = issues.Count == 0; + result.Details = string.Join("\n", stats); + if (issues.Count > 0) + { + result.Error = string.Join("; ", issues.Take(5)); + } + } + catch (Exception ex) + { + result.Error = ex.Message; + } + finally + { + owner?.Dispose(); + player?.Dispose(); + } + + return result; + } + + private async Task TestTaskReachabilityAsync(Position center, double radius) + { + var result = new TestResult { TestName = "TaskReachability" }; + SimulatorClient? owner = null; + SimulatorClient? player = null; + + try + { + // Create lobby owner + owner = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "TaskOwner"); + player = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "TaskPlayer"); + + if (!await owner.ConnectAsync(_serverHost, _serverPort)) + { + result.Error = "Owner failed to connect"; + return result; + } + + if (!await owner.CreateLobbyAsync(null, center, radius, 1, 5)) + { + result.Error = "Failed to create lobby"; + return result; + } + + var joinCode = owner.JoinCode; + + if (!await player.ConnectAsync(_serverHost, _serverPort)) + { + result.Error = "Player failed to connect"; + return result; + } + + if (!await player.JoinLobbyAsync(joinCode!)) + { + result.Error = "Player failed to join"; + return result; + } + + // Start game - this triggers map data fetch + Log(" Starting game (triggers Overpass API fetch)..."); + if (!await StartGameAndWaitForMapDataAsync(owner, player, timeoutMs: 25000)) + { + result.Error = "Timeout waiting for game to start"; + return result; + } + + // Check task positions + var mapData = owner.MapData; + var tasks = owner.MyTasks.Count > 0 ? owner.MyTasks : player.MyTasks; + + if (tasks.Count == 0) + { + result.Error = "No tasks were assigned"; + return result; + } + + int tasksInPlayArea = 0; + int tasksOnPathways = 0; + var details = new List(); + + foreach (var task in tasks) + { + var distFromCenter = task.Location.DistanceTo(center); + bool inPlayArea = distFromCenter <= radius; + if (inPlayArea) tasksInPlayArea++; + + // Check if task is near any pathway + bool nearPathway = false; + if (mapData != null) + { + var pathways = mapData.GetPathways(); + foreach (var pathway in pathways) + { + foreach (var point in pathway.Points) + { + if (task.Location.DistanceTo(point) < 15) // Within 15m of pathway + { + nearPathway = true; + break; + } + } + if (nearPathway) break; + } + } + if (nearPathway) tasksOnPathways++; + + details.Add($"{task.Name}: {distFromCenter:F0}m from center, {(inPlayArea ? "in" : "OUT OF")} play area, {(nearPathway ? "near" : "NOT NEAR")} pathway"); + } + + result.Passed = tasksInPlayArea == tasks.Count; + result.Details = $"Tasks in play area: {tasksInPlayArea}/{tasks.Count}\n" + + $"Tasks near pathways: {tasksOnPathways}/{tasks.Count}\n" + + string.Join("\n", details.Take(3)); + + if (tasksInPlayArea < tasks.Count) + { + result.Error = $"{tasks.Count - tasksInPlayArea} tasks are outside play area!"; + } + } + catch (Exception ex) + { + result.Error = ex.Message; + } + finally + { + owner?.Dispose(); + player?.Dispose(); + } + + return result; + } + + private async Task TestRepairStationReachabilityAsync(Position center, double radius) + { + var result = new TestResult { TestName = "RepairStationReachability" }; + SimulatorClient? owner = null; + SimulatorClient? player = null; + + try + { + // Create lobby with 2 players + owner = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "SabOwner"); + player = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "SabPlayer"); + + if (!await owner.ConnectAsync(_serverHost, _serverPort)) { result.Error = "Owner connect failed"; return result; } + if (!await owner.CreateLobbyAsync(null, center, radius, 1, 3)) { result.Error = "Create lobby failed"; return result; } + + var joinCode = owner.JoinCode; + + if (!await player.ConnectAsync(_serverHost, _serverPort)) { result.Error = "Player connect failed"; return result; } + if (!await player.JoinLobbyAsync(joinCode!)) { result.Error = "Join lobby failed"; return result; } + + // Start game - this triggers map data fetch + Log(" Starting game (triggers Overpass API fetch)..."); + if (!await StartGameAndWaitForMapDataAsync(owner, player, timeoutMs: 25000)) + { + result.Error = "Timeout waiting for game to start"; + return result; + } + + // Find impostor and trigger sabotage + var impostor = owner.IsImpostor ? owner : (player.IsImpostor ? player : null); + if (impostor == null) + { + result.Error = "No impostor found"; + return result; + } + + // Wait for sabotage cooldown + await Task.Delay(1000); + + // Try to start a sabotage + impostor.TrySabotage(SabotageType.CriticalMeltdown); + await Task.Delay(1500); + + // Check repair station positions + var crew = owner.IsCrew ? owner : player; + var stations = crew.RepairStations; + + if (stations.Count == 0) + { + // Sabotage might have been blocked, try CommsBlackout + impostor.TrySabotage(SabotageType.CommsBlackout); + await Task.Delay(1000); + stations = crew.RepairStations; + } + + if (stations.Count == 0) + { + result.Passed = true; // No sabotage was possible, but that's OK + result.Details = "Sabotage cooldown active, skipping repair station test"; + return result; + } + + int stationsInPlayArea = 0; + var details = new List(); + + foreach (var station in stations) + { + var distFromCenter = station.Location.DistanceTo(center); + bool inPlayArea = distFromCenter <= radius; + if (inPlayArea) stationsInPlayArea++; + + details.Add($"{station.Name}: {distFromCenter:F0}m from center ({(inPlayArea ? "OK" : "OUT!")})"); + } + + result.Passed = stationsInPlayArea == stations.Count; + result.Details = $"Stations in play area: {stationsInPlayArea}/{stations.Count}\n" + + string.Join("\n", details); + + if (stationsInPlayArea < stations.Count) + { + result.Error = $"{stations.Count - stationsInPlayArea} repair stations are outside play area!"; + } + } + catch (Exception ex) + { + result.Error = ex.Message; + } + finally + { + owner?.Dispose(); + player?.Dispose(); + } + + return result; + } + + private async Task TestPlayAreaBoundaryAsync(Position center, double radius) + { + var result = new TestResult { TestName = "PlayAreaBoundary" }; + SimulatorClient? owner = null; + SimulatorClient? player = null; + + try + { + owner = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "BoundOwner"); + player = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), "BoundPlayer"); + + if (!await owner.ConnectAsync(_serverHost, _serverPort)) { result.Error = "Connect failed"; return result; } + if (!await owner.CreateLobbyAsync(null, center, radius)) { result.Error = "Create lobby failed"; return result; } + + if (!await player.ConnectAsync(_serverHost, _serverPort)) { result.Error = "Player connect failed"; return result; } + if (!await player.JoinLobbyAsync(owner.JoinCode!)) { result.Error = "Join lobby failed"; return result; } + + // Start game - this triggers map data fetch + Log(" Starting game (triggers Overpass API fetch)..."); + if (!await StartGameAndWaitForMapDataAsync(owner, player, timeoutMs: 25000)) + { + result.Passed = true; + result.Details = "No map data to validate (Overpass might be disabled or timed out)"; + return result; + } + + if (!owner.HasMapData) + { + result.Passed = true; + result.Details = "No map data to validate (Overpass might be disabled)"; + return result; + } + + var mapData = owner.MapData!; + var pathways = mapData.GetPathways(); + var pois = mapData.GetPOIs(); + int outsidePathwayPoints = 0; + int totalPathwayPoints = 0; + int outsidePOIs = 0; + int totalPOIs = pois.Count; + + // Check all pathway points + foreach (var pathway in pathways) + { + foreach (var point in pathway.Points) + { + totalPathwayPoints++; + if (point.DistanceTo(center) > radius * 1.1) // Allow 10% margin + { + outsidePathwayPoints++; + } + } + } + + // Check all POIs + foreach (var poi in pois) + { + if (poi.Location.DistanceTo(center) > radius * 1.1) + { + outsidePOIs++; + } + } + + // Allow some points outside (Overpass query might include slightly outside data) + double pathwayOutsidePercent = totalPathwayPoints > 0 ? (outsidePathwayPoints * 100.0 / totalPathwayPoints) : 0; + double poiOutsidePercent = totalPOIs > 0 ? (outsidePOIs * 100.0 / totalPOIs) : 0; + + result.Passed = pathwayOutsidePercent < 20 && poiOutsidePercent < 20; + result.Details = $"Pathway points outside boundary: {outsidePathwayPoints}/{totalPathwayPoints} ({pathwayOutsidePercent:F1}%)\n" + + $"POIs outside boundary: {outsidePOIs}/{totalPOIs} ({poiOutsidePercent:F1}%)"; + + if (!result.Passed) + { + result.Error = "Too many map elements outside play area boundary"; + } + } + catch (Exception ex) + { + result.Error = ex.Message; + } + finally + { + owner?.Dispose(); + player?.Dispose(); + } + + return result; + } + + private async Task TestMapDataConsistencyAsync(Position center, double radius) + { + var result = new TestResult { TestName = "MapDataConsistency" }; + var owners = new List(); + var players = new List(); + + try + { + // Create 3 lobbies at the same location and compare map data + var mapDataResults = new List<(int buildings, int pathways, int pois)>(); + + for (int i = 0; i < 3; i++) + { + Log($" Creating lobby {i + 1}/3..."); + var owner = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), $"ConsOwner{i}"); + var player = new SimulatorClient(Guid.NewGuid().ToString("N").Substring(0, 8), $"ConsPlayer{i}"); + owners.Add(owner); + players.Add(player); + + if (!await owner.ConnectAsync(_serverHost, _serverPort)) continue; + if (!await owner.CreateLobbyAsync(null, center, radius)) continue; + + if (!await player.ConnectAsync(_serverHost, _serverPort)) continue; + if (!await player.JoinLobbyAsync(owner.JoinCode!)) continue; + + // Start game to trigger map data fetch + if (await StartGameAndWaitForMapDataAsync(owner, player, timeoutMs: 25000)) + { + if (owner.HasMapData) + { + var md = owner.MapData!; + mapDataResults.Add((md.GetBuildings().Count, md.GetPathways().Count, md.GetPOIs().Count)); + } + } + + await Task.Delay(300); + } + + if (mapDataResults.Count < 2) + { + result.Passed = true; + result.Details = "Not enough successful map data fetches to compare consistency"; + return result; + } + + // Check if all results are the same (should be cached) + var first = mapDataResults[0]; + bool allSame = mapDataResults.All(r => r == first); + + result.Passed = allSame; + result.Details = string.Join("\n", mapDataResults.Select((r, i) => + $"Lobby {i + 1}: {r.buildings} buildings, {r.pathways} pathways, {r.pois} POIs")); + + if (!allSame) + { + result.Error = "Map data varies between lobbies at same location (caching issue?)"; + } + } + catch (Exception ex) + { + result.Error = ex.Message; + } + finally + { + foreach (var o in owners) o?.Dispose(); + foreach (var p in players) p?.Dispose(); + } + + return result; + } +} + +/// +/// Results from a single test +/// +public class TestResult +{ + public string TestName { get; set; } = ""; + public bool Passed { get; set; } + public string? Details { get; set; } + public string? Error { get; set; } +} + +/// +/// Aggregate results from all Overpass tests +/// +public class OverpassTestResults +{ + public TestResult MapDataFetchTest { get; set; } = new(); + public TestResult MapDataStructureTest { get; set; } = new(); + public TestResult TaskReachabilityTest { get; set; } = new(); + public TestResult RepairStationReachabilityTest { get; set; } = new(); + public TestResult PlayAreaBoundaryTest { get; set; } = new(); + public TestResult ConsistencyTest { get; set; } = new(); + + public int TotalTests => 6; + public int PassedTests => new[] { MapDataFetchTest, MapDataStructureTest, TaskReachabilityTest, + RepairStationReachabilityTest, PlayAreaBoundaryTest, ConsistencyTest }.Count(t => t.Passed); + public int FailedTests => TotalTests - PassedTests; + public bool AllPassed => PassedTests == TotalTests; + + public void PrintSummary(Action log) + { + log($" Total Tests: {TotalTests}"); + log($" Passed: {PassedTests}"); + log($" Failed: {FailedTests}"); + log(""); + + if (AllPassed) + { + log(" ✓ ALL OVERPASS TESTS PASSED!"); + } + else + { + log(" ✗ SOME TESTS FAILED:"); + if (!MapDataFetchTest.Passed) log($" - Map Data Fetch: {MapDataFetchTest.Error}"); + if (!MapDataStructureTest.Passed) log($" - Map Data Structure: {MapDataStructureTest.Error}"); + if (!TaskReachabilityTest.Passed) log($" - Task Reachability: {TaskReachabilityTest.Error}"); + if (!RepairStationReachabilityTest.Passed) log($" - Repair Station Reachability: {RepairStationReachabilityTest.Error}"); + if (!PlayAreaBoundaryTest.Passed) log($" - Play Area Boundary: {PlayAreaBoundaryTest.Error}"); + if (!ConsistencyTest.Passed) log($" - Consistency: {ConsistencyTest.Error}"); + } + } +} +} diff --git a/Assets/ClientSDK/SimulatorClient.cs.meta b/Assets/ClientSDK/SimulatorClient.cs.meta new file mode 100644 index 0000000..33e1383 --- /dev/null +++ b/Assets/ClientSDK/SimulatorClient.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 80ef0979df5d1fe489225f3e5edadc5c \ No newline at end of file diff --git a/Assets/ClientSDK/bin.meta b/Assets/ClientSDK/bin.meta new file mode 100644 index 0000000..595f334 --- /dev/null +++ b/Assets/ClientSDK/bin.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3a4035bdb812fee4f96cb1aa1b24c999 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/bin/Debug.meta b/Assets/ClientSDK/bin/Debug.meta new file mode 100644 index 0000000..7f949f6 --- /dev/null +++ b/Assets/ClientSDK/bin/Debug.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7d9de4c3bce3edb458cde89bd004889b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/bin/Debug/netstandard2.1.meta b/Assets/ClientSDK/bin/Debug/netstandard2.1.meta new file mode 100644 index 0000000..6e0a0f3 --- /dev/null +++ b/Assets/ClientSDK/bin/Debug/netstandard2.1.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c7a6dde302cf01245974d243ceeba40f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.deps.json b/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.deps.json new file mode 100644 index 0000000..0d7c376 --- /dev/null +++ b/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.deps.json @@ -0,0 +1,42 @@ +{ + "runtimeTarget": { + "name": ".NETStandard,Version=v2.1/", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETStandard,Version=v2.1": {}, + ".NETStandard,Version=v2.1/": { + "ClientSDK/1.0.0": { + "dependencies": { + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "ClientSDK.dll": {} + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/netstandard2.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + } + } + }, + "libraries": { + "ClientSDK/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.deps.json.meta b/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.deps.json.meta new file mode 100644 index 0000000..df4489c --- /dev/null +++ b/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.deps.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 110fcc3f27ca804418e17744b419333f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.dll b/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.dll new file mode 100644 index 0000000..884654c Binary files /dev/null and b/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.dll differ diff --git a/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.dll.meta b/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.dll.meta new file mode 100644 index 0000000..87cfe3f --- /dev/null +++ b/Assets/ClientSDK/bin/Debug/netstandard2.1/ClientSDK.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 47eeb682cfff82d42906fbccdbd561d8 \ No newline at end of file diff --git a/Assets/ClientSDK/obj.meta b/Assets/ClientSDK/obj.meta new file mode 100644 index 0000000..c1a843e --- /dev/null +++ b/Assets/ClientSDK/obj.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 131d9de257c8edc49991d792c6e702f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.dgspec.json b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.dgspec.json new file mode 100644 index 0000000..8def387 --- /dev/null +++ b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.dgspec.json @@ -0,0 +1,80 @@ +{ + "format": 1, + "restore": { + "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\ClientSDK.csproj": {} + }, + "projects": { + "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\ClientSDK.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\ClientSDK.csproj", + "projectName": "ClientSDK", + "projectPath": "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\ClientSDK.csproj", + "packagesPath": "C:\\Users\\racek\\.nuget\\packages\\", + "outputPath": "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\racek\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "netstandard2.1" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "netstandard2.1": { + "targetAlias": "netstandard2.1", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "netstandard2.1": { + "targetAlias": "netstandard2.1", + "dependencies": { + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "NETStandard.Library": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.dgspec.json.meta b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.dgspec.json.meta new file mode 100644 index 0000000..e9eb929 --- /dev/null +++ b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.dgspec.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e24090cfcd76d42498d81c9b779bae93 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.props b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.props new file mode 100644 index 0000000..aeb2090 --- /dev/null +++ b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.props @@ -0,0 +1,16 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\.nuget\packages\ + C:\Users\racek\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages + PackageReference + 7.0.0 + + + + + + \ No newline at end of file diff --git a/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.props.meta b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.props.meta new file mode 100644 index 0000000..73062bc --- /dev/null +++ b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.props.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6967c057762dbec4a80dc0381b9a50fd +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.targets b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.targets.meta b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.targets.meta new file mode 100644 index 0000000..4297d70 --- /dev/null +++ b/Assets/ClientSDK/obj/ClientSDK.csproj.nuget.g.targets.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fe3bd5ad8f9636d41bde2abb0ebb7530 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug.meta b/Assets/ClientSDK/obj/Debug.meta new file mode 100644 index 0000000..4518b30 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fb4cee9375d0f244e8995615ecaab70c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1.meta new file mode 100644 index 0000000..c99f0f8 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 664b1b069bb17b84a9566b7c76536173 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/.NETStandard,Version=v2.1.AssemblyAttributes.cs b/Assets/ClientSDK/obj/Debug/netstandard2.1/.NETStandard,Version=v2.1.AssemblyAttributes.cs new file mode 100644 index 0000000..348b87f --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/.NETStandard,Version=v2.1.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfo.cs b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfo.cs new file mode 100644 index 0000000..ec2b5fc --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("ClientSDK")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+6fe5fff60c8e5c83560302ffb9d5f5db433cb667")] +[assembly: System.Reflection.AssemblyProductAttribute("ClientSDK")] +[assembly: System.Reflection.AssemblyTitleAttribute("ClientSDK")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfo.cs.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfo.cs.meta new file mode 100644 index 0000000..0bad271 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 317c8ca649884794eace1306da9518f4 \ No newline at end of file diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfoInputs.cache b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfoInputs.cache new file mode 100644 index 0000000..b2a5916 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +909f73150fc5400d21d798cce0fdeae4562227aba62b3fefaf41c4ebe3479a28 diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfoInputs.cache.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfoInputs.cache.meta new file mode 100644 index 0000000..dbea25c --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.AssemblyInfoInputs.cache.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 793d203358b179c4d8174f2084b26bf7 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.GeneratedMSBuildEditorConfig.editorconfig b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..a2ae7bb --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,8 @@ +is_global = true +build_property.RootNamespace = GeoSus.Client +build_property.ProjectDir = C:\Users\racek\Documents\GeoSus\ClientSDK\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.CsWinRTUseWindowsUIXamlProjections = false +build_property.EffectiveAnalysisLevelStyle = +build_property.EnableCodeStyleSeverity = diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.GeneratedMSBuildEditorConfig.editorconfig.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.GeneratedMSBuildEditorConfig.editorconfig.meta new file mode 100644 index 0000000..28773de --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.GeneratedMSBuildEditorConfig.editorconfig.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9ab4374e13e28254dbd1261542fbfde3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.assets.cache b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.assets.cache new file mode 100644 index 0000000..fca9b0e Binary files /dev/null and b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.assets.cache differ diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.assets.cache.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.assets.cache.meta new file mode 100644 index 0000000..6085204 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.assets.cache.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4e8560c40c30c0a4797e7be274a73c54 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.AssemblyReference.cache b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.AssemblyReference.cache new file mode 100644 index 0000000..3d8a525 Binary files /dev/null and b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.AssemblyReference.cache differ diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.AssemblyReference.cache.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.AssemblyReference.cache.meta new file mode 100644 index 0000000..086ac07 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.AssemblyReference.cache.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5172f98fca4ee924590563b51439fada +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.CoreCompileInputs.cache b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..7004694 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +d380e7a79749800c241c828bf7749c96ff851a709d793dc2a85f50651e2cc678 diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.CoreCompileInputs.cache.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.CoreCompileInputs.cache.meta new file mode 100644 index 0000000..5c2c67b --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.CoreCompileInputs.cache.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 13c4f3623cba4154ab87a8c2d1b77005 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.FileListAbsolute.txt b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..14f81f5 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.FileListAbsolute.txt @@ -0,0 +1,10 @@ +C:\Users\racek\Documents\GeoSus\ClientSDK\obj\Debug\netstandard2.1\ClientSDK.GeneratedMSBuildEditorConfig.editorconfig +C:\Users\racek\Documents\GeoSus\ClientSDK\obj\Debug\netstandard2.1\ClientSDK.AssemblyInfoInputs.cache +C:\Users\racek\Documents\GeoSus\ClientSDK\obj\Debug\netstandard2.1\ClientSDK.AssemblyInfo.cs +C:\Users\racek\Documents\GeoSus\ClientSDK\obj\Debug\netstandard2.1\ClientSDK.csproj.CoreCompileInputs.cache +C:\Users\racek\Documents\GeoSus\ClientSDK\obj\Debug\netstandard2.1\ClientSDK.csproj.AssemblyReference.cache +C:\Users\racek\Documents\GeoSus\ClientSDK\bin\Debug\netstandard2.1\ClientSDK.deps.json +C:\Users\racek\Documents\GeoSus\ClientSDK\bin\Debug\netstandard2.1\ClientSDK.dll +C:\Users\racek\Documents\GeoSus\ClientSDK\bin\Debug\netstandard2.1\ClientSDK.pdb +C:\Users\racek\Documents\GeoSus\ClientSDK\obj\Debug\netstandard2.1\ClientSDK.dll +C:\Users\racek\Documents\GeoSus\ClientSDK\obj\Debug\netstandard2.1\ClientSDK.pdb diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.FileListAbsolute.txt.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.FileListAbsolute.txt.meta new file mode 100644 index 0000000..9f7e090 --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.csproj.FileListAbsolute.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 61ddb0a15ce734542b4cabbb8941d1e8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.dll b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.dll new file mode 100644 index 0000000..884654c Binary files /dev/null and b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.dll differ diff --git a/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.dll.meta b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.dll.meta new file mode 100644 index 0000000..c455a8e --- /dev/null +++ b/Assets/ClientSDK/obj/Debug/netstandard2.1/ClientSDK.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8e41cfc0681c5ee488261b7967cb388a \ No newline at end of file diff --git a/Assets/ClientSDK/obj/project.assets.json b/Assets/ClientSDK/obj/project.assets.json new file mode 100644 index 0000000..5b8edec --- /dev/null +++ b/Assets/ClientSDK/obj/project.assets.json @@ -0,0 +1,133 @@ +{ + "version": 3, + "targets": { + ".NETStandard,Version=v2.1": { + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/netstandard2.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + } + } + }, + "libraries": { + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + } + }, + "projectFileDependencyGroups": { + ".NETStandard,Version=v2.1": [ + "Newtonsoft.Json >= 13.0.3" + ] + }, + "packageFolders": { + "C:\\Users\\racek\\.nuget\\packages\\": {}, + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\ClientSDK.csproj", + "projectName": "ClientSDK", + "projectPath": "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\ClientSDK.csproj", + "packagesPath": "C:\\Users\\racek\\.nuget\\packages\\", + "outputPath": "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\obj\\", + "projectStyle": "PackageReference", + "fallbackFolders": [ + "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" + ], + "configFilePaths": [ + "C:\\Users\\racek\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "netstandard2.1" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "C:\\Program Files\\dotnet\\library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "netstandard2.1": { + "targetAlias": "netstandard2.1", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "netstandard2.1": { + "targetAlias": "netstandard2.1", + "dependencies": { + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "NETStandard.Library": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/Assets/ClientSDK/obj/project.assets.json.meta b/Assets/ClientSDK/obj/project.assets.json.meta new file mode 100644 index 0000000..f4897d4 --- /dev/null +++ b/Assets/ClientSDK/obj/project.assets.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 02541c1b9976feb498ad976779a14cab +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ClientSDK/obj/project.nuget.cache b/Assets/ClientSDK/obj/project.nuget.cache new file mode 100644 index 0000000..fe7906f --- /dev/null +++ b/Assets/ClientSDK/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "2Ec22eQ8t2M=", + "success": true, + "projectFilePath": "C:\\Users\\racek\\Documents\\GeoSus\\ClientSDK\\ClientSDK.csproj", + "expectedPackageFiles": [ + "C:\\Users\\racek\\.nuget\\packages\\newtonsoft.json\\13.0.3\\newtonsoft.json.13.0.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/Assets/ClientSDK/obj/project.nuget.cache.meta b/Assets/ClientSDK/obj/project.nuget.cache.meta new file mode 100644 index 0000000..856bb2f --- /dev/null +++ b/Assets/ClientSDK/obj/project.nuget.cache.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 55e25d9881240614a8f797a612adcfb0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/InputSystem_Actions.inputactions b/Assets/InputSystem_Actions.inputactions new file mode 100644 index 0000000..1a12cb9 --- /dev/null +++ b/Assets/InputSystem_Actions.inputactions @@ -0,0 +1,1057 @@ +{ + "name": "InputSystem_Actions", + "maps": [ + { + "name": "Player", + "id": "df70fa95-8a34-4494-b137-73ab6b9c7d37", + "actions": [ + { + "name": "Move", + "type": "Value", + "id": "351f2ccd-1f9f-44bf-9bec-d62ac5c5f408", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Look", + "type": "Value", + "id": "6b444451-8a00-4d00-a97e-f47457f736a8", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Attack", + "type": "Button", + "id": "6c2ab1b8-8984-453a-af3d-a3c78ae1679a", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Interact", + "type": "Button", + "id": "852140f2-7766-474d-8707-702459ba45f3", + "expectedControlType": "Button", + "processors": "", + "interactions": "Hold", + "initialStateCheck": false + }, + { + "name": "Crouch", + "type": "Button", + "id": "27c5f898-bc57-4ee1-8800-db469aca5fe3", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Jump", + "type": "Button", + "id": "f1ba0d36-48eb-4cd5-b651-1c94a6531f70", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Previous", + "type": "Button", + "id": "2776c80d-3c14-4091-8c56-d04ced07a2b0", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Next", + "type": "Button", + "id": "b7230bb6-fc9b-4f52-8b25-f5e19cb2c2ba", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Sprint", + "type": "Button", + "id": "641cd816-40e6-41b4-8c3d-04687c349290", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "", + "id": "978bfe49-cc26-4a3d-ab7b-7d7a29327403", + "path": "/leftStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "WASD", + "id": "00ca640b-d935-4593-8157-c05846ea39b3", + "path": "Dpad", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "e2062cb9-1b15-46a2-838c-2f8d72a0bdd9", + "path": "/w", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "8180e8bd-4097-4f4e-ab88-4523101a6ce9", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "320bffee-a40b-4347-ac70-c210eb8bc73a", + "path": "/s", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "1c5327b5-f71c-4f60-99c7-4e737386f1d1", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "d2581a9b-1d11-4566-b27d-b92aff5fabbc", + "path": "/a", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "2e46982e-44cc-431b-9f0b-c11910bf467a", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "fcfe95b8-67b9-4526-84b5-5d0bc98d6400", + "path": "/d", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "77bff152-3580-4b21-b6de-dcd0c7e41164", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "1635d3fe-58b6-4ba9-a4e2-f4b964f6b5c8", + "path": "/{Primary2DAxis}", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3ea4d645-4504-4529-b061-ab81934c3752", + "path": "/stick", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c1f7a91b-d0fd-4a62-997e-7fb9b69bf235", + "path": "/rightStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8c8e490b-c610-4785-884f-f04217b23ca4", + "path": "/delta", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse;Touch", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3e5f5442-8668-4b27-a940-df99bad7e831", + "path": "/{Hatswitch}", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "143bb1cd-cc10-4eca-a2f0-a3664166fe91", + "path": "/buttonWest", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "05f6913d-c316-48b2-a6bb-e225f14c7960", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "886e731e-7071-4ae4-95c0-e61739dad6fd", + "path": "/primaryTouch/tap", + "interactions": "", + "processors": "", + "groups": ";Touch", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "ee3d0cd2-254e-47a7-a8cb-bc94d9658c54", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8255d333-5683-4943-a58a-ccb207ff1dce", + "path": "/{PrimaryAction}", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b3c1c7f0-bd20-4ee7-a0f1-899b24bca6d7", + "path": "/enter", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "cbac6039-9c09-46a1-b5f2-4e5124ccb5ed", + "path": "/2", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Next", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e15ca19d-e649-4852-97d5-7fe8ccc44e94", + "path": "/dpad/right", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Next", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "f2e9ba44-c423-42a7-ad56-f20975884794", + "path": "/leftShift", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8cbb2f4b-a784-49cc-8d5e-c010b8c7f4e6", + "path": "/leftStickPress", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "d8bf24bf-3f2f-4160-a97c-38ec1eb520ba", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "eb40bb66-4559-4dfa-9a2f-820438abb426", + "path": "/space", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "daba33a1-ad0c-4742-a909-43ad1cdfbeb6", + "path": "/buttonSouth", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "603f3daf-40bd-4854-8724-93e8017f59e3", + "path": "/secondaryButton", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1534dc16-a6aa-499d-9c3a-22b47347b52a", + "path": "/1", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Previous", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "25060bbd-a3a6-476e-8fba-45ae484aad05", + "path": "/dpad/left", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Previous", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1c04ea5f-b012-41d1-a6f7-02e963b52893", + "path": "/e", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b3f66d0b-7751-423f-908b-a11c5bd95930", + "path": "/buttonNorth", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4f4649ac-64a8-4a73-af11-b3faef356a4d", + "path": "/buttonEast", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "36e52cba-0905-478e-a818-f4bfcb9f3b9a", + "path": "/c", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + } + ] + }, + { + "name": "UI", + "id": "272f6d14-89ba-496f-b7ff-215263d3219f", + "actions": [ + { + "name": "Navigate", + "type": "PassThrough", + "id": "c95b2375-e6d9-4b88-9c4c-c5e76515df4b", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Submit", + "type": "Button", + "id": "7607c7b6-cd76-4816-beef-bd0341cfe950", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Cancel", + "type": "Button", + "id": "15cef263-9014-4fd5-94d9-4e4a6234a6ef", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Point", + "type": "PassThrough", + "id": "32b35790-4ed0-4e9a-aa41-69ac6d629449", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Click", + "type": "PassThrough", + "id": "3c7022bf-7922-4f7c-a998-c437916075ad", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "RightClick", + "type": "PassThrough", + "id": "44b200b1-1557-4083-816c-b22cbdf77ddf", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "MiddleClick", + "type": "PassThrough", + "id": "dad70c86-b58c-4b17-88ad-f5e53adf419e", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "ScrollWheel", + "type": "PassThrough", + "id": "0489e84a-4833-4c40-bfae-cea84b696689", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "TrackedDevicePosition", + "type": "PassThrough", + "id": "24908448-c609-4bc3-a128-ea258674378a", + "expectedControlType": "Vector3", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "TrackedDeviceOrientation", + "type": "PassThrough", + "id": "9caa3d8a-6b2f-4e8e-8bad-6ede561bd9be", + "expectedControlType": "Quaternion", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "Gamepad", + "id": "809f371f-c5e2-4e7a-83a1-d867598f40dd", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "14a5d6e8-4aaf-4119-a9ef-34b8c2c548bf", + "path": "/leftStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "9144cbe6-05e1-4687-a6d7-24f99d23dd81", + "path": "/rightStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "2db08d65-c5fb-421b-983f-c71163608d67", + "path": "/leftStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "58748904-2ea9-4a80-8579-b500e6a76df8", + "path": "/rightStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "8ba04515-75aa-45de-966d-393d9bbd1c14", + "path": "/leftStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "712e721c-bdfb-4b23-a86c-a0d9fcfea921", + "path": "/rightStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "fcd248ae-a788-4676-a12e-f4d81205600b", + "path": "/leftStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "1f04d9bc-c50b-41a1-bfcc-afb75475ec20", + "path": "/rightStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "fb8277d4-c5cd-4663-9dc7-ee3f0b506d90", + "path": "/dpad", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "Joystick", + "id": "e25d9774-381c-4a61-b47c-7b6b299ad9f9", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "3db53b26-6601-41be-9887-63ac74e79d19", + "path": "/stick/up", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "0cb3e13e-3d90-4178-8ae6-d9c5501d653f", + "path": "/stick/down", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "0392d399-f6dd-4c82-8062-c1e9c0d34835", + "path": "/stick/left", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "942a66d9-d42f-43d6-8d70-ecb4ba5363bc", + "path": "/stick/right", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "Keyboard", + "id": "ff527021-f211-4c02-933e-5976594c46ed", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "563fbfdd-0f09-408d-aa75-8642c4f08ef0", + "path": "/w", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "eb480147-c587-4a33-85ed-eb0ab9942c43", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "2bf42165-60bc-42ca-8072-8c13ab40239b", + "path": "/s", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "85d264ad-e0a0-4565-b7ff-1a37edde51ac", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "74214943-c580-44e4-98eb-ad7eebe17902", + "path": "/a", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "cea9b045-a000-445b-95b8-0c171af70a3b", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "8607c725-d935-4808-84b1-8354e29bab63", + "path": "/d", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "4cda81dc-9edd-4e03-9d7c-a71a14345d0b", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "9e92bb26-7e3b-4ec4-b06b-3c8f8e498ddc", + "path": "*/{Submit}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Submit", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "82627dcc-3b13-4ba9-841d-e4b746d6553e", + "path": "*/{Cancel}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Cancel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c52c8e0b-8179-41d3-b8a1-d149033bbe86", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e1394cbc-336e-44ce-9ea8-6007ed6193f7", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "5693e57a-238a-46ed-b5ae-e64e6e574302", + "path": "/touch*/position", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4faf7dc9-b979-4210-aa8c-e808e1ef89f5", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8d66d5ba-88d7-48e6-b1cd-198bbfef7ace", + "path": "/tip", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "47c2a644-3ebc-4dae-a106-589b7ca75b59", + "path": "/touch*/press", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "bb9e6b34-44bf-4381-ac63-5aa15d19f677", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "38c99815-14ea-4617-8627-164d27641299", + "path": "/scroll", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "ScrollWheel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4c191405-5738-4d4b-a523-c6a301dbf754", + "path": "/rightButton", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "RightClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "24066f69-da47-44f3-a07e-0015fb02eb2e", + "path": "/middleButton", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "MiddleClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "7236c0d9-6ca3-47cf-a6ee-a97f5b59ea77", + "path": "/devicePosition", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "TrackedDevicePosition", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "23e01e3a-f935-4948-8d8b-9bcac77714fb", + "path": "/deviceRotation", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "TrackedDeviceOrientation", + "isComposite": false, + "isPartOfComposite": false + } + ] + } + ], + "controlSchemes": [ + { + "name": "Keyboard&Mouse", + "bindingGroup": "Keyboard&Mouse", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + }, + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Gamepad", + "bindingGroup": "Gamepad", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Touch", + "bindingGroup": "Touch", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Joystick", + "bindingGroup": "Joystick", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "XR", + "bindingGroup": "XR", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + } + ] +} \ No newline at end of file diff --git a/Assets/InputSystem_Actions.inputactions.meta b/Assets/InputSystem_Actions.inputactions.meta new file mode 100644 index 0000000..6b38b04 --- /dev/null +++ b/Assets/InputSystem_Actions.inputactions.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 052faaac586de48259a63d0c4782560b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3} + generateWrapperCode: 0 + wrapperCodePath: + wrapperClassName: + wrapperCodeNamespace: diff --git a/Assets/Readme.asset b/Assets/Readme.asset new file mode 100644 index 0000000..77c2f83 --- /dev/null +++ b/Assets/Readme.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fcf7219bab7fe46a1ad266029b2fee19, type: 3} + m_Name: Readme + m_EditorClassIdentifier: + icon: {fileID: 2800000, guid: 727a75301c3d24613a3ebcec4a24c2c8, type: 3} + title: URP Empty Template + sections: + - heading: Welcome to the Universal Render Pipeline + text: This template includes the settings and assets you need to start creating with the Universal Render Pipeline. + linkText: + url: + - heading: URP Documentation + text: + linkText: Read more about URP + url: https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest + - heading: Forums + text: + linkText: Get answers and support + url: https://forum.unity.com/forums/universal-render-pipeline.383/ + - heading: Report bugs + text: + linkText: Submit a report + url: https://unity3d.com/unity/qa/bug-reporting + loadedLayout: 1 diff --git a/Assets/Readme.asset.meta b/Assets/Readme.asset.meta new file mode 100644 index 0000000..ab3ad45 --- /dev/null +++ b/Assets/Readme.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8105016687592461f977c054a80ce2f2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes.meta b/Assets/Scenes.meta new file mode 100644 index 0000000..e59fb45 --- /dev/null +++ b/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c53962885c2c4f449125a979d6ad240 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity new file mode 100644 index 0000000..f9ef62d --- /dev/null +++ b/Assets/Scenes/SampleScene.unity @@ -0,0 +1,491 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &330585543 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 330585546} + - component: {fileID: 330585545} + - component: {fileID: 330585544} + - component: {fileID: 330585547} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &330585544 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + m_Enabled: 1 +--- !u!20 &330585545 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &330585546 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &330585547 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 1 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 + m_Version: 2 +--- !u!1 &410087039 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 410087041} + - component: {fileID: 410087040} + - component: {fileID: 410087042} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &410087040 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + m_Enabled: 1 + serializedVersion: 11 + m_Type: 1 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 2 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 5000 + m_UseColorTemperature: 1 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &410087041 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &410087042 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_CustomShadowLayers: 0 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 1 + m_RenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_ShadowRenderingLayersMask: + serializedVersion: 0 + m_Bits: 1 + m_Version: 4 + m_LightLayerMask: 1 + m_ShadowLayerMask: 1 + m_RenderingLayers: 1 + m_ShadowRenderingLayers: 1 +--- !u!1 &525096926 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 525096928} + - component: {fileID: 525096929} + m_Layer: 0 + m_Name: GameManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &525096928 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 525096926} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &525096929 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 525096926} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 719b1c3bbdc301646b2dbfa653d9a455, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::UnityTestClient + serverHost: geosus.honzuvkod.dev + serverPort: 7777 + httpPort: 8080 + useHttps: 1 + currentState: 0 +--- !u!1 &832575517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 832575519} + - component: {fileID: 832575518} + m_Layer: 0 + m_Name: Global Volume + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &832575518 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 832575517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 172515602e62fb746b5d573b38a5fe58, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IsGlobal: 1 + priority: 0 + blendDistance: 0 + weight: 1 + sharedProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2} +--- !u!4 &832575519 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 832575517} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 330585546} + - {fileID: 410087041} + - {fileID: 832575519} + - {fileID: 525096928} diff --git a/Assets/Scenes/SampleScene.unity.meta b/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 0000000..9531828 --- /dev/null +++ b/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99c9720ab356a0642a771bea13969a05 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings.meta b/Assets/Settings.meta new file mode 100644 index 0000000..39b94dd --- /dev/null +++ b/Assets/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 709f11a7f3c4041caa4ef136ea32d874 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/DefaultVolumeProfile.asset b/Assets/Settings/DefaultVolumeProfile.asset new file mode 100644 index 0000000..9e4bbfd --- /dev/null +++ b/Assets/Settings/DefaultVolumeProfile.asset @@ -0,0 +1,983 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-9167874883656233139 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5485954d14dfb9a4c8ead8edb0ded5b1, type: 3} + m_Name: LiftGammaGain + m_EditorClassIdentifier: + active: 1 + lift: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + gamma: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + gain: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} +--- !u!114 &-8270506406425502121 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70afe9e12c7a7ed47911bb608a23a8ff, type: 3} + m_Name: SplitToning + m_EditorClassIdentifier: + active: 1 + shadows: + m_OverrideState: 1 + m_Value: {r: 0.5, g: 0.5, b: 0.5, a: 1} + highlights: + m_OverrideState: 1 + m_Value: {r: 0.5, g: 0.5, b: 0.5, a: 1} + balance: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-8104416584915340131 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: CopyPasteTestComponent2 + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEditor.Rendering.Tests:VolumeComponentCopyPasteTests/CopyPasteTestComponent2 + active: 1 + p1: + m_OverrideState: 1 + m_Value: 0 + p2: + m_OverrideState: 1 + m_Value: 0 + p21: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-7750755424749557576 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60f3b30c03e6ba64d9a27dc9dba8f28d, type: 3} + m_Name: OutlineVolumeComponent + m_EditorClassIdentifier: + active: 1 + Enabled: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-7743500325797982168 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ccf1aba9553839d41ae37dd52e9ebcce, type: 3} + m_Name: MotionBlur + m_EditorClassIdentifier: + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + quality: + m_OverrideState: 1 + m_Value: 0 + intensity: + m_OverrideState: 1 + m_Value: 0 + clamp: + m_OverrideState: 1 + m_Value: 0.05 +--- !u!114 &-7274224791359825572 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0fd9ee276a1023e439cf7a9c393195fa, type: 3} + m_Name: TestAnimationCurveVolumeComponent + m_EditorClassIdentifier: + active: 1 + testParameter: + m_OverrideState: 1 + m_Value: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 10 + inSlope: 0 + outSlope: 10 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 15 + inSlope: 10 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!114 &-6335409530604852063 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 66f335fb1ffd8684294ad653bf1c7564, type: 3} + m_Name: ColorAdjustments + m_EditorClassIdentifier: + active: 1 + postExposure: + m_OverrideState: 1 + m_Value: 0 + contrast: + m_OverrideState: 1 + m_Value: 0 + colorFilter: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + hueShift: + m_OverrideState: 1 + m_Value: 0 + saturation: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-6288072647309666549 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 29fa0085f50d5e54f8144f766051a691, type: 3} + m_Name: FilmGrain + m_EditorClassIdentifier: + active: 1 + type: + m_OverrideState: 1 + m_Value: 0 + intensity: + m_OverrideState: 1 + m_Value: 0 + response: + m_OverrideState: 1 + m_Value: 0.8 + texture: + m_OverrideState: 1 + m_Value: {fileID: 0} +--- !u!114 &-5520245016509672950 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 97c23e3b12dc18c42a140437e53d3951, type: 3} + m_Name: Tonemapping + m_EditorClassIdentifier: + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + neutralHDRRangeReductionMode: + m_OverrideState: 1 + m_Value: 2 + acesPreset: + m_OverrideState: 1 + m_Value: 3 + hueShiftAmount: + m_OverrideState: 1 + m_Value: 0 + detectPaperWhite: + m_OverrideState: 1 + m_Value: 0 + paperWhite: + m_OverrideState: 1 + m_Value: 300 + detectBrightnessLimits: + m_OverrideState: 1 + m_Value: 1 + minNits: + m_OverrideState: 1 + m_Value: 0.005 + maxNits: + m_OverrideState: 1 + m_Value: 1000 +--- !u!114 &-5360449096862653589 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: VolumeComponentSupportedEverywhere + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEngine.Rendering.Tests:VolumeComponentEditorSupportedOnTests/VolumeComponentSupportedEverywhere + active: 1 +--- !u!114 &-5139089513906902183 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5a00a63fdd6bd2a45ab1f2d869305ffd, type: 3} + m_Name: OasisFogVolumeComponent + m_EditorClassIdentifier: + active: 1 + Density: + m_OverrideState: 1 + m_Value: 0 + StartDistance: + m_OverrideState: 1 + m_Value: 0 + HeightRange: + m_OverrideState: 1 + m_Value: {x: 0, y: 50} + Tint: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + SunScatteringIntensity: + m_OverrideState: 1 + m_Value: 2 +--- !u!114 &-4463884970436517307 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fb60a22f311433c4c962b888d1393f88, type: 3} + m_Name: PaniniProjection + m_EditorClassIdentifier: + active: 1 + distance: + m_OverrideState: 1 + m_Value: 0 + cropToFit: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &-1410297666881709256 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6bd486065ce11414fa40e631affc4900, type: 3} + m_Name: ProbeVolumesOptions + m_EditorClassIdentifier: + active: 1 + normalBias: + m_OverrideState: 1 + m_Value: 0.33 + viewBias: + m_OverrideState: 1 + m_Value: 0 + scaleBiasWithMinProbeDistance: + m_OverrideState: 1 + m_Value: 0 + samplingNoise: + m_OverrideState: 1 + m_Value: 0.1 + animateSamplingNoise: + m_OverrideState: 1 + m_Value: 1 + leakReductionMode: + m_OverrideState: 1 + m_Value: 1 + minValidDotProductValue: + m_OverrideState: 1 + m_Value: 0.1 + occlusionOnlyReflectionNormalization: + m_OverrideState: 1 + m_Value: 1 + intensityMultiplier: + m_OverrideState: 1 + m_Value: 1 + skyOcclusionIntensityMultiplier: + m_OverrideState: 1 + m_Value: 1 + worldOffset: + m_OverrideState: 1 + m_Value: {x: 0, y: 0, z: 0} +--- !u!114 &-1216621516061285780 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0b2db86121404754db890f4c8dfe81b2, type: 3} + m_Name: Bloom + m_EditorClassIdentifier: + active: 1 + skipIterations: + m_OverrideState: 1 + m_Value: 1 + threshold: + m_OverrideState: 1 + m_Value: 0.9 + intensity: + m_OverrideState: 1 + m_Value: 0 + scatter: + m_OverrideState: 1 + m_Value: 0.7 + clamp: + m_OverrideState: 1 + m_Value: 65472 + tint: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + highQualityFiltering: + m_OverrideState: 1 + m_Value: 0 + downscale: + m_OverrideState: 1 + m_Value: 0 + maxIterations: + m_OverrideState: 1 + m_Value: 6 + dirtTexture: + m_OverrideState: 1 + m_Value: {fileID: 0} + dimension: 1 + dirtIntensity: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-1170528603972255243 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 221518ef91623a7438a71fef23660601, type: 3} + m_Name: WhiteBalance + m_EditorClassIdentifier: + active: 1 + temperature: + m_OverrideState: 1 + m_Value: 0 + tint: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-581120513425526550 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: CopyPasteTestComponent3 + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEditor.Rendering.Tests:VolumeComponentCopyPasteTests/CopyPasteTestComponent3 + active: 1 + p1: + m_OverrideState: 1 + m_Value: 0 + p2: + m_OverrideState: 1 + m_Value: 0 + p31: + m_OverrideState: 1 + m_Value: {r: 0, g: 0, b: 0, a: 1} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3} + m_Name: DefaultVolumeProfile + m_EditorClassIdentifier: + components: + - {fileID: -9167874883656233139} + - {fileID: 1918650496244738858} + - {fileID: 853819529557874667} + - {fileID: 1052315754049611418} + - {fileID: -1170528603972255243} + - {fileID: -8270506406425502121} + - {fileID: -5520245016509672950} + - {fileID: 7173750748008157695} + - {fileID: 1666464333004379222} + - {fileID: 9001657382290151224} + - {fileID: -6335409530604852063} + - {fileID: -1216621516061285780} + - {fileID: 3959858460715838825} + - {fileID: -7743500325797982168} + - {fileID: 4644742534064026673} + - {fileID: -4463884970436517307} + - {fileID: -6288072647309666549} + - {fileID: 7518938298396184218} + - {fileID: -1410297666881709256} +--- !u!114 &853819529557874667 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 06437c1ff663d574d9447842ba0a72e4, type: 3} + m_Name: ScreenSpaceLensFlare + m_EditorClassIdentifier: + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 + tintColor: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + bloomMip: + m_OverrideState: 1 + m_Value: 1 + firstFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + secondaryFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + warpedFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + warpedFlareScale: + m_OverrideState: 1 + m_Value: {x: 1, y: 1} + samples: + m_OverrideState: 1 + m_Value: 1 + sampleDimmer: + m_OverrideState: 1 + m_Value: 0.5 + vignetteEffect: + m_OverrideState: 1 + m_Value: 1 + startingPosition: + m_OverrideState: 1 + m_Value: 1.25 + scale: + m_OverrideState: 1 + m_Value: 1.5 + streaksIntensity: + m_OverrideState: 1 + m_Value: 0 + streaksLength: + m_OverrideState: 1 + m_Value: 0.5 + streaksOrientation: + m_OverrideState: 1 + m_Value: 0 + streaksThreshold: + m_OverrideState: 1 + m_Value: 0.25 + resolution: + m_OverrideState: 1 + m_Value: 4 + chromaticAbberationIntensity: + m_OverrideState: 1 + m_Value: 0.5 +--- !u!114 &1052315754049611418 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 558a8e2b6826cf840aae193990ba9f2e, type: 3} + m_Name: ShadowsMidtonesHighlights + m_EditorClassIdentifier: + active: 1 + shadows: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + midtones: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + highlights: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + shadowsStart: + m_OverrideState: 1 + m_Value: 0 + shadowsEnd: + m_OverrideState: 1 + m_Value: 0.3 + highlightsStart: + m_OverrideState: 1 + m_Value: 0.55 + highlightsEnd: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &1666464333004379222 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3eb4b772797da9440885e8bd939e9560, type: 3} + m_Name: ColorCurves + m_EditorClassIdentifier: + active: 1 + master: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + red: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + green: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + blue: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + hueVsHue: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + hueVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + satVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + lumVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!114 &1918650496244738858 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e021b4c809a781e468c2988c016ebbea, type: 3} + m_Name: ColorLookup + m_EditorClassIdentifier: + active: 1 + texture: + m_OverrideState: 1 + m_Value: {fileID: 0} + dimension: 1 + contribution: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &3959858460715838825 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c01700fd266d6914ababb731e09af2eb, type: 3} + m_Name: DepthOfField + m_EditorClassIdentifier: + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + gaussianStart: + m_OverrideState: 1 + m_Value: 10 + gaussianEnd: + m_OverrideState: 1 + m_Value: 30 + gaussianMaxRadius: + m_OverrideState: 1 + m_Value: 1 + highQualitySampling: + m_OverrideState: 1 + m_Value: 0 + focusDistance: + m_OverrideState: 1 + m_Value: 10 + aperture: + m_OverrideState: 1 + m_Value: 5.6 + focalLength: + m_OverrideState: 1 + m_Value: 50 + bladeCount: + m_OverrideState: 1 + m_Value: 5 + bladeCurvature: + m_OverrideState: 1 + m_Value: 1 + bladeRotation: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &4251301726029935498 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 74955a4b0b4243bc87231e8b59ed9140, type: 3} + m_Name: TestVolume + m_EditorClassIdentifier: + active: 1 + param: + m_OverrideState: 1 + m_Value: 123 +--- !u!114 &4644742534064026673 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 81180773991d8724ab7f2d216912b564, type: 3} + m_Name: ChromaticAberration + m_EditorClassIdentifier: + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &6940869943325143175 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: VolumeComponentSupportedOnAnySRP + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEngine.Rendering.Tests:VolumeComponentEditorSupportedOnTests/VolumeComponentSupportedOnAnySRP + active: 1 +--- !u!114 &7173750748008157695 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 899c54efeace73346a0a16faa3afe726, type: 3} + m_Name: Vignette + m_EditorClassIdentifier: + active: 1 + color: + m_OverrideState: 1 + m_Value: {r: 0, g: 0, b: 0, a: 1} + center: + m_OverrideState: 1 + m_Value: {x: 0.5, y: 0.5} + intensity: + m_OverrideState: 1 + m_Value: 0 + smoothness: + m_OverrideState: 1 + m_Value: 0.2 + rounded: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &7518938298396184218 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c5e1dc532bcb41949b58bc4f2abfbb7e, type: 3} + m_Name: LensDistortion + m_EditorClassIdentifier: + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 + xMultiplier: + m_OverrideState: 1 + m_Value: 1 + yMultiplier: + m_OverrideState: 1 + m_Value: 1 + center: + m_OverrideState: 1 + m_Value: {x: 0.5, y: 0.5} + scale: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &9001657382290151224 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cdfbdbb87d3286943a057f7791b43141, type: 3} + m_Name: ChannelMixer + m_EditorClassIdentifier: + active: 1 + redOutRedIn: + m_OverrideState: 1 + m_Value: 100 + redOutGreenIn: + m_OverrideState: 1 + m_Value: 0 + redOutBlueIn: + m_OverrideState: 1 + m_Value: 0 + greenOutRedIn: + m_OverrideState: 1 + m_Value: 0 + greenOutGreenIn: + m_OverrideState: 1 + m_Value: 100 + greenOutBlueIn: + m_OverrideState: 1 + m_Value: 0 + blueOutRedIn: + m_OverrideState: 1 + m_Value: 0 + blueOutGreenIn: + m_OverrideState: 1 + m_Value: 0 + blueOutBlueIn: + m_OverrideState: 1 + m_Value: 100 +--- !u!114 &9122958982931076880 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: CopyPasteTestComponent1 + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEditor.Rendering.Tests:VolumeComponentCopyPasteTests/CopyPasteTestComponent1 + active: 1 + p1: + m_OverrideState: 1 + m_Value: 0 + p2: + m_OverrideState: 1 + m_Value: 0 diff --git a/Assets/Settings/DefaultVolumeProfile.asset.meta b/Assets/Settings/DefaultVolumeProfile.asset.meta new file mode 100644 index 0000000..53b314a --- /dev/null +++ b/Assets/Settings/DefaultVolumeProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab09877e2e707104187f6f83e2f62510 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Mobile_RPAsset.asset b/Assets/Settings/Mobile_RPAsset.asset new file mode 100644 index 0000000..7ceffe7 --- /dev/null +++ b/Assets/Settings/Mobile_RPAsset.asset @@ -0,0 +1,135 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: Mobile_RPAsset + m_EditorClassIdentifier: + k_AssetVersion: 12 + k_AssetPreviousVersion: 12 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: 65bc7dbf4170f435aa868c779acfb082, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 0 + m_RequireOpaqueTexture: 0 + m_OpaqueDownsampling: 0 + m_SupportsTerrainHoles: 1 + m_SupportsHDR: 1 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 0.8 + m_UpscalingFilter: 0 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_LightProbeSystem: 0 + m_ProbeVolumeMemoryBudget: 1024 + m_ProbeVolumeBlendingMemoryBudget: 256 + m_SupportProbeVolumeGPUStreaming: 0 + m_SupportProbeVolumeDiskStreaming: 0 + m_SupportProbeVolumeScenarios: 0 + m_SupportProbeVolumeScenarioBlending: 0 + m_ProbeVolumeSHBands: 1 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 1 + m_MainLightShadowmapResolution: 1024 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 0 + m_AdditionalLightsShadowmapResolution: 2048 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 1 + m_ReflectionProbeBoxProjection: 1 + m_ShadowDistance: 50 + m_ShadowCascadeCount: 1 + m_Cascade2Split: 0.25 + m_Cascade3Split: {x: 0.1, y: 0.3} + m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467} + m_CascadeBorder: 0.2 + m_ShadowDepthBias: 1 + m_ShadowNormalBias: 1 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 0 + m_ConservativeEnclosingSphere: 1 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 2 + m_AdditionalLightsCookieResolution: 1024 + m_AdditionalLightsCookieFormat: 1 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 1 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 0 + m_ColorGradingLutSize: 32 + m_UseFastSRGBLinearConversion: 1 + m_SupportDataDrivenLensFlare: 1 + m_SupportScreenSpaceLensFlare: 1 + m_GPUResidentDrawerMode: 0 + m_UseLegacyLightmaps: 0 + m_SmallMeshScreenPercentage: 0 + m_GPUResidentDrawerEnableOcclusionCullingInCameras: 0 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_VolumeProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2} + apvScenesData: + obsoleteSceneBounds: + m_Keys: [] + m_Values: [] + obsoleteHasProbeVolumes: + m_Keys: [] + m_Values: + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 4 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 1 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 0 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 0 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 0 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_PrefilterUseLegacyLightmaps: 0 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} diff --git a/Assets/Settings/Mobile_RPAsset.asset.meta b/Assets/Settings/Mobile_RPAsset.asset.meta new file mode 100644 index 0000000..3660d15 --- /dev/null +++ b/Assets/Settings/Mobile_RPAsset.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e6cbd92db86f4b18aec3ed561671858 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Mobile_Renderer.asset b/Assets/Settings/Mobile_Renderer.asset new file mode 100644 index 0000000..ea246b2 --- /dev/null +++ b/Assets/Settings/Mobile_Renderer.asset @@ -0,0 +1,52 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: Mobile_Renderer + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, + type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, + type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 0} + probeVolumeFragmentationDebugShader: {fileID: 0} + probeVolumeOffsetDebugShader: {fileID: 0} + probeVolumeSamplingDebugShader: {fileID: 0} + probeSamplingDebugMesh: {fileID: 0} + probeSamplingDebugTexture: {fileID: 0} + probeVolumeBlendStatesCS: {fileID: 0} + m_RendererFeatures: [] + m_RendererFeatureMap: + m_UseNativeRenderPass: 1 + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 0 + m_RenderingMode: 0 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 0 diff --git a/Assets/Settings/Mobile_Renderer.asset.meta b/Assets/Settings/Mobile_Renderer.asset.meta new file mode 100644 index 0000000..a3588b1 --- /dev/null +++ b/Assets/Settings/Mobile_Renderer.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65bc7dbf4170f435aa868c779acfb082 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/PC_RPAsset.asset b/Assets/Settings/PC_RPAsset.asset new file mode 100644 index 0000000..a48b885 --- /dev/null +++ b/Assets/Settings/PC_RPAsset.asset @@ -0,0 +1,141 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: PC_RPAsset + m_EditorClassIdentifier: + k_AssetVersion: 12 + k_AssetPreviousVersion: 12 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: f288ae1f4751b564a96ac7587541f7a2, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 1 + m_RequireOpaqueTexture: 1 + m_OpaqueDownsampling: 1 + m_SupportsTerrainHoles: 1 + m_SupportsHDR: 1 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 1 + m_UpscalingFilter: 0 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_LightProbeSystem: 0 + m_ProbeVolumeMemoryBudget: 1024 + m_ProbeVolumeBlendingMemoryBudget: 256 + m_SupportProbeVolumeGPUStreaming: 0 + m_SupportProbeVolumeDiskStreaming: 0 + m_SupportProbeVolumeScenarios: 0 + m_SupportProbeVolumeScenarioBlending: 0 + m_ProbeVolumeSHBands: 1 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 1 + m_MainLightShadowmapResolution: 2048 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 1 + m_AdditionalLightsShadowmapResolution: 2048 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 1 + m_ReflectionProbeBoxProjection: 1 + m_ReflectionProbeAtlas: 1 + m_ShadowDistance: 50 + m_ShadowCascadeCount: 4 + m_Cascade2Split: 0.25 + m_Cascade3Split: {x: 0.1, y: 0.3} + m_Cascade4Split: {x: 0.12299999, y: 0.2926, z: 0.53599995} + m_CascadeBorder: 0.107758604 + m_ShadowDepthBias: 0.1 + m_ShadowNormalBias: 0.5 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 1 + m_ConservativeEnclosingSphere: 1 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 3 + m_AdditionalLightsCookieResolution: 2048 + m_AdditionalLightsCookieFormat: 3 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 1 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 0 + m_ColorGradingLutSize: 32 + m_AllowPostProcessAlphaOutput: 0 + m_UseFastSRGBLinearConversion: 0 + m_SupportDataDrivenLensFlare: 1 + m_SupportScreenSpaceLensFlare: 1 + m_GPUResidentDrawerMode: 0 + m_SmallMeshScreenPercentage: 0 + m_GPUResidentDrawerEnableOcclusionCullingInCameras: 0 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_VolumeProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2} + apvScenesData: + obsoleteSceneBounds: + m_Keys: [] + m_Values: [] + obsoleteHasProbeVolumes: + m_Keys: [] + m_Values: + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 0 + m_PrefilteringModeAdditionalLightShadows: 2 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 2 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 2 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterAlphaOutput: 1 + m_PrefilterSSAODepthNormals: 0 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 0 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 0 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_PrefilterUseLegacyLightmaps: 0 + m_PrefilterBicubicLightmapSampling: 1 + m_PrefilterReflectionProbeBlending: 0 + m_PrefilterReflectionProbeBoxProjection: 0 + m_PrefilterReflectionProbeAtlas: 0 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} diff --git a/Assets/Settings/PC_RPAsset.asset.meta b/Assets/Settings/PC_RPAsset.asset.meta new file mode 100644 index 0000000..e286b2f --- /dev/null +++ b/Assets/Settings/PC_RPAsset.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b83569d67af61e458304325a23e5dfd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/PC_Renderer.asset b/Assets/Settings/PC_Renderer.asset new file mode 100644 index 0000000..475b02e --- /dev/null +++ b/Assets/Settings/PC_Renderer.asset @@ -0,0 +1,95 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: PC_Renderer + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, + type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, + type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 4800000, guid: e5c6678ed2aaa91408dd3df699057aae, + type: 3} + probeVolumeFragmentationDebugShader: {fileID: 4800000, guid: 03cfc4915c15d504a9ed85ecc404e607, + type: 3} + probeVolumeOffsetDebugShader: {fileID: 4800000, guid: 53a11f4ebaebf4049b3638ef78dc9664, + type: 3} + probeVolumeSamplingDebugShader: {fileID: 4800000, guid: 8f96cd657dc40064aa21efcc7e50a2e7, + type: 3} + probeSamplingDebugMesh: {fileID: -3555484719484374845, guid: 57d7c4c16e2765b47a4d2069b311bffe, + type: 3} + probeSamplingDebugTexture: {fileID: 2800000, guid: 24ec0e140fb444a44ab96ee80844e18e, + type: 3} + probeVolumeBlendStatesCS: {fileID: 7200000, guid: b9a23f869c4fd45f19c5ada54dd82176, + type: 3} + m_RendererFeatures: + - {fileID: 7833122117494664109} + m_RendererFeatureMap: ad6b866f10d7b46c + m_UseNativeRenderPass: 1 + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 1 + stencilCompareFunction: 3 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 2 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 0 +--- !u!114 &7833122117494664109 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f62c9c65cf3354c93be831c8bc075510, type: 3} + m_Name: ScreenSpaceAmbientOcclusion + m_EditorClassIdentifier: + m_Active: 1 + m_Settings: + AOMethod: 0 + Downsample: 0 + AfterOpaque: 0 + Source: 1 + NormalSamples: 1 + Intensity: 0.4 + DirectLightingStrength: 0.25 + Radius: 0.3 + Samples: 1 + BlurQuality: 0 + Falloff: 100 + SampleCount: -1 + m_BlueNoise256Textures: + - {fileID: 2800000, guid: 36f118343fc974119bee3d09e2111500, type: 3} + - {fileID: 2800000, guid: 4b7b083e6b6734e8bb2838b0b50a0bc8, type: 3} + - {fileID: 2800000, guid: c06cc21c692f94f5fb5206247191eeee, type: 3} + - {fileID: 2800000, guid: cb76dd40fa7654f9587f6a344f125c9a, type: 3} + - {fileID: 2800000, guid: e32226222ff144b24bf3a5a451de54bc, type: 3} + - {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3} + - {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3} + m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3} diff --git a/Assets/Settings/PC_Renderer.asset.meta b/Assets/Settings/PC_Renderer.asset.meta new file mode 100644 index 0000000..ddae6a5 --- /dev/null +++ b/Assets/Settings/PC_Renderer.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f288ae1f4751b564a96ac7587541f7a2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/SampleSceneProfile.asset b/Assets/Settings/SampleSceneProfile.asset new file mode 100644 index 0000000..c1b0f63 --- /dev/null +++ b/Assets/Settings/SampleSceneProfile.asset @@ -0,0 +1,159 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7893295128165547882 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0b2db86121404754db890f4c8dfe81b2, type: 3} + m_Name: Bloom + m_EditorClassIdentifier: + active: 1 + skipIterations: + m_OverrideState: 1 + m_Value: 0 + threshold: + m_OverrideState: 1 + m_Value: 1 + intensity: + m_OverrideState: 1 + m_Value: 0.25 + scatter: + m_OverrideState: 1 + m_Value: 0.5 + clamp: + m_OverrideState: 0 + m_Value: 65472 + tint: + m_OverrideState: 0 + m_Value: {r: 1, g: 1, b: 1, a: 1} + highQualityFiltering: + m_OverrideState: 1 + m_Value: 1 + downscale: + m_OverrideState: 0 + m_Value: 0 + maxIterations: + m_OverrideState: 0 + m_Value: 6 + dirtTexture: + m_OverrideState: 0 + m_Value: {fileID: 0} + dimension: 1 + dirtIntensity: + m_OverrideState: 0 + m_Value: 0 +--- !u!114 &-3357603926938260329 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 899c54efeace73346a0a16faa3afe726, type: 3} + m_Name: Vignette + m_EditorClassIdentifier: + active: 1 + color: + m_OverrideState: 0 + m_Value: {r: 0, g: 0, b: 0, a: 1} + center: + m_OverrideState: 0 + m_Value: {x: 0.5, y: 0.5} + intensity: + m_OverrideState: 1 + m_Value: 0.2 + smoothness: + m_OverrideState: 0 + m_Value: 0.2 + rounded: + m_OverrideState: 0 + m_Value: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3} + m_Name: SampleSceneProfile + m_EditorClassIdentifier: + components: + - {fileID: 849379129802519247} + - {fileID: -7893295128165547882} + - {fileID: 7391319092446245454} + - {fileID: -3357603926938260329} +--- !u!114 &849379129802519247 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 97c23e3b12dc18c42a140437e53d3951, type: 3} + m_Name: Tonemapping + m_EditorClassIdentifier: + active: 1 + mode: + m_OverrideState: 1 + m_Value: 1 + neutralHDRRangeReductionMode: + m_OverrideState: 0 + m_Value: 2 + acesPreset: + m_OverrideState: 0 + m_Value: 3 + hueShiftAmount: + m_OverrideState: 0 + m_Value: 0 + detectPaperWhite: + m_OverrideState: 1 + m_Value: 0 + paperWhite: + m_OverrideState: 1 + m_Value: 234 + detectBrightnessLimits: + m_OverrideState: 1 + m_Value: 1 + minNits: + m_OverrideState: 1 + m_Value: 0.005 + maxNits: + m_OverrideState: 1 + m_Value: 647 +--- !u!114 &7391319092446245454 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ccf1aba9553839d41ae37dd52e9ebcce, type: 3} + m_Name: MotionBlur + m_EditorClassIdentifier: + active: 0 + mode: + m_OverrideState: 0 + m_Value: 0 + quality: + m_OverrideState: 1 + m_Value: 2 + intensity: + m_OverrideState: 1 + m_Value: 0.6 + clamp: + m_OverrideState: 0 + m_Value: 0.05 diff --git a/Assets/Settings/SampleSceneProfile.asset.meta b/Assets/Settings/SampleSceneProfile.asset.meta new file mode 100644 index 0000000..b82270c --- /dev/null +++ b/Assets/Settings/SampleSceneProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10fc4df2da32a41aaa32d77bc913491c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset b/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset new file mode 100644 index 0000000..bc3daf7 --- /dev/null +++ b/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset @@ -0,0 +1,407 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2ec995e51a6e251468d2a3fd8a686257, type: 3} + m_Name: UniversalRenderPipelineGlobalSettings + m_EditorClassIdentifier: + m_ShaderStrippingSetting: + m_Version: 0 + m_ExportShaderVariants: 1 + m_ShaderVariantLogLevel: 0 + m_StripRuntimeDebugShaders: 1 + m_URPShaderStrippingSetting: + m_Version: 0 + m_StripUnusedPostProcessingVariants: 1 + m_StripUnusedVariants: 1 + m_StripScreenCoordOverrideVariants: 1 + m_ShaderVariantLogLevel: 0 + m_ExportShaderVariants: 1 + m_StripDebugVariants: 1 + m_StripUnusedPostProcessingVariants: 1 + m_StripUnusedVariants: 1 + m_StripScreenCoordOverrideVariants: 1 + supportRuntimeDebugDisplay: 0 + m_EnableRenderGraph: 0 + m_Settings: + m_SettingsList: + m_List: + - rid: 6852985685364965376 + - rid: 6852985685364965377 + - rid: 6852985685364965378 + - rid: 6852985685364965379 + - rid: 6852985685364965380 + - rid: 6852985685364965381 + - rid: 6852985685364965382 + - rid: 6852985685364965383 + - rid: 6852985685364965384 + - rid: 6852985685364965385 + - rid: 6852985685364965386 + - rid: 6852985685364965387 + - rid: 6852985685364965388 + - rid: 6852985685364965389 + - rid: 6852985685364965390 + - rid: 6852985685364965391 + - rid: 6852985685364965392 + - rid: 6852985685364965393 + - rid: 6852985685364965394 + - rid: 8712630790384254976 + - rid: 6474872856636817408 + - rid: 6474872856636817409 + - rid: 6474872856636817410 + - rid: 6474872856636817411 + - rid: 6474872856636817412 + - rid: 6474872856636817413 + - rid: 6474872856636817414 + - rid: 6474872856636817415 + - rid: 6474872856636817416 + m_RuntimeSettings: + m_List: + - rid: 6852985685364965378 + - rid: 6852985685364965379 + - rid: 6852985685364965380 + - rid: 6852985685364965381 + - rid: 6852985685364965384 + - rid: 6852985685364965385 + - rid: 6852985685364965392 + - rid: 6852985685364965394 + - rid: 8712630790384254976 + - rid: 6474872856636817409 + - rid: 6474872856636817411 + - rid: 6474872856636817412 + - rid: 6474872856636817415 + - rid: 6474872856636817416 + m_AssetVersion: 8 + m_ObsoleteDefaultVolumeProfile: {fileID: 0} + m_RenderingLayerNames: + - Light Layer default + - Light Layer 1 + - Light Layer 2 + - Light Layer 3 + - Light Layer 4 + - Light Layer 5 + - Light Layer 6 + - Light Layer 7 + m_ValidRenderingLayers: 0 + lightLayerName0: Light Layer default + lightLayerName1: Light Layer 1 + lightLayerName2: Light Layer 2 + lightLayerName3: Light Layer 3 + lightLayerName4: Light Layer 4 + lightLayerName5: Light Layer 5 + lightLayerName6: Light Layer 6 + lightLayerName7: Light Layer 7 + apvScenesData: + obsoleteSceneBounds: + m_Keys: [] + m_Values: [] + obsoleteHasProbeVolumes: + m_Keys: [] + m_Values: + references: + version: 2 + RefIds: + - rid: 6474872856636817408 + type: {class: PostProcessData/ShaderResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + stopNanPS: {fileID: 4800000, guid: 1121bb4e615ca3c48b214e79e841e823, type: 3} + subpixelMorphologicalAntialiasingPS: {fileID: 4800000, guid: 63eaba0ebfb82cc43bde059b4a8c65f6, type: 3} + gaussianDepthOfFieldPS: {fileID: 4800000, guid: 5e7134d6e63e0bc47a1dd2669cedb379, type: 3} + bokehDepthOfFieldPS: {fileID: 4800000, guid: 2aed67ad60045d54ba3a00c91e2d2631, type: 3} + cameraMotionBlurPS: {fileID: 4800000, guid: 1edcd131364091c46a17cbff0b1de97a, type: 3} + paniniProjectionPS: {fileID: 4800000, guid: a15b78cf8ca26ca4fb2090293153c62c, type: 3} + lutBuilderLdrPS: {fileID: 4800000, guid: 65df88701913c224d95fc554db28381a, type: 3} + lutBuilderHdrPS: {fileID: 4800000, guid: ec9fec698a3456d4fb18cf8bacb7a2bc, type: 3} + bloomPS: {fileID: 4800000, guid: 5f1864addb451f54bae8c86d230f736e, type: 3} + temporalAntialiasingPS: {fileID: 4800000, guid: 9c70c1a35ff15f340b38ea84842358bf, type: 3} + LensFlareDataDrivenPS: {fileID: 4800000, guid: 6cda457ac28612740adb23da5d39ea92, type: 3} + LensFlareScreenSpacePS: {fileID: 4800000, guid: 701880fecb344ea4c9cd0db3407ab287, type: 3} + scalingSetupPS: {fileID: 4800000, guid: e8ee25143a34b8c4388709ea947055d1, type: 3} + easuPS: {fileID: 4800000, guid: 562b7ae4f629f144aa97780546fce7c6, type: 3} + uberPostPS: {fileID: 4800000, guid: e7857e9d0c934dc4f83f270f8447b006, type: 3} + finalPostPassPS: {fileID: 4800000, guid: c49e63ed1bbcb334780a3bd19dfed403, type: 3} + m_ShaderResourcesVersion: 0 + - rid: 6474872856636817409 + type: {class: ScreenSpaceAmbientOcclusionPersistentResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3} + m_Version: 0 + - rid: 6474872856636817410 + type: {class: UniversalRenderPipelineEditorAssets, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_DefaultSettingsVolumeProfile: {fileID: 11400000, guid: eda47df5b85f4f249abf7abd73db2cb2, type: 2} + - rid: 6474872856636817411 + type: {class: ScreenSpaceAmbientOcclusionDynamicResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_BlueNoise256Textures: + - {fileID: 2800000, guid: 36f118343fc974119bee3d09e2111500, type: 3} + - {fileID: 2800000, guid: 4b7b083e6b6734e8bb2838b0b50a0bc8, type: 3} + - {fileID: 2800000, guid: c06cc21c692f94f5fb5206247191eeee, type: 3} + - {fileID: 2800000, guid: cb76dd40fa7654f9587f6a344f125c9a, type: 3} + - {fileID: 2800000, guid: e32226222ff144b24bf3a5a451de54bc, type: 3} + - {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3} + - {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3} + m_Version: 0 + - rid: 6474872856636817412 + type: {class: UniversalRenderPipelineRuntimeXRResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_xrOcclusionMeshPS: {fileID: 4800000, guid: 4431b1f1f743fbf4eb310a967890cbea, type: 3} + m_xrMirrorViewPS: {fileID: 4800000, guid: d5a307c014552314b9f560906d708772, type: 3} + m_xrMotionVector: {fileID: 4800000, guid: f89aac1e4f84468418fe30e611dff395, type: 3} + - rid: 6474872856636817413 + type: {class: PostProcessData/TextureResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + blueNoise16LTex: + - {fileID: 2800000, guid: 81200413a40918d4d8702e94db29911c, type: 3} + - {fileID: 2800000, guid: d50c5e07c9911a74982bddf7f3075e7b, type: 3} + - {fileID: 2800000, guid: 1134690bf9216164dbc75050e35b7900, type: 3} + - {fileID: 2800000, guid: 7ce2118f74614a94aa8a0cdf2e6062c3, type: 3} + - {fileID: 2800000, guid: 2ca97df9d1801e84a8a8f2c53cb744f0, type: 3} + - {fileID: 2800000, guid: e63eef8f54aa9dc4da9a5ac094b503b5, type: 3} + - {fileID: 2800000, guid: 39451254daebd6d40b52899c1f1c0c1b, type: 3} + - {fileID: 2800000, guid: c94ad916058dff743b0f1c969ddbe660, type: 3} + - {fileID: 2800000, guid: ed5ea7ce59ca8ec4f9f14bf470a30f35, type: 3} + - {fileID: 2800000, guid: 071e954febf155243a6c81e48f452644, type: 3} + - {fileID: 2800000, guid: 96aaab9cc247d0b4c98132159688c1af, type: 3} + - {fileID: 2800000, guid: fc3fa8f108657e14486697c9a84ccfc5, type: 3} + - {fileID: 2800000, guid: bfed3e498947fcb4890b7f40f54d85b9, type: 3} + - {fileID: 2800000, guid: d512512f4af60a442ab3458489412954, type: 3} + - {fileID: 2800000, guid: 47a45908f6db0cb44a0d5e961143afec, type: 3} + - {fileID: 2800000, guid: 4dcc0502f8586f941b5c4a66717205e8, type: 3} + - {fileID: 2800000, guid: 9d92991794bb5864c8085468b97aa067, type: 3} + - {fileID: 2800000, guid: 14381521ff11cb74abe3fe65401c23be, type: 3} + - {fileID: 2800000, guid: d36f0fe53425e08499a2333cf423634c, type: 3} + - {fileID: 2800000, guid: d4044ea2490d63b43aa1765f8efbf8a9, type: 3} + - {fileID: 2800000, guid: c9bd74624d8070f429e3f46d161f9204, type: 3} + - {fileID: 2800000, guid: d5c9b274310e5524ebe32a4e4da3df1f, type: 3} + - {fileID: 2800000, guid: f69770e54f2823f43badf77916acad83, type: 3} + - {fileID: 2800000, guid: 10b6c6d22e73dea46a8ab36b6eebd629, type: 3} + - {fileID: 2800000, guid: a2ec5cbf5a9b64345ad3fab0912ddf7b, type: 3} + - {fileID: 2800000, guid: 1c3c6d69a645b804fa232004b96b7ad3, type: 3} + - {fileID: 2800000, guid: d18a24d7b4ed50f4387993566d9d3ae2, type: 3} + - {fileID: 2800000, guid: c989e1ed85cf7154caa922fec53e6af6, type: 3} + - {fileID: 2800000, guid: ff47e5a0f105eb34883b973e51f4db62, type: 3} + - {fileID: 2800000, guid: fa042edbfc40fbd4bad0ab9d505b1223, type: 3} + - {fileID: 2800000, guid: 896d9004736809c4fb5973b7c12eb8b9, type: 3} + - {fileID: 2800000, guid: 179f794063d2a66478e6e726f84a65bc, type: 3} + filmGrainTex: + - {fileID: 2800000, guid: 654c582f7f8a5a14dbd7d119cbde215d, type: 3} + - {fileID: 2800000, guid: dd77ffd079630404e879388999033049, type: 3} + - {fileID: 2800000, guid: 1097e90e1306e26439701489f391a6c0, type: 3} + - {fileID: 2800000, guid: f0b67500f7fad3b4c9f2b13e8f41ba6e, type: 3} + - {fileID: 2800000, guid: 9930fb4528622b34687b00bbe6883de7, type: 3} + - {fileID: 2800000, guid: bd9e8c758250ef449a4b4bfaad7a2133, type: 3} + - {fileID: 2800000, guid: 510a2f57334933e4a8dbabe4c30204e4, type: 3} + - {fileID: 2800000, guid: b4db8180660810945bf8d55ab44352ad, type: 3} + - {fileID: 2800000, guid: fd2fd78b392986e42a12df2177d3b89c, type: 3} + - {fileID: 2800000, guid: 5cdee82a77d13994f83b8fdabed7c301, type: 3} + smaaAreaTex: {fileID: 2800000, guid: d1f1048909d55cd4fa1126ab998f617e, type: 3} + smaaSearchTex: {fileID: 2800000, guid: 51eee22c2a633ef4aada830eed57c3fd, type: 3} + m_TexturesResourcesVersion: 0 + - rid: 6474872856636817414 + type: {class: RenderingDebuggerRuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_version: 0 + - rid: 6474872856636817415 + type: {class: VrsRenderPipelineRuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_TextureComputeShader: {fileID: 7200000, guid: cacb30de6c40c7444bbc78cb0a81fd2a, type: 3} + m_VisualizationShader: {fileID: 4800000, guid: 620b55b8040a88d468e94abe55bed5ba, type: 3} + m_VisualizationLookupTable: + m_Data: + - {r: 1, g: 0, b: 0, a: 1} + - {r: 1, g: 0.92156863, b: 0.015686275, a: 1} + - {r: 1, g: 1, b: 1, a: 1} + - {r: 0, g: 1, b: 0, a: 1} + - {r: 0.75, g: 0.75, b: 0, a: 1} + - {r: 0, g: 0.75, b: 0.55, a: 1} + - {r: 0.5, g: 0, b: 0.5, a: 1} + - {r: 0.5, g: 0.5, b: 0.5, a: 1} + - {r: 0, g: 0, b: 1, a: 1} + m_ConversionLookupTable: + m_Data: + - {r: 1, g: 0, b: 0, a: 1} + - {r: 1, g: 0.92156863, b: 0.015686275, a: 1} + - {r: 1, g: 1, b: 1, a: 1} + - {r: 0, g: 1, b: 0, a: 1} + - {r: 0.75, g: 0.75, b: 0, a: 1} + - {r: 0, g: 0.75, b: 0.55, a: 1} + - {r: 0.5, g: 0, b: 0.5, a: 1} + - {r: 0.5, g: 0.5, b: 0.5, a: 1} + - {r: 0, g: 0, b: 1, a: 1} + - rid: 6474872856636817416 + type: {class: LightmapSamplingSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + m_UseBicubicLightmapSampling: 0 + - rid: 6852985685364965376 + type: {class: URPShaderStrippingSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_StripUnusedPostProcessingVariants: 1 + m_StripUnusedVariants: 1 + m_StripScreenCoordOverrideVariants: 1 + - rid: 6852985685364965377 + type: {class: UniversalRenderPipelineEditorShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_AutodeskInteractive: {fileID: 4800000, guid: 0e9d5a909a1f7e84882a534d0d11e49f, type: 3} + m_AutodeskInteractiveTransparent: {fileID: 4800000, guid: 5c81372d981403744adbdda4433c9c11, type: 3} + m_AutodeskInteractiveMasked: {fileID: 4800000, guid: 80aa867ac363ac043847b06ad71604cd, type: 3} + m_DefaultSpeedTree7Shader: {fileID: 4800000, guid: 0f4122b9a743b744abe2fb6a0a88868b, type: 3} + m_DefaultSpeedTree8Shader: {fileID: -6465566751694194690, guid: 9920c1f1781549a46ba081a2a15a16ec, type: 3} + m_DefaultSpeedTree9Shader: {fileID: -6465566751694194690, guid: cbd3e1cc4ae141c42a30e33b4d666a61, type: 3} + - rid: 6852985685364965378 + type: {class: UniversalRendererResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_CopyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + m_CameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3} + m_StencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3} + m_ClusterDeferred: {fileID: 4800000, guid: 222cce62363a44a380c36bf03b392608, type: 3} + m_StencilDitherMaskSeedPS: {fileID: 4800000, guid: 8c3ee818f2efa514c889881ccb2e95a2, type: 3} + m_DBufferClear: {fileID: 4800000, guid: f056d8bd2a1c7e44e9729144b4c70395, type: 3} + - rid: 6852985685364965379 + type: {class: UniversalRenderPipelineDebugShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_DebugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + m_HdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + m_ProbeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3} + - rid: 6852985685364965380 + type: {class: UniversalRenderPipelineRuntimeShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_FallbackErrorShader: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3} + m_BlitHDROverlay: {fileID: 4800000, guid: a89bee29cffa951418fc1e2da94d1959, type: 3} + m_CoreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} + m_CoreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} + m_SamplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + m_TerrainDetailLit: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + m_TerrainDetailGrassBillboard: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_TerrainDetailGrass: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + - rid: 6852985685364965381 + type: {class: UniversalRenderPipelineRuntimeTextures, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 1 + m_BlueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + m_BayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_DebugFontTex: {fileID: 2800000, guid: 26a413214480ef144b2915d6ff4d0beb, type: 3} + - rid: 6852985685364965382 + type: {class: Renderer2DResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_LightShader: {fileID: 4800000, guid: 3f6c848ca3d7bca4bbe846546ac701a1, type: 3} + m_ProjectedShadowShader: {fileID: 4800000, guid: ce09d4a80b88c5a4eb9768fab4f1ee00, type: 3} + m_SpriteShadowShader: {fileID: 4800000, guid: 44fc62292b65ab04eabcf310e799ccf6, type: 3} + m_SpriteUnshadowShader: {fileID: 4800000, guid: de02b375720b5c445afe83cd483bedf3, type: 3} + m_GeometryShadowShader: {fileID: 4800000, guid: 19349a0f9a7ed4c48a27445bcf92e5e1, type: 3} + m_GeometryUnshadowShader: {fileID: 4800000, guid: 77774d9009bb81447b048c907d4c6273, type: 3} + m_FallOffLookup: {fileID: 2800000, guid: 5688ab254e4c0634f8d6c8e0792331ca, type: 3} + m_CopyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + m_DefaultLitMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_DefaultUnlitMaterial: {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2} + m_DefaultMaskMaterial: {fileID: 2100000, guid: 15d0c3709176029428a0da2f8cecf0b5, type: 2} + - rid: 6852985685364965383 + type: {class: UniversalRenderPipelineEditorMaterials, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_DefaultMaterial: {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + m_DefaultParticleMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2} + m_DefaultLineMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2} + m_DefaultTerrainMaterial: {fileID: 2100000, guid: 594ea882c5a793440b60ff72d896021e, type: 2} + m_DefaultDecalMaterial: {fileID: 2100000, guid: 31d0dcc6f2dd4e4408d18036a2c93862, type: 2} + m_DefaultSpriteMaterial: {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2} + - rid: 6852985685364965384 + type: {class: URPDefaultVolumeProfileSettings, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_VolumeProfile: {fileID: 11400000, guid: ab09877e2e707104187f6f83e2f62510, type: 2} + - rid: 6852985685364965385 + type: {class: RenderGraphSettings, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_EnableRenderCompatibilityMode: 0 + - rid: 6852985685364965386 + type: {class: GPUResidentDrawerResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.GPUDriven.Runtime} + data: + m_Version: 0 + m_InstanceDataBufferCopyKernels: {fileID: 7200000, guid: f984aeb540ded8b4fbb8a2047ab5b2e2, type: 3} + m_InstanceDataBufferUploadKernels: {fileID: 7200000, guid: 53864816eb00f2343b60e1a2c5a262ef, type: 3} + m_TransformUpdaterKernels: {fileID: 7200000, guid: 2a567b9b2733f8d47a700c3c85bed75b, type: 3} + m_WindDataUpdaterKernels: {fileID: 7200000, guid: fde76746e4fd0ed418c224f6b4084114, type: 3} + m_OccluderDepthPyramidKernels: {fileID: 7200000, guid: 08b2b5fb307b0d249860612774a987da, type: 3} + m_InstanceOcclusionCullingKernels: {fileID: 7200000, guid: f6d223acabc2f974795a5a7864b50e6c, type: 3} + m_OcclusionCullingDebugKernels: {fileID: 7200000, guid: b23e766bcf50ca4438ef186b174557df, type: 3} + m_DebugOcclusionTestPS: {fileID: 4800000, guid: d3f0849180c2d0944bc71060693df100, type: 3} + m_DebugOccluderPS: {fileID: 4800000, guid: b3c92426a88625841ab15ca6a7917248, type: 3} + - rid: 6852985685364965387 + type: {class: STP/RuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_setupCS: {fileID: 7200000, guid: 33be2e9a5506b2843bdb2bdff9cad5e1, type: 3} + m_preTaaCS: {fileID: 7200000, guid: a679dba8ec4d9ce45884a270b0e22dda, type: 3} + m_taaCS: {fileID: 7200000, guid: 3923900e2b41b5e47bc25bfdcbcdc9e6, type: 3} + - rid: 6852985685364965388 + type: {class: ProbeVolumeBakingResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + dilationShader: {fileID: 7200000, guid: 6bb382f7de370af41b775f54182e491d, type: 3} + subdivideSceneCS: {fileID: 7200000, guid: bb86f1f0af829fd45b2ebddda1245c22, type: 3} + voxelizeSceneShader: {fileID: 4800000, guid: c8b6a681c7b4e2e4785ffab093907f9e, type: 3} + traceVirtualOffsetCS: {fileID: -6772857160820960102, guid: ff2cbab5da58bf04d82c5f34037ed123, type: 3} + traceVirtualOffsetRT: {fileID: -5126288278712620388, guid: ff2cbab5da58bf04d82c5f34037ed123, type: 3} + skyOcclusionCS: {fileID: -6772857160820960102, guid: 5a2a534753fbdb44e96c3c78b5a6999d, type: 3} + skyOcclusionRT: {fileID: -5126288278712620388, guid: 5a2a534753fbdb44e96c3c78b5a6999d, type: 3} + renderingLayerCS: {fileID: -6772857160820960102, guid: 94a070d33e408384bafc1dea4a565df9, type: 3} + renderingLayerRT: {fileID: -5126288278712620388, guid: 94a070d33e408384bafc1dea4a565df9, type: 3} + - rid: 6852985685364965389 + type: {class: ProbeVolumeGlobalSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + m_ProbeVolumeDisableStreamingAssets: 0 + - rid: 6852985685364965390 + type: {class: ProbeVolumeDebugResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + probeVolumeDebugShader: {fileID: 4800000, guid: 3b21275fd12d65f49babb5286f040f2d, type: 3} + probeVolumeFragmentationDebugShader: {fileID: 4800000, guid: 3a80877c579b9144ebdcc6d923bca303, type: 3} + probeVolumeSamplingDebugShader: {fileID: 4800000, guid: bf54e6528c79a224e96346799064c393, type: 3} + probeVolumeOffsetDebugShader: {fileID: 4800000, guid: db8bd7436dc2c5f4c92655307d198381, type: 3} + probeSamplingDebugMesh: {fileID: -3555484719484374845, guid: 20be25aac4e22ee49a7db76fb3df6de2, type: 3} + numbersDisplayTex: {fileID: 2800000, guid: 73fe53b428c5b3440b7e87ee830b608a, type: 3} + - rid: 6852985685364965391 + type: {class: IncludeAdditionalRPAssets, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_version: 0 + m_IncludeReferencedInScenes: 0 + m_IncludeAssetsByLabel: 0 + m_LabelToInclude: + - rid: 6852985685364965392 + type: {class: ShaderStrippingSetting, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 0 + m_ExportShaderVariants: 1 + m_ShaderVariantLogLevel: 0 + m_StripRuntimeDebugShaders: 1 + - rid: 6852985685364965393 + type: {class: ProbeVolumeRuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + probeVolumeBlendStatesCS: {fileID: 7200000, guid: a3f7b8c99de28a94684cb1daebeccf5d, type: 3} + probeVolumeUploadDataCS: {fileID: 7200000, guid: 0951de5992461754fa73650732c4954c, type: 3} + probeVolumeUploadDataL2CS: {fileID: 7200000, guid: 6196f34ed825db14b81fb3eb0ea8d931, type: 3} + - rid: 6852985685364965394 + type: {class: RenderGraphGlobalSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_version: 0 + m_EnableCompilationCaching: 1 + m_EnableValidityChecks: 1 + - rid: 8712630790384254976 + type: {class: RenderGraphUtilsResources, ns: UnityEngine.Rendering.RenderGraphModule.Util, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 0 + m_CoreCopyPS: {fileID: 4800000, guid: 12dc59547ea167a4ab435097dd0f9add, type: 3} diff --git a/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset.meta b/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset.meta new file mode 100644 index 0000000..81b84f2 --- /dev/null +++ b/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 18dc0cd2c080841dea60987a38ce93fa +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo.meta b/Assets/TutorialInfo.meta new file mode 100644 index 0000000..a700bca --- /dev/null +++ b/Assets/TutorialInfo.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba062aa6c92b140379dbc06b43dd3b9b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Icons.meta b/Assets/TutorialInfo/Icons.meta new file mode 100644 index 0000000..1d19fb9 --- /dev/null +++ b/Assets/TutorialInfo/Icons.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8a0c9218a650547d98138cd835033977 +folderAsset: yes +timeCreated: 1484670163 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Icons/URP.png b/Assets/TutorialInfo/Icons/URP.png new file mode 100644 index 0000000..6194a80 Binary files /dev/null and b/Assets/TutorialInfo/Icons/URP.png differ diff --git a/Assets/TutorialInfo/Icons/URP.png.meta b/Assets/TutorialInfo/Icons/URP.png.meta new file mode 100644 index 0000000..0f2cab0 --- /dev/null +++ b/Assets/TutorialInfo/Icons/URP.png.meta @@ -0,0 +1,134 @@ +fileFormatVersion: 2 +guid: 727a75301c3d24613a3ebcec4a24c2c8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Layout.wlt b/Assets/TutorialInfo/Layout.wlt new file mode 100644 index 0000000..7b50a25 --- /dev/null +++ b/Assets/TutorialInfo/Layout.wlt @@ -0,0 +1,654 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12004, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PixelRect: + serializedVersion: 2 + x: 0 + y: 45 + width: 1666 + height: 958 + m_ShowMode: 4 + m_Title: + m_RootView: {fileID: 6} + m_MinSize: {x: 950, y: 542} + m_MaxSize: {x: 10000, y: 10000} +--- !u!114 &2 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 466 + width: 290 + height: 442 + m_MinSize: {x: 234, y: 271} + m_MaxSize: {x: 10004, y: 10021} + m_ActualView: {fileID: 14} + m_Panes: + - {fileID: 14} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &3 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 4} + - {fileID: 2} + m_Position: + serializedVersion: 2 + x: 973 + y: 0 + width: 290 + height: 908 + m_MinSize: {x: 234, y: 492} + m_MaxSize: {x: 10004, y: 14042} + vertical: 1 + controlID: 226 +--- !u!114 &4 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 290 + height: 466 + m_MinSize: {x: 204, y: 221} + m_MaxSize: {x: 4004, y: 4021} + m_ActualView: {fileID: 17} + m_Panes: + - {fileID: 17} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &5 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 466 + width: 973 + height: 442 + m_MinSize: {x: 202, y: 221} + m_MaxSize: {x: 4002, y: 4021} + m_ActualView: {fileID: 15} + m_Panes: + - {fileID: 15} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &6 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12008, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 7} + - {fileID: 8} + - {fileID: 9} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1666 + height: 958 + m_MinSize: {x: 950, y: 542} + m_MaxSize: {x: 10000, y: 10000} +--- !u!114 &7 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12011, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1666 + height: 30 + m_MinSize: {x: 0, y: 0} + m_MaxSize: {x: 0, y: 0} + m_LastLoadedLayoutName: Tutorial +--- !u!114 &8 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 10} + - {fileID: 3} + - {fileID: 11} + m_Position: + serializedVersion: 2 + x: 0 + y: 30 + width: 1666 + height: 908 + m_MinSize: {x: 713, y: 492} + m_MaxSize: {x: 18008, y: 14042} + vertical: 0 + controlID: 74 +--- !u!114 &9 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12042, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 938 + width: 1666 + height: 20 + m_MinSize: {x: 0, y: 0} + m_MaxSize: {x: 0, y: 0} +--- !u!114 &10 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 12} + - {fileID: 5} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 973 + height: 908 + m_MinSize: {x: 202, y: 442} + m_MaxSize: {x: 4002, y: 8042} + vertical: 1 + controlID: 75 +--- !u!114 &11 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 1263 + y: 0 + width: 403 + height: 908 + m_MinSize: {x: 277, y: 71} + m_MaxSize: {x: 4002, y: 4021} + m_ActualView: {fileID: 13} + m_Panes: + - {fileID: 13} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &12 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 973 + height: 466 + m_MinSize: {x: 202, y: 221} + m_MaxSize: {x: 4002, y: 4021} + m_ActualView: {fileID: 16} + m_Panes: + - {fileID: 16} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &13 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12019, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 0 + m_MinSize: {x: 275, y: 50} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Inspector + m_Image: {fileID: -6905738622615590433, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 0 + m_Pos: + serializedVersion: 2 + x: 2 + y: 19 + width: 401 + height: 887 + m_ScrollPosition: {x: 0, y: 0} + m_InspectorMode: 0 + m_PreviewResizer: + m_CachedPref: -160 + m_ControlHash: -371814159 + m_PrefName: Preview_InspectorPreview + m_PreviewWindow: {fileID: 0} +--- !u!114 &14 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12014, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 0 + m_MinSize: {x: 230, y: 250} + m_MaxSize: {x: 10000, y: 10000} + m_TitleContent: + m_Text: Project + m_Image: {fileID: -7501376956915960154, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 0 + m_Pos: + serializedVersion: 2 + x: 2 + y: 19 + width: 286 + height: 421 + m_SearchFilter: + m_NameFilter: + m_ClassNames: [] + m_AssetLabels: [] + m_AssetBundleNames: [] + m_VersionControlStates: [] + m_ReferencingInstanceIDs: + m_ScenePaths: [] + m_ShowAllHits: 0 + m_SearchArea: 0 + m_Folders: + - Assets + m_ViewMode: 0 + m_StartGridSize: 64 + m_LastFolders: + - Assets + m_LastFoldersGridSize: -1 + m_LastProjectPath: /Users/danielbrauer/Unity Projects/New Unity Project 47 + m_IsLocked: 0 + m_FolderTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: ee240000 + m_LastClickedID: 9454 + m_ExpandedIDs: ee24000000ca9a3bffffff7f + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_AssetTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 68fbffff + m_LastClickedID: 0 + m_ExpandedIDs: ee240000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_ListAreaState: + m_SelectedInstanceIDs: 68fbffff + m_LastClickedInstanceID: -1176 + m_HadKeyboardFocusLastEvent: 0 + m_ExpandedInstanceIDs: c6230000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_NewAssetIndexInList: -1 + m_ScrollPosition: {x: 0, y: 0} + m_GridSize: 64 + m_DirectoriesAreaWidth: 110 +--- !u!114 &15 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12015, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 1 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Game + m_Image: {fileID: -2087823869225018852, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 32 + m_Pos: + serializedVersion: 2 + x: 0 + y: 19 + width: 971 + height: 421 + m_MaximizeOnPlay: 0 + m_Gizmos: 0 + m_Stats: 0 + m_SelectedSizes: 00000000000000000000000000000000000000000000000000000000000000000000000000000000 + m_TargetDisplay: 0 + m_ZoomArea: + m_HRangeLocked: 0 + m_VRangeLocked: 0 + m_HBaseRangeMin: -242.75 + m_HBaseRangeMax: 242.75 + m_VBaseRangeMin: -101 + m_VBaseRangeMax: 101 + m_HAllowExceedBaseRangeMin: 1 + m_HAllowExceedBaseRangeMax: 1 + m_VAllowExceedBaseRangeMin: 1 + m_VAllowExceedBaseRangeMax: 1 + m_ScaleWithWindow: 0 + m_HSlider: 0 + m_VSlider: 0 + m_IgnoreScrollWheelUntilClicked: 0 + m_EnableMouseInput: 1 + m_EnableSliderZoom: 0 + m_UniformScale: 1 + m_UpDirection: 1 + m_DrawArea: + serializedVersion: 2 + x: 0 + y: 17 + width: 971 + height: 404 + m_Scale: {x: 2, y: 2} + m_Translation: {x: 485.5, y: 202} + m_MarginLeft: 0 + m_MarginRight: 0 + m_MarginTop: 0 + m_MarginBottom: 0 + m_LastShownAreaInsideMargins: + serializedVersion: 2 + x: -242.75 + y: -101 + width: 485.5 + height: 202 + m_MinimalGUI: 1 + m_defaultScale: 2 + m_TargetTexture: {fileID: 0} + m_CurrentColorSpace: 0 + m_LastWindowPixelSize: {x: 1942, y: 842} + m_ClearInEditMode: 1 + m_NoCameraWarning: 1 + m_LowResolutionForAspectRatios: 01000000000100000100 +--- !u!114 &16 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12013, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 1 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Scene + m_Image: {fileID: 2318424515335265636, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 32 + m_Pos: + serializedVersion: 2 + x: 0 + y: 19 + width: 971 + height: 445 + m_SceneLighting: 1 + lastFramingTime: 0 + m_2DMode: 0 + m_isRotationLocked: 0 + m_AudioPlay: 0 + m_Position: + m_Target: {x: 0, y: 0, z: 0} + speed: 2 + m_Value: {x: 0, y: 0, z: 0} + m_RenderMode: 0 + m_ValidateTrueMetals: 0 + m_SceneViewState: + showFog: 1 + showMaterialUpdate: 0 + showSkybox: 1 + showFlares: 1 + showImageEffects: 1 + grid: + xGrid: + m_Target: 0 + speed: 2 + m_Value: 0 + yGrid: + m_Target: 1 + speed: 2 + m_Value: 1 + zGrid: + m_Target: 0 + speed: 2 + m_Value: 0 + m_Rotation: + m_Target: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + speed: 2 + m_Value: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + m_Size: + m_Target: 10 + speed: 2 + m_Value: 10 + m_Ortho: + m_Target: 0 + speed: 2 + m_Value: 0 + m_LastSceneViewRotation: {x: 0, y: 0, z: 0, w: 0} + m_LastSceneViewOrtho: 0 + m_ReplacementShader: {fileID: 0} + m_ReplacementString: + m_LastLockedObject: {fileID: 0} + m_ViewIsLockedToObject: 0 +--- !u!114 &17 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12061, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 0 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Hierarchy + m_Image: {fileID: -590624980919486359, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 0 + m_Pos: + serializedVersion: 2 + x: 2 + y: 19 + width: 286 + height: 445 + m_TreeViewState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 68fbffff + m_LastClickedID: -1176 + m_ExpandedIDs: 7efbffff00000000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 0 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_ExpandedScenes: + - + m_CurrenRootInstanceID: 0 + m_Locked: 0 + m_CurrentSortingName: TransformSorting diff --git a/Assets/TutorialInfo/Layout.wlt.meta b/Assets/TutorialInfo/Layout.wlt.meta new file mode 100644 index 0000000..c0c8c77 --- /dev/null +++ b/Assets/TutorialInfo/Layout.wlt.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eabc9546105bf4accac1fd62a63e88e6 +timeCreated: 1487337779 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Scripts.meta b/Assets/TutorialInfo/Scripts.meta new file mode 100644 index 0000000..02da605 --- /dev/null +++ b/Assets/TutorialInfo/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5a9bcd70e6a4b4b05badaa72e827d8e0 +folderAsset: yes +timeCreated: 1475835190 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Scripts/Editor.meta b/Assets/TutorialInfo/Scripts/Editor.meta new file mode 100644 index 0000000..f59f099 --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3ad9b87dffba344c89909c6d1b1c17e1 +folderAsset: yes +timeCreated: 1475593892 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs b/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs new file mode 100644 index 0000000..ad55eca --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs @@ -0,0 +1,242 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using System; +using System.IO; +using System.Reflection; + +[CustomEditor(typeof(Readme))] +[InitializeOnLoad] +public class ReadmeEditor : Editor +{ + static string s_ShowedReadmeSessionStateName = "ReadmeEditor.showedReadme"; + + static string s_ReadmeSourceDirectory = "Assets/TutorialInfo"; + + const float k_Space = 16f; + + static ReadmeEditor() + { + EditorApplication.delayCall += SelectReadmeAutomatically; + } + + static void RemoveTutorial() + { + if (EditorUtility.DisplayDialog("Remove Readme Assets", + + $"All contents under {s_ReadmeSourceDirectory} will be removed, are you sure you want to proceed?", + "Proceed", + "Cancel")) + { + if (Directory.Exists(s_ReadmeSourceDirectory)) + { + FileUtil.DeleteFileOrDirectory(s_ReadmeSourceDirectory); + FileUtil.DeleteFileOrDirectory(s_ReadmeSourceDirectory + ".meta"); + } + else + { + Debug.Log($"Could not find the Readme folder at {s_ReadmeSourceDirectory}"); + } + + var readmeAsset = SelectReadme(); + if (readmeAsset != null) + { + var path = AssetDatabase.GetAssetPath(readmeAsset); + FileUtil.DeleteFileOrDirectory(path + ".meta"); + FileUtil.DeleteFileOrDirectory(path); + } + + AssetDatabase.Refresh(); + } + } + + static void SelectReadmeAutomatically() + { + if (!SessionState.GetBool(s_ShowedReadmeSessionStateName, false)) + { + var readme = SelectReadme(); + SessionState.SetBool(s_ShowedReadmeSessionStateName, true); + + if (readme && !readme.loadedLayout) + { + LoadLayout(); + readme.loadedLayout = true; + } + } + } + + static void LoadLayout() + { + var assembly = typeof(EditorApplication).Assembly; + var windowLayoutType = assembly.GetType("UnityEditor.WindowLayout", true); + var method = windowLayoutType.GetMethod("LoadWindowLayout", BindingFlags.Public | BindingFlags.Static); + method.Invoke(null, new object[] { Path.Combine(Application.dataPath, "TutorialInfo/Layout.wlt"), false }); + } + + static Readme SelectReadme() + { + var ids = AssetDatabase.FindAssets("Readme t:Readme"); + if (ids.Length == 1) + { + var readmeObject = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(ids[0])); + + Selection.objects = new UnityEngine.Object[] { readmeObject }; + + return (Readme)readmeObject; + } + else + { + Debug.Log("Couldn't find a readme"); + return null; + } + } + + protected override void OnHeaderGUI() + { + var readme = (Readme)target; + Init(); + + var iconWidth = Mathf.Min(EditorGUIUtility.currentViewWidth / 3f - 20f, 128f); + + GUILayout.BeginHorizontal("In BigTitle"); + { + if (readme.icon != null) + { + GUILayout.Space(k_Space); + GUILayout.Label(readme.icon, GUILayout.Width(iconWidth), GUILayout.Height(iconWidth)); + } + GUILayout.Space(k_Space); + GUILayout.BeginVertical(); + { + + GUILayout.FlexibleSpace(); + GUILayout.Label(readme.title, TitleStyle); + GUILayout.FlexibleSpace(); + } + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + } + GUILayout.EndHorizontal(); + } + + public override void OnInspectorGUI() + { + var readme = (Readme)target; + Init(); + + foreach (var section in readme.sections) + { + if (!string.IsNullOrEmpty(section.heading)) + { + GUILayout.Label(section.heading, HeadingStyle); + } + + if (!string.IsNullOrEmpty(section.text)) + { + GUILayout.Label(section.text, BodyStyle); + } + + if (!string.IsNullOrEmpty(section.linkText)) + { + if (LinkLabel(new GUIContent(section.linkText))) + { + Application.OpenURL(section.url); + } + } + + GUILayout.Space(k_Space); + } + + if (GUILayout.Button("Remove Readme Assets", ButtonStyle)) + { + RemoveTutorial(); + } + } + + bool m_Initialized; + + GUIStyle LinkStyle + { + get { return m_LinkStyle; } + } + + [SerializeField] + GUIStyle m_LinkStyle; + + GUIStyle TitleStyle + { + get { return m_TitleStyle; } + } + + [SerializeField] + GUIStyle m_TitleStyle; + + GUIStyle HeadingStyle + { + get { return m_HeadingStyle; } + } + + [SerializeField] + GUIStyle m_HeadingStyle; + + GUIStyle BodyStyle + { + get { return m_BodyStyle; } + } + + [SerializeField] + GUIStyle m_BodyStyle; + + GUIStyle ButtonStyle + { + get { return m_ButtonStyle; } + } + + [SerializeField] + GUIStyle m_ButtonStyle; + + void Init() + { + if (m_Initialized) + return; + m_BodyStyle = new GUIStyle(EditorStyles.label); + m_BodyStyle.wordWrap = true; + m_BodyStyle.fontSize = 14; + m_BodyStyle.richText = true; + + m_TitleStyle = new GUIStyle(m_BodyStyle); + m_TitleStyle.fontSize = 26; + + m_HeadingStyle = new GUIStyle(m_BodyStyle); + m_HeadingStyle.fontStyle = FontStyle.Bold; + m_HeadingStyle.fontSize = 18; + + m_LinkStyle = new GUIStyle(m_BodyStyle); + m_LinkStyle.wordWrap = false; + + // Match selection color which works nicely for both light and dark skins + m_LinkStyle.normal.textColor = new Color(0x00 / 255f, 0x78 / 255f, 0xDA / 255f, 1f); + m_LinkStyle.stretchWidth = false; + + m_ButtonStyle = new GUIStyle(EditorStyles.miniButton); + m_ButtonStyle.fontStyle = FontStyle.Bold; + + m_Initialized = true; + } + + bool LinkLabel(GUIContent label, params GUILayoutOption[] options) + { + var position = GUILayoutUtility.GetRect(label, LinkStyle, options); + + Handles.BeginGUI(); + Handles.color = LinkStyle.normal.textColor; + Handles.DrawLine(new Vector3(position.xMin, position.yMax), new Vector3(position.xMax, position.yMax)); + Handles.color = Color.white; + Handles.EndGUI(); + + EditorGUIUtility.AddCursorRect(position, MouseCursor.Link); + + return GUI.Button(position, label, LinkStyle); + } +} diff --git a/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs.meta b/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs.meta new file mode 100644 index 0000000..f038618 --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 476cc7d7cd9874016adc216baab94a0a +timeCreated: 1484146680 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Scripts/Readme.cs b/Assets/TutorialInfo/Scripts/Readme.cs new file mode 100644 index 0000000..95f6269 --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Readme.cs @@ -0,0 +1,16 @@ +using System; +using UnityEngine; + +public class Readme : ScriptableObject +{ + public Texture2D icon; + public string title; + public Section[] sections; + public bool loadedLayout; + + [Serializable] + public class Section + { + public string heading, text, linkText, url; + } +} diff --git a/Assets/TutorialInfo/Scripts/Readme.cs.meta b/Assets/TutorialInfo/Scripts/Readme.cs.meta new file mode 100644 index 0000000..935153f --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Readme.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fcf7219bab7fe46a1ad266029b2fee19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - icon: {instanceID: 0} + executionOrder: 0 + icon: {fileID: 2800000, guid: a186f8a87ca4f4d3aa864638ad5dfb65, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UnityTestClient.meta b/Assets/UnityTestClient.meta new file mode 100644 index 0000000..21bdf0a --- /dev/null +++ b/Assets/UnityTestClient.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 73fe4270e4fe45e4595beed20ffade02 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UnityTestClient/UnityTestClient.cs b/Assets/UnityTestClient/UnityTestClient.cs new file mode 100644 index 0000000..bd7e1c9 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient.cs @@ -0,0 +1,675 @@ +/* +╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ +║ ║ +║ GEOSUS UNITY TEST CLIENT - KOMPLETNÍ PRŮVODCE ║ +║ ║ +║ Tento soubor je součástí testovacího klienta pro hru GeoSus - multiplayer GPS hru inspirovanou ║ +║ hrou Among Us. Tento klient slouží jako referenční implementace pro studenty, kteří chtějí ║ +║ postavit vlastní hru na základě GeoSus serveru. ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 📚 OBSAH DOKUMENTACE: ║ +║ ═══════════════════ ║ +║ ║ +║ 1. ARCHITEKTURA APLIKACE ║ +║ 2. SÍŤOVÁ KOMUNIKACE ║ +║ 3. HERNÍ LOGIKA ║ +║ 4. UŽIVATELSKÉ ROZHRANÍ ║ +║ 5. VYKRESLOVÁNÍ MAPY ║ +║ 6. STATISTIKY HRÁČŮ ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 📁 STRUKTURA SOUBORŮ: ║ +║ ═════════════════════ ║ +║ ║ +║ UnityTestClient_Main.cs - Hlavní třída, inicializace, herní smyčka ║ +║ UnityTestClient_Network.cs - Síťová komunikace, zpracování zpráv ║ +║ UnityTestClient_UI.cs - Veškeré uživatelské rozhraní (IMGUI) ║ +║ UnityTestClient_Map.cs - Vykreslování mapy pomocí 3D objektů ║ +║ UnityTestClient_Game.cs - Herní mechaniky (pohyb, tasky, sabotáže) ║ +║ UnityTestClient_Stats.cs - HTTP API pro statistiky hráčů ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 🎮 1. ARCHITEKTURA APLIKACE ║ +║ ═══════════════════════════ ║ +║ ║ +║ Aplikace používá PARTIAL CLASS pattern - všechny soubory definují stejnou třídu ║ +║ UnityTestClient, která dědí z MonoBehaviour. Unity je automaticky spojí dohromady. ║ +║ ║ +║ Hlavní herní stavy (AppState): ║ +║ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ║ +║ │ MainMenu │───▶│ Lobby │───▶│ Loading │───▶│ InGame │ ║ +║ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ ║ +║ │ │ │ ║ +║ │ │ ▼ ║ +║ │ │ ┌─────────────┐ ║ +║ │ │ │ Meeting │ ║ +║ │ │ └─────────────┘ ║ +║ │ │ │ ║ +║ ▼ ▼ ▼ ║ +║ ┌─────────────────────────────────────────────────────────────────────┐ ║ +║ │ GameEnded │ ║ +║ └─────────────────────────────────────────────────────────────────────┘ ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 🌐 2. SÍŤOVÁ KOMUNIKACE ║ +║ ═══════════════════════ ║ +║ ║ +║ Komunikace probíhá přes TCP socket s AES-256 šifrováním. ║ +║ ║ +║ Handshake proces: ║ +║ 1. Klient posílá ClientHello s UUID a jménem ║ +║ 2. Server odpovídá ServerHello s RSA veřejným klíčem ║ +║ 3. Klient generuje AES klíč, zašifruje ho RSA a pošle KeyExchange ║ +║ 4. Server potvrdí KeyExchangeAck - od teď je vše šifrované AES ║ +║ ║ +║ Formát zpráv: ║ +║ ┌────────────┬──────────────────────────────────────────┐ ║ +║ │ 4 bajty │ N bajtů │ ║ +║ │ (délka) │ (JSON data, po handshake šifrovaná AES) │ ║ +║ └────────────┴──────────────────────────────────────────┘ ║ +║ ║ +║ Důležité typy zpráv: ║ +║ • CreateLobby/JoinLobby - vytvoření/připojení do lobby ║ +║ • StartGame - spuštění hry (pouze owner) ║ +║ • UpdatePosition - aktualizace pozice hráče ║ +║ • KillAttempt - pokus o zabití (pouze impostor) ║ +║ • ReportBody/CallEmergencyMeeting - svolání schůze ║ +║ • CastVote - hlasování ║ +║ • CompleteTask - dokončení úkolu (server validuje pozici) ║ +║ • StartSabotage - spuštění sabotáže (pouze impostor) ║ +║ • ActivateRepairStation - oprava sabotáže ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 🎯 3. HERNÍ LOGIKA ║ +║ ═════════════════ ║ +║ ║ +║ Role hráčů: ║ +║ • Crew (posádka) - plní úkoly, hlasuje, reportuje těla ║ +║ • Impostor - zabíjí, sabotuje, předstírá plnění úkolů ║ +║ ║ +║ Herní fáze (GamePhase): ║ +║ • Lobby - čekání na hráče, nastavení hry ║ +║ • Loading - načítání mapových dat z Overpass API ║ +║ • Playing - hlavní herní fáze ║ +║ • Meeting - diskuze před hlasováním ║ +║ • Voting - hlasování o vyloučení ║ +║ • Ended - konec hry ║ +║ ║ +║ Typy úkolů: ║ +║ • Všechny úkoly jsou INSTANT - stačí přijít na místo a stisknout USE ║ +║ • Server validuje pozici hráče (musí být do 5m od úkolu) ║ +║ • Duchové (mrtví crew) mohou také plnit úkoly ║ +║ ║ +║ Sabotáže (SabotageType): ║ +║ • CommsBlackout - blokuje reporty a emergency meetings, 1 opravná stanice ║ +║ • CriticalMeltdown - časový limit, 2 stanice musí opravovat současně ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 🖥️ 4. UŽIVATELSKÉ ROZHRANÍ ║ +║ ═══════════════════════════ ║ +║ ║ +║ UI používá Unity IMGUI (OnGUI) pro jednoduchost a přenositelnost. ║ +║ Pro produkční hru doporučujeme použít Unity UI (Canvas) nebo UI Toolkit. ║ +║ ║ +║ Škálování UI: ║ +║ • Používáme relativní jednotky (procenta obrazovky) ║ +║ • GUI.matrix pro globální škálování ║ +║ • Responzivní layout pomocí GUILayout ║ +║ ║ +║ Hlavní obrazovky: ║ +║ • MainMenu - připojení, vytvoření lobby, statistiky ║ +║ • Lobby - seznam hráčů, nastavení, chat ║ +║ • HUD - role, úkoly, minimap, sabotáže ║ +║ • Meeting - hlasovací panel, timer ║ +║ • GameEnd - výsledky, statistiky ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 🗺️ 5. VYKRESLOVÁNÍ MAPY ║ +║ ═══════════════════════ ║ +║ ║ +║ Mapa se vykresluje pomocí 3D GameObjects v prostoru Unity: ║ +║ ║ +║ Převod GPS → Unity souřadnice: ║ +║ • Střed mapy (playAreaCenter) = Vector3(0, 0, 0) ║ +║ • 1 metr reálně = 1 Unity jednotka ║ +║ • Latitude → Z osa, Longitude → X osa ║ +║ ║ +║ Vrstvy mapy (od spodu): ║ +║ 1. Podklad (zelená plocha) - Y = 0 ║ +║ 2. Oblasti (parky, voda) - Y = 0.01 ║ +║ 3. Cesty - Y = 0.02 ║ +║ 4. Budovy - Y = 0 až výška budovy ║ +║ 5. POI markery - Y = 0.5 ║ +║ 6. Hráči - Y = 1 ║ +║ 7. Markery (úkoly, těla) - Y = 0.3 ║ +║ ║ +║ Dynamické objekty: ║ +║ • Hráči - capsule s barvou podle stavu ║ +║ • Těla - ležící kapsle ║ +║ • Úkoly - žluté diamanty ║ +║ • Opravné stanice - červené/zelené krychle ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 📊 6. STATISTIKY HRÁČŮ ║ +║ ═══════════════════════ ║ +║ ║ +║ Server poskytuje HTTP REST API na portu 8088: ║ +║ ║ +║ GET /stats/{playerId} - statistiky konkrétního hráče ║ +║ GET /leaderboard - žebříček hráčů ║ +║ GET /health - stav serveru ║ +║ ║ +║ Statistiky zahrnují: ║ +║ • Počet her, výher, proher ║ +║ • Zabití, smrti, K/D ratio ║ +║ • Dokončené úkoly ║ +║ • Win rate jako impostor/crew ║ +║ • Přesnost hlasování ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ 🚀 JAK ZAČÍT: ║ +║ ═════════════ ║ +║ ║ +║ 1. Přidejte VŠECHNY soubory UnityTestClient_*.cs do Unity projektu ║ +║ 2. Přidejte ClientSDK (Protocol.cs, Encryption.cs, EventDispatcher.cs, GameClient.cs) ║ +║ 3. Vytvořte prázdný GameObject a přidejte komponentu UnityTestClient ║ +║ 4. Nastavte v Inspectoru serverHost a serverPort ║ +║ 5. Spusťte server (dotnet run v Server/) ║ +║ 6. Spusťte hru v Unity ║ +║ ║ +║ Pro vlastní hru: ║ +║ • Nahraďte IMGUI za Unity UI Canvas ║ +║ • Přidejte vlastní 3D modely místo primitivních tvarů ║ +║ • Implementujte GPS pohyb místo WASD (Input.location) ║ +║ • Přidejte zvuky, particle efekty, animace ║ +║ ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ +║ ║ +║ ⚠️ DŮLEŽITÉ POZNÁMKY: ║ +║ ═════════════════════ ║ +║ ║ +║ • GameClient.Update() MUSÍ být volán každý frame pro zpracování síťových událostí ║ +║ • Pozice hráče se odesílá automaticky každých 100ms ║ +║ • Server má anti-cheat - příliš rychlý pohyb způsobí varování/kick ║ +║ • Všechny herní akce (zabití, hlasování) validuje server ║ +║ • MapData může být null pokud Overpass API není dostupné ║ +║ ║ +╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ +*/ + +using UnityEngine; +using System; +using System.Collections.Generic; +using GeoSus.Client; + +/// +/// Hlavní třída Unity testovacího klienta pro GeoSus. +/// Tato partial třída obsahuje inicializaci, herní smyčku a správu stavů. +/// +/// POUŽITÍ: +/// 1. Přidejte tento skript na prázdný GameObject +/// 2. Nastavte serverHost a serverPort v Inspectoru +/// 3. Spusťte hru +/// +public partial class UnityTestClient : MonoBehaviour +{ + #region ═══════════════════════════════════════════════════════════════════ + // KONFIGURACE SERVERU + // ════════════════════════════════════════════════════════════════════════ + // Tyto hodnoty nastavte v Unity Inspectoru nebo zde přímo v kódu. + // ServerHost je IP adresa nebo hostname serveru. + // ServerPort je TCP port pro herní komunikaci (výchozí 7777). + // HttpPort je port pro REST API statistik (výchozí 8088). + #endregion + + [Header("Nastavení serveru")] + [Tooltip("IP adresa nebo hostname GeoSus serveru")] + public string serverHost = "127.0.0.1"; + + [Tooltip("TCP port pro herní komunikaci")] + public int serverPort = 7777; + + [Tooltip("HTTP port pro statistiky API (ignorováno pokud useHttps=true)")] + public int httpPort = 8088; + + [Tooltip("Použít HTTPS pro Stats API (pro produkční server)")] + public bool useHttps = false; + + #region ═══════════════════════════════════════════════════════════════════ + // HERNÍ STAVY + // ════════════════════════════════════════════════════════════════════════ + // AppState určuje, která obrazovka se zobrazuje a jaká logika běží. + // Toto je KLIENTSKÝ stav, nezaměňovat s GamePhase ze serveru. + #endregion + + /// + /// Stav aplikace určující aktuální obrazovku. + /// MainMenu -> Lobby -> Loading -> InGame -> GameEnded + /// + public enum AppState + { + /// Hlavní menu - připojení, vytvoření/vstup do lobby + MainMenu, + /// V lobby - čekání na hráče, nastavení hry + Lobby, + /// Načítání - stahování mapových dat + Loading, + /// Ve hře - hlavní gameplay + InGame, + /// Konec hry - zobrazení výsledků + GameEnded + } + + #region ═══════════════════════════════════════════════════════════════════ + // HLAVNÍ PROMĚNNÉ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Aktuální stav aplikace (která obrazovka je aktivní) + /// + [HideInInspector] + public AppState currentState = AppState.MainMenu; + + /// + /// Instance herního klienta z ClientSDK. + /// Obsahuje veškerou síťovou logiku a herní data. + /// + protected GameClient client; + + /// + /// Unikátní ID tohoto klienta (generuje se při startu) + /// + protected string clientUuid; + + /// + /// Zobrazované jméno hráče + /// + protected string displayName = "Hráč"; + + /// + /// Fronta notifikací k zobrazení na obrazovce + /// + protected Queue notifications = new Queue(); + + /// + /// Aktuálně zobrazená notifikace (null = žádná) + /// + protected NotificationData currentNotification; + + /// + /// Čas konce zobrazení aktuální notifikace + /// + protected float notificationEndTime; + + /// + /// Chybová zpráva k zobrazení (null = žádná chyba) + /// + protected string errorMessage; + + /// + /// Čas zmizení chybové zprávy + /// + protected float errorMessageEndTime; + + /// + /// Hlavní herní kamera + /// + protected Camera playerCamera; + + /// + /// Výška kamery nad mapou + /// + protected float cameraHeight = 100f; + + #region ═══════════════════════════════════════════════════════════════════ + // DATOVÉ STRUKTURY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Struktura pro notifikaci na obrazovce + /// + protected struct NotificationData + { + /// Text notifikace + public string message; + /// Barva pozadí + public Color color; + /// Doba zobrazení v sekundách + public float duration; + /// Ikona (emoji nebo text) + public string icon; + } + + #region ═══════════════════════════════════════════════════════════════════ + // UNITY LIFECYCLE + // ════════════════════════════════════════════════════════════════════════ + // Unity volá tyto metody automaticky: + // Awake() - při vytvoření objektu (před Start) + // Start() - před prvním Update + // Update() - každý frame + // OnDestroy() - při zničení objektu + // OnGUI() - pro vykreslení IMGUI (může být vícekrát za frame) + #endregion + + /// + /// Inicializace při vytvoření objektu. + /// Generujeme unikátní UUID pro tohoto klienta. + /// + void Awake() + { + // Generujeme unikátní ID klienta + // V produkční hře byste toto ukládali do PlayerPrefs + clientUuid = Guid.NewGuid().ToString("N").Substring(0, 8); + + // Načteme uložené jméno hráče (pokud existuje) + displayName = PlayerPrefs.GetString("PlayerName", "Hráč" + UnityEngine.Random.Range(1, 999)); + + Debug.Log($"[GeoSus] Klient inicializován s UUID: {clientUuid}"); + } + + /// + /// Inicializace před prvním frame. + /// + void Start() + { + // Nastavení kamery pro top-down pohled + SetupCamera(); + + Debug.Log("[GeoSus] Test klient připraven"); + } + + /// + /// Hlavní herní smyčka - volá se každý frame. + /// DŮLEŽITÉ: Zde musíme volat client.Update() pro zpracování síťových událostí! + /// + void Update() + { + // ═══════════════════════════════════════════════════════════════════ + // KRITICKÉ: Zpracování síťových událostí + // ═══════════════════════════════════════════════════════════════════ + // GameClient používá EventDispatcher pro thread-safe přenos událostí + // ze síťového vlákna do hlavního Unity vlákna. + // BEZ TOHOTO VOLÁNÍ nebudete dostávat žádné události ze serveru! + if (client != null) + { + client.Update(); + } + + // Zpracování vstupu podle aktuálního stavu + switch (currentState) + { + case AppState.InGame: + // Herní logika - pohyb, akce + HandlePlayerInput(); + UpdateGameLogic(); + break; + } + + // Aktualizace notifikací + UpdateNotifications(); + + // Aktualizace herních objektů na mapě + if (currentState == AppState.InGame || currentState == AppState.Loading) + { + UpdateMapObjects(); + } + + // Automatické obnovování statistik + UpdateStatsAutoRefresh(); + } + + /// + /// Úklid při zničení objektu. + /// DŮLEŽITÉ: Vždy se odpojte od serveru při ukončení! + /// + void OnDestroy() + { + // Odpojení od serveru + if (client != null) + { + client.Disconnect("Aplikace ukončena"); + client.Dispose(); + client = null; + } + + // Úklid mapových objektů + CleanupMapObjects(); + + Debug.Log("[GeoSus] Klient ukončen"); + } + + /// Příznak, zda jsou GUI styly inicializované + private bool stylesInitialized = false; + + /// + /// Vykreslení IMGUI - volá se každý frame (může i vícekrát). + /// Veškeré UI se vykresluje zde. + /// + void OnGUI() + { + // Inicializace stylů při prvním volání OnGUI + if (!stylesInitialized) + { + InitializeUIStyles(); + stylesInitialized = true; + } + + // Aplikace škálování UI pro různé rozlišení + ApplyUIScaling(); + + // Vykreslení UI podle aktuálního stavu + switch (currentState) + { + case AppState.MainMenu: + DrawMainMenu(); + break; + case AppState.Lobby: + DrawLobbyScreen(); + break; + case AppState.Loading: + DrawLoadingScreen(); + break; + case AppState.InGame: + DrawGameHUD(); + DrawMeetingPanel(); // Zobrazí se jen pokud je meeting aktivní + break; + case AppState.GameEnded: + DrawGameEndScreen(); + break; + } + + // Overlay prvky (notifikace, chyby) - vždy navrchu + DrawNotifications(); + DrawErrorMessage(); + + // Debug panel (pouze v editoru) + #if UNITY_EDITOR + DrawDebugPanel(); + #endif + } + + #region ═══════════════════════════════════════════════════════════════════ + // POMOCNÉ METODY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Zobrazí notifikaci na obrazovce. + /// Notifikace se řadí do fronty a zobrazují postupně. + /// + /// Text zprávy + /// Barva pozadí + /// Ikona/emoji (volitelné) + protected void ShowNotification(string message, Color color, string icon) + { + ShowNotification(message, color, 3f, icon); + } + + /// + /// Zobrazí notifikaci na obrazovce. + /// Notifikace se řadí do fronty a zobrazují postupně. + /// + /// Text zprávy + /// Barva pozadí + /// Doba zobrazení v sekundách + /// Ikona/emoji (volitelné) + protected void ShowNotification(string message, Color color, float duration = 3f, string icon = "") + { + notifications.Enqueue(new NotificationData + { + message = message, + color = color, + duration = duration, + icon = icon + }); + } + + /// + /// Aktualizace fronty notifikací + /// + private void UpdateNotifications() + { + // Pokud aktuální notifikace vypršela, zobrazíme další + if (currentNotification.message != null && Time.time > notificationEndTime) + { + currentNotification = default; + } + + // Pokud není žádná notifikace a fronta není prázdná, zobrazíme další + if (currentNotification.message == null && notifications.Count > 0) + { + currentNotification = notifications.Dequeue(); + notificationEndTime = Time.time + currentNotification.duration; + } + } + + /// + /// Zobrazí chybovou zprávu + /// + /// Text chyby + /// Doba zobrazení + protected void ShowError(string message, float duration = 5f) + { + errorMessage = message; + errorMessageEndTime = Time.time + duration; + Debug.LogError($"[GeoSus] {message}"); + } + + /// + /// Nastavení kamery pro top-down pohled + /// + private void SetupCamera() + { + // Najdeme nebo vytvoříme hlavní kameru + playerCamera = Camera.main; + if (playerCamera == null) + { + GameObject camObj = new GameObject("MainCamera"); + playerCamera = camObj.AddComponent(); + camObj.tag = "MainCamera"; + } + + // Nastavení pro top-down pohled + playerCamera.orthographic = true; + playerCamera.orthographicSize = 50f; // Výchozí zoom (50 metrů od středu) + playerCamera.transform.position = new Vector3(0, cameraHeight, 0); + playerCamera.transform.rotation = Quaternion.Euler(90, 0, 0); + playerCamera.backgroundColor = new Color(0.2f, 0.3f, 0.2f); // Tmavě zelená + playerCamera.clearFlags = CameraClearFlags.SolidColor; + + // Přidáme naši komponentu pro ovládání kamery + if (playerCamera.GetComponent() == null) + { + playerCamera.gameObject.AddComponent(); + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // DEBUG PANEL + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Debug panel - zobrazuje interní stav klienta + /// Pouze v Unity Editoru + /// + private void DrawDebugPanel() + { + GUILayout.BeginArea(new Rect(10, Screen.height - 150, 300, 140)); + GUI.Box(new Rect(0, 0, 300, 140), ""); + + GUILayout.Label($"DEBUG", richTextStyle); + GUILayout.Label($"State: {currentState}"); + GUILayout.Label($"Connected: {client?.IsConnected ?? false}"); + GUILayout.Label($"LobbyId: {client?.LobbyId ?? "null"}"); + GUILayout.Label($"Phase: {client?.CurrentLobbyState?.Phase.ToString() ?? "null"}"); + GUILayout.Label($"Role: {client?.MyRole?.ToString() ?? "null"}"); + GUILayout.Label($"Ping: {client?.Ping ?? 0}ms"); + + GUILayout.EndArea(); + } +} + +/// +/// Jednoduchý kontroler kamery pro top-down pohled. +/// Umožňuje pohyb pomocí WASD/šipek a zoom pomocí kolečka myši. +/// +/// POZNÁMKA: V produkční hře byste toto pravděpodobně spojili +/// s pohybem hráče - kamera sleduje hráče. +/// +public class CameraController : MonoBehaviour +{ + [Header("Nastavení kamery")] + [Tooltip("Rychlost pohybu kamery")] + public float moveSpeed = 50f; + + [Tooltip("Rychlost zoomu")] + public float zoomSpeed = 10f; + + [Tooltip("Minimální zoom (orthographic size)")] + public float minZoom = 10f; + + [Tooltip("Maximální zoom (orthographic size)")] + public float maxZoom = 200f; + + private Camera cam; + + void Start() + { + cam = GetComponent(); + } + + void Update() + { + // Pohyb kamery - WASD nebo šipky + // POZNÁMKA: V plné hře se kamera obvykle pohybuje s hráčem + float h = Input.GetAxis("Horizontal"); + float v = Input.GetAxis("Vertical"); + + Vector3 movement = new Vector3(h, 0, v) * moveSpeed * Time.deltaTime; + transform.position += movement; + + // Zoom - kolečko myši + float scroll = Input.GetAxis("Mouse ScrollWheel"); + if (scroll != 0 && cam.orthographic) + { + cam.orthographicSize = Mathf.Clamp( + cam.orthographicSize - scroll * zoomSpeed, + minZoom, + maxZoom + ); + } + } +} diff --git a/Assets/UnityTestClient/UnityTestClient.cs.meta b/Assets/UnityTestClient/UnityTestClient.cs.meta new file mode 100644 index 0000000..692a765 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 719b1c3bbdc301646b2dbfa653d9a455 \ No newline at end of file diff --git a/Assets/UnityTestClient/UnityTestClient_Game.cs b/Assets/UnityTestClient/UnityTestClient_Game.cs new file mode 100644 index 0000000..01763f7 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_Game.cs @@ -0,0 +1,673 @@ +/* +╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ +║ ║ +║ HERNÍ MECHANIKY - UnityTestClient_Game.cs ║ +║ ║ +║ Tento soubor obsahuje veškeré herní mechaniky: ║ +║ • Pohyb hráče (WASD + myš) ║ +║ • Interakce (úkoly, reporty, opravy) ║ +║ • Kill mechanika (pro impostory) ║ +║ • Sabotáže a jejich opravy ║ +║ • Emergency meeting ║ +║ • Hlasování ║ +║ ║ +║ OVLÁDÁNÍ: ║ +║ • WASD - pohyb hráče ║ +║ • Myš - otáčení kamery (volitelné) ║ +║ • E - interakce (úkoly, report, oprava) ║ +║ • Q - kill (pouze impostor) ║ +║ • Tab - mapa/statistiky ║ +║ • Escape - menu ║ +║ ║ +║ SYSTÉM ÚKOLŮ: ║ +║ • Všechny úkoly jsou INSTANT - stačí přijít na místo (do 5m) a stisknout E ║ +║ • Server validuje pozici hráče - nemůžete dokončit úkol na dálku ║ +║ • Duchové (mrtví crew) mohou dokončovat úkoly - pomáhají týmu vyhrát ║ +║ • Impostoři NEMOHOU dokončovat úkoly ║ +║ ║ +║ SABOTÁŽE: ║ +║ • CommsBlackout - blokuje reporty a emergency meetings ║ +║ - 1 opravná stanice, libovolný hráč opraví sám ║ +║ • CriticalMeltdown - časový limit na opravu! ║ +║ - 2 stanice musí být opravovány SOUČASNĚ dvěma hráči ║ +║ - Pokud čas vyprší, impostoři vyhrávají ║ +║ ║ +║ POZNÁMKA: ║ +║ V reálné mobilní hře by se pozice hráče aktualizovala podle GPS (Input.location). ║ +║ Tento test klient umožňuje simulovat pohyb pomocí WASD pro testování. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ +*/ + +using UnityEngine; +using System; +using System.Collections.Generic; +using GeoSus.Client; + +// ═══════════════════════════════════════════════════════════════════════════════ +// LOKÁLNÍ TYPY PRO UNITY (kopie z Protocol.cs pro kompatibilitu) +// ═══════════════════════════════════════════════════════════════════════════════ + +/// +/// Reprezentace úkolu hráče +/// +[System.Serializable] +public class PlayerTask +{ + public string Id; + public string Name; + public string Description; + public TaskType Type; + public Position Location; + public bool IsCompleted; +} + +/// +/// Opravná stanice pro sabotáže +/// +[System.Serializable] +public class RepairStation +{ + public string Id; + public string Name; + public Position Position; + public bool IsActive; +} + +public partial class UnityTestClient +{ + #region ═══════════════════════════════════════════════════════════════════ + // GAME PROMĚNNÉ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + // ───────────────────────────────────────────────────────────────────────── + // Pohyb + // ───────────────────────────────────────────────────────────────────────── + + /// Rychlost pohybu hráče (Unity jednotky/s) + protected float moveSpeed = 10f; + + /// Aktuální pozice hráče v Unity souřadnicích + protected Vector3 currentPlayerPosition; + + /// Interval odesílání pozice na server (sekundy) + protected float positionUpdateInterval = 0.5f; + + /// Čas posledního odeslání pozice + protected float lastPositionUpdate; + + // ───────────────────────────────────────────────────────────────────────── + // Opravy + // ───────────────────────────────────────────────────────────────────────── + + /// Právě opravujeme? + protected bool isRepairing = false; + + /// ID aktivní opravné stanice + protected string activeRepairStation = null; + + /// Progress opravy (0-1) + protected float repairProgress = 0f; + + // ───────────────────────────────────────────────────────────────────────── + // Sabotáže + // ───────────────────────────────────────────────────────────────────────── + + /// Aktuální sabotáž (null = žádná) + protected SabotageStartedPayload currentSabotage = null; + + // ───────────────────────────────────────────────────────────────────────── + // Kill + // ───────────────────────────────────────────────────────────────────────── + + /// Cooldown killu (sekundy) + protected float killCooldown = 25f; + + /// Čas posledního killu + protected float lastKillTime = -100f; + + // ───────────────────────────────────────────────────────────────────────── + // Konec hry + // ───────────────────────────────────────────────────────────────────────── + + /// Data o konci hry + protected GameEndedPayload gameEndData = null; + + #region ═══════════════════════════════════════════════════════════════════ + // POHYB HRÁČE + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Zpracování vstupu hráče. + /// Volá se každý frame v Update(). + /// + /// POZNÁMKA PRO STUDENTY: + /// Input.GetAxis vrací hodnotu -1 až 1 pro plynulý pohyb. + /// "Horizontal" = A/D nebo šipky vlevo/vpravo + /// "Vertical" = W/S nebo šipky nahoru/dolů + /// + protected void HandlePlayerInput() + { + // Pohyb pouze během hraní + if (currentState != AppState.InGame) return; + + // Kontrola, zda jsme naživu - bezpečný přístup + if (client?.PlayerPositions != null && + client.PlayerPositions.TryGetValue(clientUuid, out var myInfo)) + { + if (myInfo.State != PlayerState.Alive) + { + // Duch může létat, ale neposílá pozici + HandleGhostMovement(); + return; + } + } + + // Kontrola, zda není meeting - ale během arrival fáze se můžeme hýbat + var phase = client?.CurrentLobbyState?.Phase; + if (phase == GamePhase.Meeting) + { + // Během arrival fáze (před ArrivalDeadline) se můžeme hýbat + if (currentMeeting != null && DateTime.UtcNow < currentMeeting.ArrivalDeadline) + { + // OK - můžeme se hýbat k meeting pointu + } + else + { + return; // Po arrival deadline se nehýbeme + } + } + + // ═══════════════════════════════════════════════════════════════════ + // WASD POHYB + // ═══════════════════════════════════════════════════════════════════ + + float horizontal = Input.GetAxis("Horizontal"); // A/D + float vertical = Input.GetAxis("Vertical"); // W/S + + if (horizontal != 0 || vertical != 0) + { + // Směr pohybu + Vector3 movement = new Vector3(horizontal, 0, vertical).normalized; + + // Aplikace rychlosti a delta time + Vector3 newPosition = currentPlayerPosition + movement * moveSpeed * Time.deltaTime; + + // Kontrola hranic herní oblasti + if (IsPositionInPlayArea(newPosition)) + { + currentPlayerPosition = newPosition; + UpdateCameraPosition(); + } + } + + // ═══════════════════════════════════════════════════════════════════ + // ODESÍLÁNÍ POZICE NA SERVER + // ═══════════════════════════════════════════════════════════════════ + + if (Time.time - lastPositionUpdate >= positionUpdateInterval) + { + SendPositionToServer(); + lastPositionUpdate = Time.time; + } + + // ═══════════════════════════════════════════════════════════════════ + // KLÁVESOVÉ ZKRATKY PRO AKCE + // ═══════════════════════════════════════════════════════════════════ + + // E - Interakce (USE) + if (Input.GetKeyDown(KeyCode.E)) + { + PerformPrimaryAction(); + } + + // Q - Kill (pouze impostor) + if (Input.GetKeyDown(KeyCode.Q) && client?.MyRole == PlayerRole.Impostor) + { + TryKillNearbyPlayer(); + } + + // R - Emergency meeting + if (Input.GetKeyDown(KeyCode.R)) + { + CallEmergencyMeeting(); + } + + // Escape - Menu + if (Input.GetKeyDown(KeyCode.Escape)) + { + // TODO: Toggle pause menu + } + } + + /// + /// Pohyb ducha (mrtvý hráč) + /// + private void HandleGhostMovement() + { + float horizontal = Input.GetAxis("Horizontal"); + float vertical = Input.GetAxis("Vertical"); + + if (horizontal != 0 || vertical != 0) + { + Vector3 movement = new Vector3(horizontal, 0, vertical).normalized; + currentPlayerPosition += movement * moveSpeed * 1.5f * Time.deltaTime; // Duch je rychlejší + UpdateCameraPosition(); + } + } + + /// + /// Kontrola, zda je pozice v hrací oblasti + /// + private bool IsPositionInPlayArea(Vector3 position) + { + // Vzdálenost od středu + float distance = Vector3.Distance(position, Vector3.zero); + return distance <= (float)mapRadius; + } + + /// + /// Aktualizace pozice kamery podle hráče + /// + private void UpdateCameraPosition() + { + if (playerCamera == null) return; + + // Top-down kamera následuje hráče + Vector3 cameraPos = currentPlayerPosition; + cameraPos.y = cameraHeight; + playerCamera.transform.position = cameraPos; + + // Aktualizace lokálního hráče vizuálu + UpdateLocalPlayerVisual(); + } + + /// + /// Inicializace pozice hráče při startu hry + /// + protected void InitializePlayerPosition() + { + // Nastavíme hráče na střed mapy + currentPlayerPosition = Vector3.zero; + UpdateCameraPosition(); + Debug.Log("[GeoSus] Pozice hráče inicializována na střed mapy"); + } + + /// + /// Odeslání pozice hráče na server + /// + private void SendPositionToServer() + { + if (client == null || !client.IsConnected) return; + + // Převod na GPS + Position gpsPosition = UnityToGPS(currentPlayerPosition); + + // Odeslání + client.UpdatePosition(gpsPosition); + } + + #region ═══════════════════════════════════════════════════════════════════ + // INTERAKCE + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Provede primární akci (USE/REPORT/REPAIR) + /// + protected void PerformPrimaryAction() + { + if (client == null) return; + + // Kontrola stavu hráče - bezpečný přístup + if (client.PlayerPositions != null && client.PlayerPositions.TryGetValue(clientUuid, out var myState)) + { + if (myState.State != PlayerState.Alive) + { + ShowNotification("Jsi mrtvý!", Color.gray, 2f, "💀"); + return; + } + } + + // ═══════════════════════════════════════════════════════════════════ + // PRIORITA 1: Report těla + // ═══════════════════════════════════════════════════════════════════ + + var body = client.FindNearbyBody(5.0); + if (body != null) + { + // Použijeme přímo BodyId property + ReportBody(body.BodyId); + return; + } + + // ═══════════════════════════════════════════════════════════════════ + // PRIORITA 2: Oprava stanice + // ═══════════════════════════════════════════════════════════════════ + + if (currentSabotage != null) + { + var station = FindNearbyRepairStation(5.0); + if (station != null) + { + if (!isRepairing) + { + StartRepair(station.StationId); + } + return; + } + } + + // ═══════════════════════════════════════════════════════════════════ + // PRIORITA 3: Úkol (pouze crew) + // ═══════════════════════════════════════════════════════════════════ + + if (client.MyRole == PlayerRole.Crew) + { + var task = client.FindNearbyTask(5.0); + if (task != null) + { + TryCompleteTask(task); + return; + } + } + + ShowNotification("Nic v dosahu!", Color.yellow, "❓"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // ÚKOLY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Pokus o dokončení úkolu - pošle CompleteTask na server. + /// Server ověří pozici a označí jako dokončený. + /// + private void TryCompleteTask(object taskObj) + { + if (client == null) return; + + // Dynamicky získáme vlastnosti úkolu přes reflexi + var taskType = taskObj.GetType(); + string taskId = taskType.GetField("TaskId")?.GetValue(taskObj) as string ?? + taskType.GetProperty("TaskId")?.GetValue(taskObj) as string ?? "unknown"; + string taskName = taskType.GetField("Name")?.GetValue(taskObj) as string ?? + taskType.GetProperty("Name")?.GetValue(taskObj) as string ?? "Úkol"; + + // Pošleme CompleteTask na server + client.CompleteTask(taskId); + + ShowNotification($"Provádím: {taskName}...", Color.cyan, "📋"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // REPORT TĚLA + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Nahlášení těla + /// + /// ID těla + protected void ReportBody(string bodyId) + { + if (client == null) return; + + client.ReportBody(bodyId); + + ShowNotification("Tělo nahlášeno!", Color.red, "🚨"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // KILL + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Pokus o zabití blízkého hráče + /// + private void TryKillNearbyPlayer() + { + if (client?.MyRole != PlayerRole.Impostor) return; + + // Kontrola cooldownu + if (Time.time - lastKillTime < killCooldown) + { + float remaining = killCooldown - (Time.time - lastKillTime); + ShowNotification($"Cooldown: {remaining:F0}s", Color.yellow, "⏳"); + return; + } + + // Najdi blízkého hráče + string targetId = client.FindNearbyPlayer(5.0, true); + + if (targetId != null) + { + AttemptKill(targetId); + } + else + { + ShowNotification("Nikdo v dosahu!", Color.yellow, "🔪"); + } + } + + /// + /// Pokus o zabití konkrétního hráče + /// + /// UUID cíle + protected void AttemptKill(string targetId) + { + if (client == null) return; + + client.Kill(targetId); + lastKillTime = Time.time; + + string targetName = GetPlayerName(targetId); + ShowNotification($"Útočíš na {targetName}!", Color.red, "🔪"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // SABOTÁŽE + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Spuštění sabotáže + /// + /// Typ sabotáže + protected void StartSabotage(SabotageType type) + { + if (client?.MyRole != PlayerRole.Impostor) return; + if (currentSabotage != null) return; // Již běží sabotáž + + client.Send(new StartSabotage { SabotageType = type }); + + string sabName = type == SabotageType.CommsBlackout ? "Comms Blackout" : "Critical Meltdown"; + ShowNotification($"Sabotáž: {sabName}!", new Color(1f, 0.5f, 0f), "⚠"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // OPRAVY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Oprava stanice - INSTANT + /// Server opraví stanici okamžitě při přijetí ActivateRepairStation. + /// Budoucí pokročilý klient může simulovat progress bar a poslat request až po uplynutí času. + /// + /// ID opravné stanice + private void StartRepair(string stationId) + { + if (currentSabotage == null) return; + + // Pošleme serveru - ten opraví INSTANT + client.Send(new ActivateRepairStation { StationId = stationId }); + + ShowNotification("Stanice opravena!", Color.green, "✅"); + } + + /// + /// Aktualizace průběhu opravy - NEPOUŽÍVÁ SE (oprava je instant) + /// Ponecháno pro budoucí implementaci s progress barem. + /// + protected void UpdateRepairProgress() + { + // Oprava je nyní instant - tato metoda není potřeba + // Budoucí klient může implementovat lokální progress bar: + // if (!isRepairing) return; + // repairProgress += Time.deltaTime / 3f; // 3 sekundy + // if (repairProgress >= 1f) { + // client.Send(new ActivateRepairStation { StationId = activeRepairStation }); + // isRepairing = false; + // } + } + + /// + /// Ukončení opravy (úspěšné) - NEPOUŽÍVÁ SE (oprava je instant) + /// + private void StopRepair() + { + // Oprava je instant - tato metoda není potřeba + } + + /// + /// Zrušení opravy - NEPOUŽÍVÁ SE (oprava je instant) + /// + private void CancelRepair() + { + // Oprava je instant - tato metoda není potřeba + } + + #region ═══════════════════════════════════════════════════════════════════ + // EMERGENCY MEETING + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Svolání emergency meetingu + /// + protected void CallEmergencyMeeting() + { + if (client == null) return; + + // Kontrola sabotáže - nelze volat během comms blackout + if (currentSabotage?.Type == SabotageType.CommsBlackout) + { + ShowNotification("Komunikace odpojeny!", Color.red, "📡"); + return; + } + + client.CallEmergencyMeeting(); + + ShowNotification("Emergency Meeting!", Color.red, "🔔"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // HLASOVÁNÍ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Odeslání hlasu + /// + /// UUID hráče nebo null pro skip + protected void CastVote(string targetId) + { + if (client == null) + { + Debug.LogError("[GeoSus] CastVote: client je null!"); + return; + } + + if (!canVote) + { + Debug.LogWarning("[GeoSus] CastVote: canVote je false!"); + return; + } + + string voteText = targetId == null ? "SKIP" : GetPlayerName(targetId); + Debug.Log($"[GeoSus] Hlasování: {voteText} (targetId: {targetId ?? "null"})"); + + client.Vote(targetId); + myVote = targetId ?? "skip"; + canVote = false; + + ShowNotification($"Hlasoval jsi: {voteText}", Color.cyan, 2f, "🗳"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // POMOCNÉ METODY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Získání jména hráče podle UUID + /// + protected string GetPlayerName(string playerId) + { + if (client?.CurrentLobbyState?.Players == null) return playerId; + + foreach (var player in client.CurrentLobbyState.Players) + { + if (player.ClientUuid == playerId) + { + return player.DisplayName; + } + } + + return playerId.Substring(0, 8) + "..."; + } + + /// + /// Inicializace herního stavu při startu hry + /// + protected void InitializeGameState() + { + // Reset pozice na střed + currentPlayerPosition = Vector3.zero; + + // Reset úkolů + totalTasksCompleted = 0; + totalTasksRequired = client?.MyTasks?.Count ?? 0; + myCompletedTaskIds.Clear(); + + // Reset oprav + isRepairing = false; + activeRepairStation = null; + repairProgress = 0f; + + // Reset kill cooldownu + lastKillTime = Time.time; // Cooldown na začátku + + // Reset sabotáže + currentSabotage = null; + + // Reset meetingu + currentMeeting = null; + meetingVotes.Clear(); + myVote = null; + canVote = false; + + // Reset konce hry + gameEndData = null; + } + + /// + /// Game loop - aktualizace herní logiky. + /// Volá se v Update(). + /// + protected void UpdateGameLogic() + { + if (currentState != AppState.InGame) return; + + // Aktualizace opravy + UpdateRepairProgress(); + + // Aktualizace mapových objektů + UpdateMapObjects(); + } +} diff --git a/Assets/UnityTestClient/UnityTestClient_Game.cs.meta b/Assets/UnityTestClient/UnityTestClient_Game.cs.meta new file mode 100644 index 0000000..43156f8 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_Game.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 829e2eaa53b86d347912031dba7711da \ No newline at end of file diff --git a/Assets/UnityTestClient/UnityTestClient_Map.cs b/Assets/UnityTestClient/UnityTestClient_Map.cs new file mode 100644 index 0000000..eb9a663 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_Map.cs @@ -0,0 +1,1532 @@ +/* +╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ +║ ║ +║ VYKRESLOVÁNÍ MAPY - UnityTestClient_Map.cs ║ +║ ║ +║ Tento soubor obsahuje veškeré vykreslování 3D mapy pomocí GameObjectů: ║ +║ • Budovy (Buildings) - 3D kvádry s výškou ║ +║ • Cesty (Pathways) - LineRenderer nebo extrudované polygony ║ +║ • Oblasti (Areas) - Ploché 3D objekty (parky, voda) ║ +║ • POI (Points of Interest) - Markery s ikonami ║ +║ • Hráči - Capsule s barvou podle role/stavu ║ +║ • Těla - Ležící capsule (po zabití) ║ +║ • Úkoly - Žluté diamanty (markery) ║ +║ • Opravné stanice - Oranžové věže (při sabotáži) ║ +║ ║ +║ GPS → UNITY PŘEVOD: ║ +║ 1. Střed mapy (PlayAreaCenter) = Vector3(0, 0, 0) ║ +║ 2. 1 metr GPS ≈ 1 Unity jednotka ║ +║ 3. Latitude → Z osa (sever = +Z) ║ +║ 4. Longitude → X osa (východ = +X) ║ +║ 5. Haversine formula pro přesný výpočet vzdáleností ║ +║ ║ +║ VRSTVY (Y osa): ║ +║ 0.00 - Zelený podklad ║ +║ 0.01 - Oblasti (parky, voda) ║ +║ 0.02 - Cesty ║ +║ 0.XX - Budovy (výška podle dat) ║ +║ 0.30 - Markery (úkoly, těla) ║ +║ 0.50 - POI ║ +║ 1.00 - Hráči ║ +║ 5.00+ - Opravné stanice (věže) ║ +║ ║ +║ MAPOVÁ DATA: ║ +║ Server stahuje data z OpenStreetMap (Overpass API) a posílá je klientovi. ║ +║ Pokud Overpass API není dostupné, mapa se vykreslí bez detailů. ║ +║ ║ +╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ +*/ + +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using GeoSus.Client; + +public partial class UnityTestClient +{ + #region ═══════════════════════════════════════════════════════════════════ + // MAP PROMĚNNÉ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + // ───────────────────────────────────────────────────────────────────────── + // Kontejnery pro mapové objekty + // ───────────────────────────────────────────────────────────────────────── + + /// Rodičovský objekt pro celou mapu + protected GameObject mapContainer; + + /// Kontejner pro budovy + protected GameObject buildingsContainer; + + /// Kontejner pro cesty + protected GameObject pathwaysContainer; + + /// Kontejner pro oblasti + protected GameObject areasContainer; + + /// Kontejner pro POI + protected GameObject poisContainer; + + /// Kontejner pro hráče + protected GameObject playersContainer; + + /// Kontejner pro těla + protected GameObject bodiesContainer; + + /// Kontejner pro úkoly + protected GameObject tasksContainer; + + /// Kontejner pro opravné stanice + protected GameObject repairStationsContainer; + + /// Emergency button marker (střed mapy) + protected GameObject emergencyButtonMarker; + + /// Meeting lokace marker (během meetingu) + protected GameObject meetingLocationMarker; + + // ───────────────────────────────────────────────────────────────────────── + // Mapování objektů na ID + // ───────────────────────────────────────────────────────────────────────── + + /// Mapování ID hráče na GameObject + protected Dictionary playerObjects = new Dictionary(); + + /// Mapování ID těla na GameObject + protected Dictionary bodyObjects = new Dictionary(); + + /// Mapování ID úkolu na GameObject + protected Dictionary taskObjects = new Dictionary(); + + /// Mapování ID opravné stanice na GameObject + protected Dictionary repairStationObjects = new Dictionary(); + + // ───────────────────────────────────────────────────────────────────────── + // GPS referenční bod + // ───────────────────────────────────────────────────────────────────────── + + /// Střed herní oblasti (GPS) + protected Position? mapCenter; + + /// Poloměr herní oblasti (metry) + protected double mapRadius; + + // ───────────────────────────────────────────────────────────────────────── + // Materiály + // ───────────────────────────────────────────────────────────────────────── + + /// Materiál pro budovy + protected Material buildingMaterial; + + /// Materiál pro cesty + protected Material pathwayMaterial; + + /// Materiál pro oblasti + protected Material areaMaterial; + + /// Materiál pro POI + protected Material poiMaterial; + + /// Materiál pro hráče + protected Material playerMaterial; + + /// Materiál pro těla + protected Material bodyMaterial; + + /// Materiál pro úkoly + protected Material taskMaterial; + + /// Materiál pro opravné stanice + protected Material repairMaterial; + + #region ═══════════════════════════════════════════════════════════════════ + // INICIALIZACE MAPY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vytvoření kontejnerů a materiálů pro mapu. + /// Volá se při startu hry. + /// + protected void InitializeMapSystem() + { + // Vytvoření hlavního kontejneru + if (mapContainer == null) + { + mapContainer = new GameObject("MapContainer"); + } + + // Vytvoření sub-kontejnerů pro lepší organizaci + buildingsContainer = CreateContainer("Buildings"); + pathwaysContainer = CreateContainer("Pathways"); + areasContainer = CreateContainer("Areas"); + poisContainer = CreateContainer("POIs"); + playersContainer = CreateContainer("Players"); + bodiesContainer = CreateContainer("Bodies"); + tasksContainer = CreateContainer("Tasks"); + repairStationsContainer = CreateContainer("RepairStations"); + + // Inicializace materiálů + InitializeMaterials(); + + // Vytvoření podlahy herní oblasti + CreateGroundPlane(); + } + + /// + /// Pomocná metoda pro vytvoření kontejneru + /// + private GameObject CreateContainer(string name) + { + var container = new GameObject(name); + container.transform.SetParent(mapContainer.transform); + return container; + } + + /// + /// Inicializace materiálů pro různé typy objektů. + /// BUILD-SAFE: Všechny materiály jsou odvozeny z primitiv. + /// + private void InitializeMaterials() + { + // Budovy - různé barvy podle typu + buildingMaterial = CreateUnlitMaterial(new Color(0.7f, 0.65f, 0.6f)); // Světle šedá/béžová + + // Cesty - tmavší šedá + pathwayMaterial = CreateUnlitMaterial(new Color(0.5f, 0.5f, 0.5f)); + + // Oblasti (parky) - zelená s průhledností + areaMaterial = CreateTransparentMaterial(new Color(0.3f, 0.7f, 0.3f, 0.4f)); + + // POI - jasně žlutá + poiMaterial = CreateUnlitMaterial(Color.yellow); + + // Hráči - modrá + playerMaterial = CreateUnlitMaterial(new Color(0.2f, 0.5f, 1f)); + + // Těla - červená + bodyMaterial = CreateUnlitMaterial(new Color(0.8f, 0.2f, 0.2f)); + + // Úkoly - cyan/tyrkysová + taskMaterial = CreateUnlitMaterial(new Color(0f, 0.9f, 0.9f)); + + // Opravné stanice - oranžová + repairMaterial = CreateUnlitMaterial(new Color(1f, 0.6f, 0.1f)); + } + + /// + /// Vytvoří průhledný materiál + /// BUILD-SAFE: Používá materiál z primitivu jako základ + /// + private Material CreateTransparentMaterial(Color color) + { + var mat = CreateUnlitMaterial(color); + + // Nastavení průhlednosti + mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + mat.SetInt("_ZWrite", 0); + mat.renderQueue = 3000; + + // Pro URP + if (mat.HasProperty("_Surface")) + { + mat.SetFloat("_Surface", 1); // 1 = Transparent + } + + return mat; + } + + /// + /// Nastaví materiál jako průhledný + /// + private void SetMaterialTransparent(Material mat) + { + mat.SetFloat("_Mode", 3); // Transparent + mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + mat.SetInt("_ZWrite", 0); + mat.DisableKeyword("_ALPHATEST_ON"); + mat.EnableKeyword("_ALPHABLEND_ON"); + mat.DisableKeyword("_ALPHAPREMULTIPLY_ON"); + mat.renderQueue = 3000; + } + + /// + /// Nastaví materiál jako emisivní (svítící) + /// + private void SetMaterialEmissive(Material mat, Color emissionColor) + { + mat.EnableKeyword("_EMISSION"); + mat.SetColor("_EmissionColor", emissionColor); + } + + /// + /// Vytvoření podlahy herní oblasti + /// + private void CreateGroundPlane() + { + var ground = GameObject.CreatePrimitive(PrimitiveType.Plane); + ground.name = "Ground"; + ground.transform.SetParent(mapContainer.transform); + ground.transform.localPosition = Vector3.zero; + + // Škálování podle poloměru (Plane má základní velikost 10x10) + float scale = (float)mapRadius * 0.3f; // Mírně větší než poloměr + ground.transform.localScale = new Vector3(scale, 1, scale); + + // Materiál podlahy - použijeme Unlit shader pro konzistentní barvu + var groundMat = CreateUnlitMaterial(new Color(0.25f, 0.45f, 0.2f)); // Tráva + ground.GetComponent().material = groundMat; + + // Vytvoříme emergency button marker uprostřed mapy + CreateEmergencyButtonMarker(); + } + + /// + /// Vytvoří výrazný marker pro emergency button (střed mapy) + /// + private void CreateEmergencyButtonMarker() + { + emergencyButtonMarker = new GameObject("EmergencyButton"); + emergencyButtonMarker.transform.SetParent(mapContainer.transform); + emergencyButtonMarker.transform.localPosition = new Vector3(0, 0.1f, 0); // Střed mapy + + // Velký červený kruh na zemi + var platform = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + platform.name = "Platform"; + platform.transform.SetParent(emergencyButtonMarker.transform); + platform.transform.localPosition = Vector3.zero; + platform.transform.localScale = new Vector3(8f, 0.2f, 8f); + var platformMat = CreateEmissiveMaterial(new Color(0.8f, 0.2f, 0.2f), 1.5f); + platform.GetComponent().material = platformMat; + + // Tlačítko uprostřed + var button = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + button.name = "Button"; + button.transform.SetParent(emergencyButtonMarker.transform); + button.transform.localPosition = new Vector3(0, 0.5f, 0); + button.transform.localScale = new Vector3(3f, 0.5f, 3f); + var buttonMat = CreateEmissiveMaterial(Color.red, 3f); + button.GetComponent().material = buttonMat; + + // Světelná koule nahoře + var light = GameObject.CreatePrimitive(PrimitiveType.Sphere); + light.name = "Light"; + light.transform.SetParent(emergencyButtonMarker.transform); + light.transform.localPosition = new Vector3(0, 3f, 0); + light.transform.localScale = new Vector3(2f, 2f, 2f); + light.GetComponent().material = buttonMat; + } + + /// + /// Vytvoří nebo aktualizuje marker pro meeting lokaci + /// + protected void UpdateMeetingLocationMarker(Position? location, bool isActive) + { + if (!isActive || location == null) + { + if (meetingLocationMarker != null) + { + Destroy(meetingLocationMarker); + meetingLocationMarker = null; + } + return; + } + + if (meetingLocationMarker == null) + { + meetingLocationMarker = new GameObject("MeetingLocation"); + meetingLocationMarker.transform.SetParent(mapContainer.transform); + + // Velký pulsující kruh + var ring = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + ring.name = "Ring"; + ring.transform.SetParent(meetingLocationMarker.transform); + ring.transform.localPosition = new Vector3(0, 0.1f, 0); + ring.transform.localScale = new Vector3(15f, 0.1f, 15f); + var ringMat = CreateEmissiveMaterial(new Color(1f, 1f, 0f, 0.6f), 2f); + ring.GetComponent().material = ringMat; + + // Šipka dolů + var arrow = GameObject.CreatePrimitive(PrimitiveType.Cube); + arrow.name = "Arrow"; + arrow.transform.SetParent(meetingLocationMarker.transform); + arrow.transform.localPosition = new Vector3(0, 10f, 0); + arrow.transform.localScale = new Vector3(2f, 8f, 0.5f); + var arrowMat = CreateEmissiveMaterial(Color.yellow, 4f); + arrow.GetComponent().material = arrowMat; + } + + Vector3 pos = GPSToUnity(location.Value); + meetingLocationMarker.transform.position = pos; + } + + /// + /// Cache pro základní materiál - získaný z primitivu při prvním volání + /// + private static Material _cachedBaseMaterial = null; + + /// + /// Vytvoří materiál pro konzistentní barvu + /// BUILD-SAFE: Používá Sprites/Default shader který je vždy zahrnut + /// + private Material CreateUnlitMaterial(Color color) + { + // Sprites/Default shader je VŽDY zahrnut v Unity buildech + var shader = Shader.Find("Sprites/Default"); + if (shader == null) + { + // Absolutní fallback - nemělo by nikdy nastat + Debug.LogError("[GeoSus] Sprites/Default shader nenalezen!"); + var tempCube = GameObject.CreatePrimitive(PrimitiveType.Cube); + var mat = new Material(tempCube.GetComponent().sharedMaterial); + DestroyImmediate(tempCube); + mat.color = color; + return mat; + } + + var material = new Material(shader); + material.color = color; + + return material; + } + + #region ═══════════════════════════════════════════════════════════════════ + // GPS KONVERZE + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Konverze GPS souřadnic na Unity pozici. + /// Střed mapy je na (0, 0, 0). + /// + /// MATEMATIKA: + /// - Latitude (zeměpisná šířka) → Z osa + /// - Longitude (zeměpisná délka) → X osa + /// - Používáme Haversine formuli pro přesnou vzdálenost + /// + /// GPS souřadnice + /// Unity pozice ve 3D prostoru + protected Vector3 GPSToUnity(Position position) + { + if (!mapCenter.HasValue) return Vector3.zero; + + // Výpočet vzdálenosti a směru od středu + // Zjednodušená verze - pro malé vzdálenosti je dost přesná + + double latDiff = position.Lat - mapCenter.Value.Lat; + double lonDiff = position.Lon - mapCenter.Value.Lon; + + // Převod stupňů na metry + // 1 stupeň latitude ≈ 111320 metrů + // 1 stupeň longitude závisí na latitude: 111320 * cos(latitude) + double metersPerDegreeLat = 111320.0; + double metersPerDegreeLon = 111320.0 * Math.Cos(mapCenter.Value.Lat * Math.PI / 180.0); + + float x = (float)(lonDiff * metersPerDegreeLon); + float z = (float)(latDiff * metersPerDegreeLat); + + return new Vector3(x, 0, z); + } + + /// + /// Konverze Unity pozice zpět na GPS souřadnice. + /// Inverzní funkce k GPSToUnity. + /// + /// Unity pozice + /// GPS souřadnice + protected Position UnityToGPS(Vector3 unityPos) + { + if (!mapCenter.HasValue) return new Position(0, 0); + + double metersPerDegreeLat = 111320.0; + double metersPerDegreeLon = 111320.0 * Math.Cos(mapCenter.Value.Lat * Math.PI / 180.0); + + double latDiff = unityPos.z / metersPerDegreeLat; + double lonDiff = unityPos.x / metersPerDegreeLon; + + return new Position(mapCenter.Value.Lat + latDiff, mapCenter.Value.Lon + lonDiff); + } + + #region ═══════════════════════════════════════════════════════════════════ + // BUDOVY (BUILDINGS) + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Získá barvu budovy podle typu + /// + private Color GetBuildingColor(string buildingType) + { + if (string.IsNullOrEmpty(buildingType)) return new Color(0.7f, 0.65f, 0.6f); + + switch (buildingType.ToLower()) + { + case "residential": + case "apartments": + case "house": + return new Color(0.85f, 0.75f, 0.65f); // Teplá béžová + case "commercial": + case "retail": + case "shop": + return new Color(0.7f, 0.7f, 0.85f); // Světle modrá + case "industrial": + case "warehouse": + return new Color(0.6f, 0.55f, 0.5f); // Tmavě šedá + case "school": + case "university": + return new Color(0.9f, 0.85f, 0.7f); // Světle žlutá + case "hospital": + case "clinic": + return new Color(0.9f, 0.9f, 0.95f); // Bílá + case "church": + case "cathedral": + return new Color(0.8f, 0.75f, 0.85f); // Světle fialová + case "garage": + case "garages": + return new Color(0.5f, 0.5f, 0.5f); // Šedá + default: + return new Color(0.75f, 0.7f, 0.65f); // Výchozí béžová + } + } + + /// + /// Vytvoření budovy z mapových dat. + /// Budova je vykreslena jako 3D kvádr s výškou. + /// + /// Data budovy z mapy + protected void CreateBuildingObject(MapBuilding building) + { + // Vytvoření GameObjectu + var buildingObj = new GameObject($"Building_{building.Name ?? "Unknown"}"); + buildingObj.transform.SetParent(buildingsContainer.transform); + + // Výpočet středu budovy + Vector3 center = CalculatePolygonCenter(building.Outline); + buildingObj.transform.position = center; + + // Vytvoření mesh pro budovu + MeshFilter meshFilter = buildingObj.AddComponent(); + MeshRenderer meshRenderer = buildingObj.AddComponent(); + + // Generování mesh z polygonu (výška implicitně 10m) + Mesh mesh = CreateExtrudedPolygonMesh(building.Outline, 10f); + meshFilter.mesh = mesh; + + // Použijeme barvu podle typu budovy + Color buildingColor = GetBuildingColor(building.BuildingType); + meshRenderer.material = CreateUnlitMaterial(buildingColor); + + // Přidání collideru pro interakci + buildingObj.AddComponent(); + } + + /// + /// Výpočet středu polygonu + /// + private Vector3 CalculatePolygonCenter(List points) + { + Vector3 center = Vector3.zero; + foreach (var point in points) + { + center += GPSToUnity(point); + } + return center / points.Count; + } + + /// + /// Vytvoření 3D mesh z polygonu vytažením do výšky. + /// + /// ALGORITMUS: + /// 1. Triangulace spodní podstavy (ear clipping) + /// 2. Kopie vrcholů nahoru pro horní podstavu + /// 3. Vytvoření bočních stěn spojením okrajů + /// + private Mesh CreateExtrudedPolygonMesh(List outline, float height) + { + Mesh mesh = new Mesh(); + + int vertexCount = outline.Count; + + // Vertices - spodní a horní podstava + Vector3[] vertices = new Vector3[vertexCount * 2]; + Vector3 center = CalculatePolygonCenter(outline); + + for (int i = 0; i < vertexCount; i++) + { + Vector3 pos = GPSToUnity(outline[i]) - center; + vertices[i] = pos; // Spodní + vertices[i + vertexCount] = pos + Vector3.up * height; // Horní + } + + // Triangles - jen boční stěny pro jednoduchost + List triangles = new List(); + + for (int i = 0; i < vertexCount; i++) + { + int next = (i + 1) % vertexCount; + + // Boční stěna - dva trojúhelníky + triangles.Add(i); + triangles.Add(i + vertexCount); + triangles.Add(next); + + triangles.Add(next); + triangles.Add(i + vertexCount); + triangles.Add(next + vertexCount); + } + + // Horní podstava - zjednodušená triangulace (fan) + if (vertexCount >= 3) + { + for (int i = 1; i < vertexCount - 1; i++) + { + triangles.Add(vertexCount); // Střed (první bod horní) + triangles.Add(vertexCount + i); + triangles.Add(vertexCount + i + 1); + } + } + + mesh.vertices = vertices; + mesh.triangles = triangles.ToArray(); + mesh.RecalculateNormals(); + mesh.RecalculateBounds(); + + return mesh; + } + + #region ═══════════════════════════════════════════════════════════════════ + // CESTY (PATHWAYS) + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vytvoření cesty z mapových dat. + /// Cesta je vykreslena jako LineRenderer nebo plochý polygon. + /// + /// Data cesty + protected void CreatePathwayObject(MapPathway pathway) + { + var pathObj = new GameObject($"Path_{pathway.Name ?? "Unknown"}"); + pathObj.transform.SetParent(pathwaysContainer.transform); + + // Použijeme LineRenderer pro jednoduchost + LineRenderer line = pathObj.AddComponent(); + line.material = pathwayMaterial; + line.widthMultiplier = GetPathWidth(pathway.PathType); + + // Nastavení bodů cesty + line.positionCount = pathway.Points.Count; + for (int i = 0; i < pathway.Points.Count; i++) + { + Vector3 pos = GPSToUnity(pathway.Points[i]); + pos.y = 0.1f; // Mírně nad zemí + line.SetPosition(i, pos); + } + } + + /// + /// Získání šířky cesty podle typu + /// + private float GetPathWidth(PathType type) + { + switch (type) + { + case PathType.Road: return 5f; + case PathType.Pedestrian: return 2f; // Sidewalk + case PathType.Path: return 1f; // Trail + case PathType.Footway: return 1.5f; + default: return 2f; + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // OBLASTI (AREAS) + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vytvoření oblasti z mapových dat. + /// Oblast je vykreslena jako plochý 3D polygon. + /// + /// Data oblasti + protected void CreateAreaObject(MapArea area) + { + var areaObj = new GameObject($"Area_{area.Name ?? "Unknown"}"); + areaObj.transform.SetParent(areasContainer.transform); + + MeshFilter meshFilter = areaObj.AddComponent(); + MeshRenderer meshRenderer = areaObj.AddComponent(); + + // Vytvoření plochého mesh + Mesh mesh = CreateFlatPolygonMesh(area.Outline); + meshFilter.mesh = mesh; + + // Materiál podle typu + Material mat = new Material(areaMaterial); + mat.color = GetAreaColor(area.AreaType); + meshRenderer.material = mat; + + areaObj.transform.position = new Vector3(0, 0.05f, 0); // Těsně nad zemí + } + + /// + /// Vytvoření plochého mesh z polygonu + /// + private Mesh CreateFlatPolygonMesh(List outline) + { + Mesh mesh = new Mesh(); + + int vertexCount = outline.Count; + Vector3[] vertices = new Vector3[vertexCount]; + Vector3 center = CalculatePolygonCenter(outline); + + for (int i = 0; i < vertexCount; i++) + { + vertices[i] = GPSToUnity(outline[i]) - center; + } + + // Triangulace - fan pattern + List triangles = new List(); + if (vertexCount >= 3) + { + for (int i = 1; i < vertexCount - 1; i++) + { + triangles.Add(0); + triangles.Add(i); + triangles.Add(i + 1); + } + } + + mesh.vertices = vertices; + mesh.triangles = triangles.ToArray(); + mesh.RecalculateNormals(); + + return mesh; + } + + /// + /// Získání barvy oblasti podle typu + /// + private Color GetAreaColor(MapAreaType type) + { + switch (type) + { + case MapAreaType.Park: return new Color(0.2f, 0.8f, 0.2f, 0.5f); + case MapAreaType.Garden: return new Color(0.3f, 0.7f, 0.3f, 0.5f); + case MapAreaType.Water: return new Color(0.2f, 0.5f, 0.9f, 0.7f); + case MapAreaType.Forest: return new Color(0.1f, 0.5f, 0.1f, 0.5f); + case MapAreaType.Grass: return new Color(0.4f, 0.8f, 0.4f, 0.5f); + case MapAreaType.Playground: return new Color(0.6f, 0.5f, 0.4f, 0.5f); + default: return new Color(0.5f, 0.5f, 0.5f, 0.5f); + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // POI (POINTS OF INTEREST) + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vytvoření POI markeru - VÝRAZNÝ marker s ikonou a popisem. + /// POI jsou body zájmu pro orientaci na mapě. + /// + /// Data POI + protected void CreatePOIObject(MapPOI poi) + { + var poiObj = new GameObject($"POI_{poi.Name ?? "Unknown"}"); + poiObj.transform.SetParent(poisContainer.transform); + + Vector3 pos = GPSToUnity(poi.Location); + pos.y = 0.5f; + poiObj.transform.position = pos; + + // Vytvoření vizuálu - větší a viditelnější + var visual = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + visual.transform.SetParent(poiObj.transform); + visual.transform.localPosition = new Vector3(0, 0.5f, 0); + visual.transform.localScale = new Vector3(1.2f, 0.5f, 1.2f); + + // Barva podle typu - svítící materiál + Color poiColor = GetPOIColor(poi.POIType); + Material mat = CreateEmissiveMaterial(poiColor, 1.5f); + visual.GetComponent().material = mat; + + // Ikona/symbol nahoře - malá koule + var icon = GameObject.CreatePrimitive(PrimitiveType.Sphere); + icon.transform.SetParent(poiObj.transform); + icon.transform.localPosition = new Vector3(0, 1.3f, 0); + icon.transform.localScale = new Vector3(0.8f, 0.8f, 0.8f); + icon.GetComponent().material = mat; + } + + /// + /// Získání barvy POI podle typu + /// + private Color GetPOIColor(MapPOIType type) + { + switch (type) + { + case MapPOIType.Shop: return Color.magenta; + case MapPOIType.FoodDrink: return new Color(1f, 0.5f, 0f); + case MapPOIType.Transport: return Color.blue; + case MapPOIType.Landmark: return Color.yellow; + case MapPOIType.Health: return Color.green; + case MapPOIType.Culture: return Color.cyan; + case MapPOIType.Recreation: return new Color(0.5f, 1f, 0.5f); + default: return Color.white; + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // HRÁČI + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Barvy pro hráče - každý hráč má unikátní barvu + /// + private static readonly Color[] PlayerColors = new Color[] + { + Color.red, + Color.blue, + Color.green, + Color.yellow, + Color.cyan, + Color.magenta, + new Color(1f, 0.5f, 0f), // Orange + new Color(0.5f, 0f, 1f), // Purple + new Color(0f, 1f, 0.5f), // Mint + new Color(1f, 0.75f, 0.8f), // Pink + }; + + /// + /// Vytvoření nebo aktualizace objektu hráče - VÝRAZNÝ marker. + /// Hráč je vykreslován jako Capsule s barvou a jménem. + /// + /// UUID hráče + /// GPS pozice + /// Stav hráče + protected void UpdatePlayerObject(string playerId, Position position, PlayerState state) + { + // Skip pro lokálního hráče - ten je vykreslen jinak + if (playerId == clientUuid) return; + + GameObject playerObj; + + if (!playerObjects.TryGetValue(playerId, out playerObj)) + { + // Kontejner pro hráče + playerObj = new GameObject($"Player_{GetPlayerName(playerId)}"); + playerObj.transform.SetParent(playersContainer.transform); + + // Tělo hráče - větší capsule + var body = GameObject.CreatePrimitive(PrimitiveType.Capsule); + body.name = "Body"; + body.transform.SetParent(playerObj.transform); + body.transform.localPosition = new Vector3(0, 2f, 0); + body.transform.localScale = new Vector3(2f, 2.5f, 2f); + + // Přidělení výrazné barvy + int colorIndex = playerObjects.Count % PlayerColors.Length; + var mat = CreateEmissiveMaterial(PlayerColors[colorIndex], 0.5f); + body.GetComponent().material = mat; + + // Kroužek pod hráčem + var ring = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + ring.name = "Ring"; + ring.transform.SetParent(playerObj.transform); + ring.transform.localPosition = new Vector3(0, 0.1f, 0); + ring.transform.localScale = new Vector3(4f, 0.1f, 4f); + var ringMat = CreateEmissiveMaterial(PlayerColors[colorIndex] * 0.7f, 0.3f); + ring.GetComponent().material = ringMat; + + playerObjects[playerId] = playerObj; + } + + // Aktualizace pozice + Vector3 unityPos = GPSToUnity(position); + playerObj.transform.position = unityPos; + + // Viditelnost podle stavu + playerObj.SetActive(state == PlayerState.Alive); + } + + /// + /// Aktualizace lokálního hráče (kurzor/avatar) - VELMI VÝRAZNÝ + /// + protected void UpdateLocalPlayerVisual() + { + // Vytvoření lokálního hráče pokud neexistuje + if (localPlayerObject == null) + { + // Hlavní objekt hráče + localPlayerObject = new GameObject("LocalPlayer"); + localPlayerObject.transform.SetParent(playersContainer.transform); + + // Tělo hráče - VELKÁ jasně zelená capsule + var body = GameObject.CreatePrimitive(PrimitiveType.Capsule); + body.name = "Body"; + body.transform.SetParent(localPlayerObject.transform); + body.transform.localPosition = new Vector3(0, 2.5f, 0); + body.transform.localScale = new Vector3(3f, 3f, 3f); + + // Výrazná zelená barva se svícením + var bodyMat = CreateEmissiveMaterial(new Color(0.3f, 1f, 0.3f), 1.5f); + body.GetComponent().material = bodyMat; + + // VELKÝ indikátor - kroužek kolem hráče + var indicator = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + indicator.name = "Indicator"; + indicator.transform.SetParent(localPlayerObject.transform); + indicator.transform.localPosition = new Vector3(0, 0.15f, 0); + indicator.transform.localScale = new Vector3(8f, 0.15f, 8f); + + // Žlutý svítící kroužek + var indicatorMat = CreateEmissiveMaterial(new Color(1f, 1f, 0f), 2f); + indicator.GetComponent().material = indicatorMat; + + // Šipka směru + var arrow = GameObject.CreatePrimitive(PrimitiveType.Cube); + arrow.name = "Arrow"; + arrow.transform.SetParent(localPlayerObject.transform); + arrow.transform.localPosition = new Vector3(0, 0.3f, 3f); + arrow.transform.localScale = new Vector3(1.5f, 0.3f, 3f); + arrow.GetComponent().material = bodyMat; + + // Druhý vnější ring pro ještě lepší viditelnost + var outerRing = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + outerRing.name = "OuterRing"; + outerRing.transform.SetParent(localPlayerObject.transform); + outerRing.transform.localPosition = new Vector3(0, 0.1f, 0); + outerRing.transform.localScale = new Vector3(12f, 0.1f, 12f); + var outerMat = CreateEmissiveMaterial(new Color(0.5f, 1f, 0.5f, 0.3f), 0.5f); + outerRing.GetComponent().material = outerMat; + } + + // Pozice podle currentPlayerPosition (ne kamery!) + localPlayerObject.transform.position = new Vector3( + currentPlayerPosition.x, + 0, + currentPlayerPosition.z + ); + } + + /// Objekt lokálního hráče + protected GameObject localPlayerObject; + + #region ═══════════════════════════════════════════════════════════════════ + // TĚLA (BODIES) + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vytvoření objektu těla mrtvého hráče. + /// Tělo je vykresleno jako ležící capsule. + /// + /// ID těla + /// GPS pozice + /// Jméno oběti + protected void CreateBodyObject(string bodyId, Position position, string victimName) + { + if (bodyObjects.ContainsKey(bodyId)) return; + + // Kontejner pro tělo + var container = new GameObject($"Body_{victimName}"); + container.transform.SetParent(bodiesContainer.transform); + + Vector3 unityPos = GPSToUnity(position); + container.transform.position = unityPos; + + // Ležící tělo + var bodyObj = GameObject.CreatePrimitive(PrimitiveType.Capsule); + bodyObj.name = "Corpse"; + bodyObj.transform.SetParent(container.transform); + bodyObj.transform.localPosition = new Vector3(0, 0.3f, 0); + bodyObj.transform.rotation = Quaternion.Euler(90, 0, 0); + bodyObj.transform.localScale = new Vector3(1.5f, 2f, 1.5f); + + // Výrazná červená barva se svícením + var bodyMat = CreateEmissiveMaterial(new Color(1f, 0.2f, 0.2f), 1.5f); + bodyObj.GetComponent().material = bodyMat; + + // Výstražný kroužek + var ring = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + ring.name = "WarningRing"; + ring.transform.SetParent(container.transform); + ring.transform.localPosition = new Vector3(0, 0.1f, 0); + ring.transform.localScale = new Vector3(6f, 0.1f, 6f); + var ringMat = CreateEmissiveMaterial(new Color(1f, 0f, 0f, 0.6f), 2f); + ring.GetComponent().material = ringMat; + + // Výstražná značka nahoře + var warning = GameObject.CreatePrimitive(PrimitiveType.Cube); + warning.name = "Warning"; + warning.transform.SetParent(container.transform); + warning.transform.localPosition = new Vector3(0, 4f, 0); + warning.transform.localScale = new Vector3(2f, 2f, 0.3f); + warning.GetComponent().material = bodyMat; + + bodyObjects[bodyId] = container; + } + + /// + /// Odstranění objektu těla (po reportu) + /// + protected void RemoveBodyObject(string bodyId) + { + if (bodyObjects.TryGetValue(bodyId, out var bodyObj)) + { + Destroy(bodyObj); + bodyObjects.Remove(bodyId); + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // ÚKOLY (TASKS) + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vytvoření markerů úkolů pro hráče. + /// Úkoly jsou vykresleny jako svítící válce. + /// + protected void CreateTaskMarkers() + { + if (client?.MyTasks == null) return; + + foreach (var task in client.MyTasks) + { + CreateTaskObject(task); + } + } + + /// + /// Vytvoření markeru úkolu - VÝRAZNÝ marker s popiskem + /// + private void CreateTaskObject(object taskObj) + { + // Dynamický přístup k vlastnostem + var taskType = taskObj.GetType(); + string taskId = taskType.GetField("TaskId")?.GetValue(taskObj) as string ?? + taskType.GetProperty("TaskId")?.GetValue(taskObj) as string ?? + taskType.GetField("Id")?.GetValue(taskObj) as string ?? + taskType.GetProperty("Id")?.GetValue(taskObj) as string ?? System.Guid.NewGuid().ToString(); + string taskName = taskType.GetField("Name")?.GetValue(taskObj) as string ?? + taskType.GetProperty("Name")?.GetValue(taskObj) as string ?? "Task"; + + // Získání lokace + object locationObj = taskType.GetField("Location")?.GetValue(taskObj) ?? + taskType.GetProperty("Location")?.GetValue(taskObj); + Position location = locationObj is Position pos ? pos : new Position(0, 0); + + if (taskObjects.ContainsKey(taskId)) return; + + // Kontejner pro task marker + var container = new GameObject($"Task_{taskName}"); + container.transform.SetParent(tasksContainer.transform); + + Vector3 unityPos = GPSToUnity(location); + container.transform.position = unityPos; + + // Hlavní marker - VĚTŠÍ svítící válec + var marker = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + marker.name = "Marker"; + marker.transform.SetParent(container.transform); + marker.transform.localPosition = new Vector3(0, 2f, 0); + marker.transform.localScale = new Vector3(4f, 2f, 4f); + + // Výrazný svítící cyan materiál + var mat = CreateEmissiveMaterial(new Color(0f, 1f, 1f), 2f); + marker.GetComponent().material = mat; + + // Vrchní kužel jako "šipka dolů" + var cone = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + cone.name = "Cone"; + cone.transform.SetParent(container.transform); + cone.transform.localPosition = new Vector3(0, 5f, 0); + cone.transform.localScale = new Vector3(2f, 1f, 2f); + cone.GetComponent().material = mat; + + // Pulsující ring na zemi + var ring = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + ring.name = "Ring"; + ring.transform.SetParent(container.transform); + ring.transform.localPosition = new Vector3(0, 0.1f, 0); + ring.transform.localScale = new Vector3(8f, 0.1f, 8f); + var ringMat = CreateEmissiveMaterial(new Color(0f, 0.8f, 0.8f, 0.5f), 1f); + ring.GetComponent().material = ringMat; + + taskObjects[taskId] = container; + } + + /// + /// Vytvoří svítící materiál + /// BUILD-SAFE: Používá Sprites/Default - emise simulována jasnou barvou + /// + private Material CreateEmissiveMaterial(Color color, float intensity = 1f) + { + // Simulujeme emisi zjasnením barvy + Color brightColor = new Color( + Mathf.Min(1f, color.r * (1f + intensity * 0.5f)), + Mathf.Min(1f, color.g * (1f + intensity * 0.5f)), + Mathf.Min(1f, color.b * (1f + intensity * 0.5f)), + color.a + ); + + return CreateUnlitMaterial(brightColor); + } + + /// + /// Aktualizace stavu úkolu (dokončen = skryje marker) + /// + protected void UpdateTaskMarker(string taskId, bool completed) + { + if (taskObjects.TryGetValue(taskId, out var taskObj)) + { + if (completed) + { + // Skryjeme celý marker + taskObj.SetActive(false); + } + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // OPRAVNÉ STANICE + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vytvoření markerů opravných stanic. + /// Zobrazují se pouze při aktivní sabotáži. + /// + protected void CreateRepairStationMarkers() + { + if (currentSabotage?.RepairStations == null) return; + + foreach (var station in currentSabotage.RepairStations) + { + CreateRepairStationObject(station.StationId, station.Name, station.Location); + } + } + + /// + /// Vytvoření markeru opravné stanice - VELMI VÝRAZNÝ marker + /// + private void CreateRepairStationObject(string stationId, string stationName, Position stationPos) + { + if (string.IsNullOrEmpty(stationId)) stationId = System.Guid.NewGuid().ToString(); + if (string.IsNullOrEmpty(stationName)) stationName = "Repair"; + + if (repairStationObjects.ContainsKey(stationId)) return; + + Debug.Log($"[GeoSus] Creating repair station marker: {stationId} '{stationName}' @ {stationPos.Lat:F6}, {stationPos.Lon:F6}"); + + // Kontejner pro opravnou stanici + var container = new GameObject($"Repair_{stationName}"); + container.transform.SetParent(repairStationsContainer.transform); + + Vector3 unityPos = GPSToUnity(stationPos); + container.transform.position = unityPos; + + // VELKÝ hlavní marker - věž + var tower = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + tower.name = "Tower"; + tower.transform.SetParent(container.transform); + tower.transform.localPosition = new Vector3(0, 5f, 0); + tower.transform.localScale = new Vector3(3f, 5f, 3f); + + // Výrazná oranžová/žlutá barva + var towerMat = CreateEmissiveMaterial(new Color(1f, 0.6f, 0f), 3f); + tower.GetComponent().material = towerMat; + + // Výstražná koule nahoře + var beacon = GameObject.CreatePrimitive(PrimitiveType.Sphere); + beacon.name = "Beacon"; + beacon.transform.SetParent(container.transform); + beacon.transform.localPosition = new Vector3(0, 11f, 0); + beacon.transform.localScale = new Vector3(4f, 4f, 4f); + var beaconMat = CreateEmissiveMaterial(new Color(1f, 0.8f, 0f), 5f); + beacon.GetComponent().material = beaconMat; + + // Velký kroužek na zemi - blikající + var ring = GameObject.CreatePrimitive(PrimitiveType.Cylinder); + ring.name = "Ring"; + ring.transform.SetParent(container.transform); + ring.transform.localPosition = new Vector3(0, 0.15f, 0); + ring.transform.localScale = new Vector3(12f, 0.15f, 12f); + var ringMat = CreateEmissiveMaterial(new Color(1f, 0.5f, 0f, 0.6f), 2f); + ring.GetComponent().material = ringMat; + + // Druhá výstražná značka - šipka dolů + var arrow1 = GameObject.CreatePrimitive(PrimitiveType.Cube); + arrow1.name = "Arrow1"; + arrow1.transform.SetParent(container.transform); + arrow1.transform.localPosition = new Vector3(0, 15f, 0); + arrow1.transform.localScale = new Vector3(2f, 4f, 0.5f); + arrow1.GetComponent().material = beaconMat; + + repairStationObjects[stationId] = container; + } + + /// + /// Aktualizace stavu opravné stanice + /// + protected void UpdateRepairStationMarker(string stationId, bool active) + { + if (repairStationObjects.TryGetValue(stationId, out var stationObj)) + { + // Najdeme Beacon (kouli nahoře) pro blikání + var beacon = stationObj.transform.Find("Beacon"); + var ring = stationObj.transform.Find("Ring"); + + if (beacon != null) + { + var renderer = beacon.GetComponent(); + if (renderer != null) + { + float pulse = active ? Mathf.Abs(Mathf.Sin(Time.time * 8f)) : 0.5f; + Color emissionColor = new Color(1f, 0.8f, 0f) * (1f + pulse * 3f); + renderer.material.color = emissionColor; + } + } + + if (ring != null) + { + var renderer = ring.GetComponent(); + if (renderer != null) + { + float pulse = Mathf.Abs(Mathf.Sin(Time.time * 3f)); + Color ringColor = active ? new Color(1f, 1f, 0f, 0.6f + pulse * 0.4f) : new Color(1f, 0.5f, 0f, 0.4f); + renderer.material.color = ringColor; + } + } + } + } + + /// + /// Odstranění všech opravných stanic (po opravě sabotáže) + /// + protected void ClearRepairStationMarkers() + { + foreach (var kvp in repairStationObjects) + { + Destroy(kvp.Value); + } + repairStationObjects.Clear(); + } + + #region ═══════════════════════════════════════════════════════════════════ + // NAČTENÍ MAPY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Zpracování přijatých mapových dat. + /// Vytvoří všechny 3D objekty mapy. + /// + /// POZNÁMKA: MapDataPayload používá kompaktní formát: + /// - Buildings: List kde každý double[] je [lat1,lon1,lat2,lon2,...] + /// - Pathways: List podobně + /// - Areas: List podobně + /// - POIs: List ve formátu [lat,lon,type,lat,lon,type,...] + /// + /// Data z Overpass API + protected void ProcessMapData(MapDataPayload mapData) + { + if (mapData == null) return; + + // Uložení referenčních bodů + mapCenter = mapData.Center; + mapRadius = mapData.RadiusMeters; + + // Inicializace systému + InitializeMapSystem(); + + // Vytvoření budov z kompaktního formátu + if (mapData.Buildings != null) + { + loadingMessage = "Vytvářím budovy..."; + for (int i = 0; i < mapData.Buildings.Count; i++) + { + var coords = mapData.Buildings[i]; + string buildingType = (mapData.BuildingTypes != null && i < mapData.BuildingTypes.Count) + ? mapData.BuildingTypes[i] : null; + CreateBuildingFromCoords(coords, buildingType, i); + } + } + + // Vytvoření cest z kompaktního formátu + if (mapData.Pathways != null) + { + loadingMessage = "Vytvářím cesty..."; + for (int i = 0; i < mapData.Pathways.Count; i++) + { + var coords = mapData.Pathways[i]; + PathType pathType = (mapData.PathwayTypes != null && i < mapData.PathwayTypes.Count) + ? (PathType)mapData.PathwayTypes[i] : PathType.Footway; + CreatePathwayFromCoords(coords, pathType, i); + } + } + + // Vytvoření oblastí z kompaktního formátu + if (mapData.Areas != null) + { + loadingMessage = "Vytvářím oblasti..."; + for (int i = 0; i < mapData.Areas.Count; i++) + { + var coords = mapData.Areas[i]; + MapAreaType areaType = (mapData.AreaTypes != null && i < mapData.AreaTypes.Count) + ? (MapAreaType)mapData.AreaTypes[i] : MapAreaType.Other; + CreateAreaFromCoords(coords, areaType, i); + } + } + + // Vytvoření POI z kompaktního formátu [lat,lon,type,lat,lon,type,...] + if (mapData.POIs != null && mapData.POIs.Count >= 3) + { + loadingMessage = "Vytvářím body zájmu..."; + for (int i = 0; i + 2 < mapData.POIs.Count; i += 3) + { + double lat = mapData.POIs[i]; + double lon = mapData.POIs[i + 1]; + int typeIndex = (int)mapData.POIs[i + 2]; + MapPOIType poiType = (MapPOIType)typeIndex; + CreatePOIFromCoords(lat, lon, poiType, i / 3); + } + } + + loadingProgress = 1f; + loadingMessage = "Mapa připravena!"; + } + + /// + /// Vytvoření budovy z kompaktních souřadnic + /// + private void CreateBuildingFromCoords(double[] coords, string buildingType, int index) + { + if (coords == null || coords.Length < 6) return; // Potřeba alespoň 3 body + + // Převod na List + List outline = new List(); + for (int i = 0; i + 1 < coords.Length; i += 2) + { + outline.Add(new Position(coords[i], coords[i + 1])); + } + + // Vytvoření MapBuilding objektu + var building = new MapBuilding + { + Id = index, + Outline = outline, + Name = buildingType ?? "Building", + BuildingType = buildingType + }; + + CreateBuildingObject(building); + } + + /// + /// Vytvoření cesty z kompaktních souřadnic + /// + private void CreatePathwayFromCoords(double[] coords, PathType pathType, int index) + { + if (coords == null || coords.Length < 4) return; // Potřeba alespoň 2 body + + // Převod na List + List points = new List(); + for (int i = 0; i + 1 < coords.Length; i += 2) + { + points.Add(new Position(coords[i], coords[i + 1])); + } + + // Vytvoření MapPathway objektu + var pathway = new MapPathway + { + Id = index, + Points = points, + PathType = pathType, + Name = pathType.ToString() + }; + + CreatePathwayObject(pathway); + } + + /// + /// Vytvoření oblasti z kompaktních souřadnic + /// + private void CreateAreaFromCoords(double[] coords, MapAreaType areaType, int index) + { + if (coords == null || coords.Length < 6) return; // Potřeba alespoň 3 body + + // Převod na List + List outline = new List(); + for (int i = 0; i + 1 < coords.Length; i += 2) + { + outline.Add(new Position(coords[i], coords[i + 1])); + } + + // Vytvoření MapArea objektu + var area = new MapArea + { + Id = index, + Outline = outline, + AreaType = areaType, + Name = areaType.ToString() + }; + + CreateAreaObject(area); + } + + /// + /// Vytvoření POI z souřadnic + /// + private void CreatePOIFromCoords(double lat, double lon, MapPOIType poiType, int index) + { + var poi = new MapPOI + { + Id = index, + Location = new Position(lat, lon), + POIType = poiType, + Name = poiType.ToString() + }; + + CreatePOIObject(poi); + } + + #region ═══════════════════════════════════════════════════════════════════ + // ÚKLID + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vyčištění všech mapových objektů. + /// Volá se při ukončení hry nebo odpojení. + /// + protected void CleanupMapObjects() + { + // Zničení hlavního kontejneru zničí všechny potomky + if (mapContainer != null) + { + Destroy(mapContainer); + mapContainer = null; + } + + // Vyčištění slovníků + playerObjects.Clear(); + bodyObjects.Clear(); + taskObjects.Clear(); + repairStationObjects.Clear(); + + // Zničení lokálního hráče + if (localPlayerObject != null) + { + Destroy(localPlayerObject); + localPlayerObject = null; + } + } + + /// + /// Aktualizace všech dynamických objektů na mapě. + /// Volá se každý frame v Update(). + /// + protected void UpdateMapObjects() + { + if (client == null || currentState != AppState.InGame) return; + + // Aktualizace pozic hráčů - bezpečně kopírujeme klíče + if (client.PlayerPositions != null) + { + try + { + // Použijeme ToArray() místo new List() - je rychlejší a bezpečnější + var playerIds = client.PlayerPositions.Keys.ToArray(); + foreach (var playerId in playerIds) + { + if (client.PlayerPositions.TryGetValue(playerId, out var playerInfo)) + { + UpdatePlayerObject(playerId, playerInfo.Position, playerInfo.State); + } + } + } + catch (System.InvalidOperationException) + { + // Dictionary byl změněn během iterace - přeskočíme tento frame + } + } + + // Aktualizace lokálního hráče + UpdateLocalPlayerVisual(); + + // Aktualizace opravných stanic (blikání) - bezpečně kopírujeme klíče + if (currentSabotage != null) + { + try + { + var stationIds = repairStationObjects.Keys.ToArray(); + foreach (var stationId in stationIds) + { + bool isActive = activeRepairStation == stationId; + UpdateRepairStationMarker(stationId, isActive); + } + } + catch (System.InvalidOperationException) + { + // Dictionary byl změněn během iterace - přeskočíme tento frame + } + } + + // Aktualizace meeting location markeru + bool hasMeeting = currentMeeting != null && client?.CurrentLobbyState?.Phase == GamePhase.Meeting; + if (hasMeeting && currentMeeting != null) + { + UpdateMeetingLocationMarker(currentMeeting.MeetingLocation, true); + } + else + { + UpdateMeetingLocationMarker(null, false); + } + } + + /// + /// Hledání nejbližší opravné stanice + /// + protected RepairStationInfo FindNearbyRepairStation(double maxDistance) + { + if (currentSabotage?.RepairStations == null) return null; + if (localPlayerObject == null) return null; + + Position myPos = UnityToGPS(localPlayerObject.transform.position); + + foreach (var station in currentSabotage.RepairStations) + { + double dist = CalculateDistance(myPos, station.Location); + if (dist <= maxDistance) return station; + } + + return null; + } + + /// + /// Výpočet vzdálenosti mezi dvěma GPS body (Haversine) + /// + protected double CalculateDistance(Position a, Position b) + { + const double R = 6371000; // Poloměr Země v metrech + + double lat1 = a.Lat * Math.PI / 180; + double lat2 = b.Lat * Math.PI / 180; + double dLat = (b.Lat - a.Lat) * Math.PI / 180; + double dLon = (b.Lon - a.Lon) * Math.PI / 180; + + double h = Math.Sin(dLat/2) * Math.Sin(dLat/2) + + Math.Cos(lat1) * Math.Cos(lat2) * + Math.Sin(dLon/2) * Math.Sin(dLon/2); + + return 2 * R * Math.Asin(Math.Sqrt(h)); + } +} diff --git a/Assets/UnityTestClient/UnityTestClient_Map.cs.meta b/Assets/UnityTestClient/UnityTestClient_Map.cs.meta new file mode 100644 index 0000000..a0a811f --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_Map.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2d9f27ae239808c44b27975df7eefd38 \ No newline at end of file diff --git a/Assets/UnityTestClient/UnityTestClient_Network.cs b/Assets/UnityTestClient/UnityTestClient_Network.cs new file mode 100644 index 0000000..c00203d --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_Network.cs @@ -0,0 +1,1196 @@ +/* +╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ +║ ║ +║ SÍŤOVÁ KOMUNIKACE - UnityTestClient_Network.cs ║ +║ ║ +║ Tento soubor obsahuje veškerou síťovou logiku: ║ +║ • Připojení k serveru (TCP s AES-256 šifrováním) ║ +║ • Zpracování příchozích zpráv a událostí ║ +║ • Odesílání herních akcí ║ +║ • Lobby management ║ +║ ║ +║ KOMUNIKAČNÍ PROTOKOL: ║ +║ 1. Handshake: ClientHello → ServerHello (RSA klíč) → KeyExchange (AES) → KeyExchangeAck ║ +║ 2. Po handshake: Veškerá komunikace je šifrovaná AES-256 ║ +║ 3. Formát zpráv: [4 bajty délka] + [JSON payload] ║ +║ ║ +║ DŮLEŽITÉ ZPRÁVY (klient → server): ║ +║ • CreateLobby/JoinLobby - vytvoření/vstup do lobby ║ +║ • StartGame - spuštění hry (pouze owner) ║ +║ • UpdatePosition - GPS pozice hráče (každých 100ms) ║ +║ • CompleteTask - dokončení úkolu (server validuje pozici!) ║ +║ • KillAttempt - pokus o zabití (pouze impostor) ║ +║ • ReportBody - report těla (svolá meeting) ║ +║ • CallEmergencyMeeting - emergency button ║ +║ • CastVote - hlasování ║ +║ • StartSabotage - spuštění sabotáže (pouze impostor) ║ +║ • ActivateRepairStation - oprava sabotáže ║ +║ ║ +║ DŮLEŽITÉ UDÁLOSTI (server → klient): ║ +║ • LobbyCreated/LobbyJoined - úspěšný vstup do lobby ║ +║ • GameStarted - hra začala ║ +║ • RoleAssigned - přiřazení role (Crew/Impostor) a seznamu úkolů ║ +║ • TaskCompleted - úkol dokončen (s globálním progress) ║ +║ • PlayerKilled - hráč byl zabit ║ +║ • MeetingStarted - začátek meetingu ║ +║ • VotingClosed - výsledky hlasování ║ +║ • SabotageStarted - sabotáž spuštěna (s lokacemi repair stations) ║ +║ • SabotageRepaired - sabotáž opravena ║ +║ • GameEnded - konec hry (s výsledky) ║ +║ ║ +╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ +*/ + +using UnityEngine; +using System; +using System.Threading.Tasks; +using GeoSus.Client; + +public partial class UnityTestClient +{ + #region ═══════════════════════════════════════════════════════════════════ + // SÍŤOVÉ PROMĚNNÉ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Příznak, zda probíhá připojování k serveru + /// + protected bool isConnecting = false; + + /// + /// Časovač pro pravidelné odesílání pozice (každých 100ms) + /// + protected float lastPositionUpdateTime = 0f; + + /// + /// Interval odesílání pozice v sekundách + /// + protected const float POSITION_UPDATE_INTERVAL = 0.1f; + + /// + /// Časovač pro ping + /// + protected float lastPingTime = 0f; + + /// + /// Interval pingu v sekundách + /// + protected const float PING_INTERVAL = 5f; + + /// + /// Aktuální pozice hráče (GPS) + /// + protected Position playerPosition; + + /// + /// ID opravné stanice, kterou právě opravujeme + /// + protected string currentRepairStationId; + + /// + /// Poslední chybová zpráva z ACK - pro prevenci spamu + /// + private string lastAckError = null; + + /// + /// Čas posledního zobrazení chyby z ACK + /// + private float lastAckErrorTime = 0f; + + #region ═══════════════════════════════════════════════════════════════════ + // PŘIPOJENÍ K SERVERU + // ════════════════════════════════════════════════════════════════════════ + // Připojení je asynchronní operace. Používáme async/await pattern. + // Unity vyžaduje volat síťové operace mimo hlavní vlákno, + // ale GameClient to řeší interně pomocí EventDispatcher. + #endregion + + /// + /// Připojení k serveru. + /// Tato metoda vytvoří novou instanci GameClient a pokusí se připojit. + /// + /// DŮLEŽITÉ: Po úspěšném připojení se automaticky registrují event handlery + /// pro příjem zpráv ze serveru. + /// + protected async void ConnectToServer() + { + // Ochrana proti vícenásobnému připojení + if (isConnecting || (client != null && client.IsConnected)) + { + ShowError("Již se připojujete nebo jste připojeni!"); + return; + } + + isConnecting = true; + Debug.Log($"[GeoSus] Připojuji k serveru {serverHost}:{serverPort}..."); + + try + { + // ═══════════════════════════════════════════════════════════════ + // KROK 1: Vytvoření instance GameClient + // ═══════════════════════════════════════════════════════════════ + // GameClient je hlavní třída z ClientSDK pro komunikaci se serverem. + // Vyžaduje unikátní UUID klienta a zobrazované jméno. + client = new GameClient(clientUuid, displayName); + + // ═══════════════════════════════════════════════════════════════ + // KROK 2: Registrace event handlerů + // ═══════════════════════════════════════════════════════════════ + // Události jsou volány na hlavním vlákně díky EventDispatcher. + // Registrujeme je PŘED připojením, abychom neminuli žádné události. + RegisterEventHandlers(); + + // ═══════════════════════════════════════════════════════════════ + // KROK 3: Připojení k serveru + // ═══════════════════════════════════════════════════════════════ + // ConnectAsync provede celý handshake proces: + // ClientHello -> ServerHello -> KeyExchange -> KeyExchangeAck + bool success = await client.ConnectAsync(serverHost, serverPort); + + if (success) + { + Debug.Log("[GeoSus] Úspěšně připojeno k serveru!"); + ShowNotification("Připojeno k serveru", Color.green, 2f, "✓"); + + // Načteme statistiky z HTTP API + FetchPlayerStats(); + FetchLeaderboard(5); + CheckServerHealth(); + } + else + { + ShowError("Nepodařilo se připojit k serveru. Zkontrolujte, zda server běží."); + client.Dispose(); + client = null; + } + } + catch (Exception ex) + { + ShowError($"Chyba připojení: {ex.Message}"); + Debug.LogError($"[GeoSus] Chyba připojení: {ex}"); + + if (client != null) + { + client.Dispose(); + client = null; + } + } + finally + { + isConnecting = false; + } + } + + /// + /// Odpojení od serveru. + /// Volá se při opuštění hry nebo při chybě. + /// + protected void DisconnectFromServer() + { + if (client != null) + { + client.Disconnect("Hráč se odpojil"); + client.Dispose(); + client = null; + } + + // Reset stavu + currentState = AppState.MainMenu; + CleanupMapObjects(); + + Debug.Log("[GeoSus] Odpojeno od serveru"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // EVENT HANDLERY + // ════════════════════════════════════════════════════════════════════════ + // Event handlery jsou volány když přijde zpráva ze serveru. + // GameClient má několik typů událostí: + // • OnConnected - úspěšné připojení + // • OnDisconnected - odpojení (s důvodem) + // • OnError - chyba + // • OnMessage - jakákoli zpráva (pro debug) + // • OnGameEvent - herní události (GameEvent) + #endregion + + /// + /// Registrace všech event handlerů. + /// Volá se při vytvoření klienta, PŘED připojením. + /// + private void RegisterEventHandlers() + { + // ═══════════════════════════════════════════════════════════════════ + // Základní síťové události + // ═══════════════════════════════════════════════════════════════════ + + client.OnConnected += OnClientConnected; + client.OnDisconnected += OnClientDisconnected; + client.OnError += OnClientError; + + // ═══════════════════════════════════════════════════════════════════ + // Herní události - toto je hlavní zdroj informací ze serveru + // ═══════════════════════════════════════════════════════════════════ + + client.OnGameEvent += OnGameEvent; + + // ═══════════════════════════════════════════════════════════════════ + // Zprávy - pro debug a speciální případy + // ═══════════════════════════════════════════════════════════════════ + + client.OnMessage += OnMessage; + } + + /// + /// Handler pro úspěšné připojení + /// + private void OnClientConnected() + { + Debug.Log("[GeoSus] Event: OnConnected"); + } + + /// + /// Handler pro odpojení od serveru + /// + /// Důvod odpojení + private void OnClientDisconnected(string reason) + { + Debug.Log($"[GeoSus] Event: OnDisconnected - {reason}"); + + ShowNotification($"Odpojeno: {reason}", Color.red, 5f, "⚠"); + + // Reset do hlavního menu + currentState = AppState.MainMenu; + CleanupMapObjects(); + + client = null; + } + + /// + /// Handler pro chyby + /// + /// Popis chyby + private void OnClientError(string error) + { + Debug.LogError($"[GeoSus] Event: OnError - {error}"); + ShowError(error); + } + + /// + /// Handler pro příchozí zprávy (všechny typy). + /// Používá se hlavně pro debug a speciální zprávy. + /// + /// Příchozí zpráva + private void OnMessage(Message message) + { + // ═══════════════════════════════════════════════════════════════════ + // Zpracování odpovědí na lobby operace + // ═══════════════════════════════════════════════════════════════════ + + switch (message) + { + case CreateLobbyResponse response: + HandleCreateLobbyResponse(response); + break; + + case JoinLobbyResponse response: + HandleJoinLobbyResponse(response); + break; + + case Ack ack: + HandleAck(ack); + break; + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // HERNÍ UDÁLOSTI (GameEvent) + // ════════════════════════════════════════════════════════════════════════ + // GameEvent je hlavní způsob, jak server informuje klienty o změnách. + // Každý event má: + // • EventId - sekvenční číslo pro řazení + // • EventType - typ události (string) + // • Payload - data události (JObject, deserializuje se na konkrétní typ) + // • Actor - UUID hráče, který akci provedl + #endregion + + /// + /// Hlavní handler pro herní události. + /// Zde se zpracovávají všechny události ze serveru. + /// + /// DŮLEŽITÉ: Payload se deserializuje pomocí GetPayload() + /// + /// Herní událost + private void OnGameEvent(GameEvent evt) + { + Debug.Log($"[GeoSus] GameEvent: {evt.EventType}"); + + // ═══════════════════════════════════════════════════════════════════ + // SWITCH podle typu události + // Každý typ má svůj vlastní payload s daty + // ═══════════════════════════════════════════════════════════════════ + + switch (evt.EventType) + { + // ─────────────────────────────────────────────────────────────── + // LOBBY UDÁLOSTI + // ─────────────────────────────────────────────────────────────── + + case "PlayerJoined": + HandlePlayerJoined(evt); + break; + + case "PlayerLeft": + HandlePlayerLeft(evt); + break; + + case "HostChanged": + HandleHostChanged(evt); + break; + + case "LobbySettingsChanged": + HandleLobbySettingsChanged(evt); + break; + + // ─────────────────────────────────────────────────────────────── + // LOADING FÁZE + // ─────────────────────────────────────────────────────────────── + + case "GameStarting": + HandleGameStarting(evt); + break; + + case "MapDataReady": + HandleMapDataReady(evt); + break; + + case "PlayerMapDataReceived": + HandlePlayerMapDataReceived(evt); + break; + + // ─────────────────────────────────────────────────────────────── + // HRA ZAČÍNÁ + // ─────────────────────────────────────────────────────────────── + + case "GameStarted": + HandleGameStarted(evt); + break; + + case "RoleAssigned": + HandleRoleAssigned(evt); + break; + + // ─────────────────────────────────────────────────────────────── + // HERNÍ AKCE + // ─────────────────────────────────────────────────────────────── + + case "PlayerKilled": + HandlePlayerKilled(evt); + break; + + case "BodyReported": + HandleBodyReported(evt); + break; + + case "EmergencyMeetingCalled": + HandleEmergencyMeetingCalled(evt); + break; + + // ─────────────────────────────────────────────────────────────── + // MEETING A HLASOVÁNÍ + // ─────────────────────────────────────────────────────────────── + + case "MeetingStarted": + HandleMeetingStarted(evt); + break; + + case "PlayerArrivedAtMeeting": + HandlePlayerArrivedAtMeeting(evt); + break; + + case "PlayerVoted": + HandlePlayerVoted(evt); + break; + + case "VotingClosed": + HandleVotingClosed(evt); + break; + + case "PlayerEjected": + HandlePlayerEjected(evt); + break; + + // ─────────────────────────────────────────────────────────────── + // ÚKOLY + // ─────────────────────────────────────────────────────────────── + + case "TaskCompleted": + HandleTaskCompleted(evt); + break; + + // ─────────────────────────────────────────────────────────────── + // SABOTÁŽE + // ─────────────────────────────────────────────────────────────── + + case "SabotageStarted": + HandleSabotageStarted(evt); + break; + + case "RepairStarted": + HandleRepairStarted(evt); + break; + + case "RepairStopped": + HandleRepairStopped(evt); + break; + + case "SabotageRepaired": + HandleSabotageRepaired(evt); + break; + + case "SabotageMeltdown": + HandleSabotageMeltdown(evt); + break; + + // ─────────────────────────────────────────────────────────────── + // KONEC HRY + // ─────────────────────────────────────────────────────────────── + + case "GameEnded": + HandleGameEnded(evt); + break; + + case "ReturnedToLobby": + HandleReturnedToLobby(evt); + break; + + // ─────────────────────────────────────────────────────────────── + // SYSTÉMOVÉ ZPRÁVY + // ─────────────────────────────────────────────────────────────── + + case "SystemMessage": + HandleSystemMessage(evt); + break; + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // HANDLERY JEDNOTLIVÝCH UDÁLOSTÍ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + // ───────────────────────────────────────────────────────────────────────── + // LOBBY HANDLERY + // ───────────────────────────────────────────────────────────────────────── + + /// + /// Zpracování odpovědi na vytvoření lobby + /// + private void HandleCreateLobbyResponse(CreateLobbyResponse response) + { + if (response.Success) + { + Debug.Log($"[GeoSus] Lobby vytvořeno: {response.JoinCode}"); + currentState = AppState.Lobby; + ShowNotification($"Lobby vytvořeno! Kód: {response.JoinCode}", Color.green, 3f, "🏠"); + } + else + { + ShowError($"Nelze vytvořit lobby: {response.Error}"); + } + } + + /// + /// Zpracování odpovědi na připojení do lobby + /// + private void HandleJoinLobbyResponse(JoinLobbyResponse response) + { + if (response.Success) + { + Debug.Log($"[GeoSus] Připojeno do lobby: {response.LobbyId}"); + currentState = AppState.Lobby; + ShowNotification("Připojeno do lobby!", Color.green, 2f, "✓"); + } + else + { + ShowError($"Nelze se připojit: {response.Error}"); + } + } + + /// + /// Zpracování ACK zprávy (potvrzení akce) + /// + private void HandleAck(Ack ack) + { + if (!ack.Success && !string.IsNullOrEmpty(ack.Error)) + { + // Prevence spamu - nezobrazujeme stejnou chybu opakovaně v krátkém čase + float currentTime = Time.time; + if (ack.Error == lastAckError && currentTime - lastAckErrorTime < 3f) + { + // Stejná chyba před méně než 3 sekundami - nezobrazovat + return; + } + + lastAckError = ack.Error; + lastAckErrorTime = currentTime; + + // Zobrazíme chybu uživateli + ShowNotification(ack.Error, new Color(1f, 0.5f, 0f), 3f, "⚠"); + } + } + + /// + /// Hráč se připojil do lobby + /// + private void HandlePlayerJoined(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // SDK automaticky aktualizuje CurrentLobbyState.Players + ShowNotification($"{payload.DisplayName} se připojil/a", Color.cyan, 2f, "→"); + } + } + + /// + /// Hráč opustil lobby + /// + private void HandlePlayerLeft(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // Zkontrolujeme jestli jsme byli kicknuti my + if (payload.ClientUuid == clientUuid) + { + // Jsme kicknuti! + string reason = payload.Reason ?? "Vyhozen administrátorem"; + Debug.Log($"[GeoSus] Byl jsem kicknut: {reason}"); + ShowNotification($"🚫 Byli jste vyhozeni: {reason}", Color.red, 10f, "🚫"); + + // Odpojíme se a vrátíme do menu + currentState = AppState.MainMenu; + client?.Disconnect(); + return; + } + + // SDK automaticky aktualizuje CurrentLobbyState.Players + // Najdeme jméno hráče pro zobrazení + string name = payload.ClientUuid; + if (client?.CurrentLobbyState?.Players != null) + { + foreach (var p in client.CurrentLobbyState.Players) + { + if (p.ClientUuid == payload.ClientUuid) + { + name = p.DisplayName; + break; + } + } + } + + // Zobrazíme jestli byl hráč kicknut nebo odešel sám + bool wasKicked = !string.IsNullOrEmpty(payload.Reason) && payload.Reason.Contains("Kicked"); + if (wasKicked) + { + ShowNotification($"{name} byl/a vyhozen/a", Color.red, 3f, "🚫"); + } + else + { + ShowNotification($"{name} odešel/a", Color.gray, 2f, "←"); + } + } + } + + /// + /// Vlastník lobby se změnil (host migration) + /// + private void HandleHostChanged(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // SDK automaticky aktualizuje CurrentLobbyState.OwnerId a IsOwner flags + bool iAmNewOwner = payload.NewHostId == clientUuid; + + if (iAmNewOwner) + { + ShowNotification("Jsi nyní vlastníkem lobby!", Color.yellow, 4f, "👑"); + Debug.Log("[GeoSus] Stal jsem se vlastníkem lobby"); + } + else + { + // Najdeme jméno nového vlastníka + string newOwnerName = payload.NewHostId; + if (client?.CurrentLobbyState?.Players != null) + { + foreach (var p in client.CurrentLobbyState.Players) + { + if (p.ClientUuid == payload.NewHostId) + { + newOwnerName = p.DisplayName; + break; + } + } + } + ShowNotification($"{newOwnerName} je nyní vlastníkem", Color.cyan, 3f, "👑"); + } + } + } + + /// + /// Nastavení lobby se změnilo + /// + private void HandleLobbySettingsChanged(GameEvent evt) + { + ShowNotification("Nastavení lobby změněno", Color.yellow, 2f, "⚙"); + } + + // ───────────────────────────────────────────────────────────────────────── + // LOADING FÁZE HANDLERY + // ───────────────────────────────────────────────────────────────────────── + + /// + /// Hra začíná - vstupujeme do loading fáze + /// + private void HandleGameStarting(GameEvent evt) + { + Debug.Log("[GeoSus] Hra začíná - načítání mapových dat..."); + currentState = AppState.Loading; + loadingMessage = "Načítání mapových dat..."; + loadingProgress = 0f; + + ShowNotification("Hra začíná!", Color.yellow, 2f, "🎮"); + } + + /// + /// Mapová data jsou připravena + /// + private void HandleMapDataReady(GameEvent evt) + { + var payload = evt.GetPayload(); + + Debug.Log("[GeoSus] Mapová data přijata"); + loadingMessage = "Mapová data přijata, čekám na ostatní hráče..."; + loadingProgress = 0.5f; + + // Vykreslíme mapu - ProcessMapData inicializuje mapu + if (payload?.MapData != null && client?.CurrentLobbyState != null) + { + mapCenter = client.CurrentLobbyState.PlayAreaCenter; + mapRadius = client.CurrentLobbyState.PlayAreaRadius; + ProcessMapData(payload.MapData); + } + + // POZNÁMKA: GameClient automaticky pošle MapDataReceived potvrzení + } + + /// + /// Hráč potvrdil příjem mapových dat + /// + private void HandlePlayerMapDataReceived(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + loadingMessage = $"Hráči připraveni: {payload.PlayersReady}/{payload.TotalPlayers}"; + loadingProgress = 0.5f + (0.5f * payload.PlayersReady / payload.TotalPlayers); + } + } + + // ───────────────────────────────────────────────────────────────────────── + // HRA HANDLERY + // ───────────────────────────────────────────────────────────────────────── + + /// + /// Hra oficiálně začala + /// + private void HandleGameStarted(GameEvent evt) + { + Debug.Log("[GeoSus] Hra začala!"); + currentState = AppState.InGame; + + // Reset herních proměnných + isRepairing = false; + repairProgress = 0f; + + // Inicializace pozice hráče + InitializePlayerPosition(); + + ShowNotification("HRA ZAČALA!", Color.green, 3f, "🎮"); + } + + /// + /// Přiřazení role hráči + /// + private void HandleRoleAssigned(GameEvent evt) + { + var payload = evt.GetPayload(); + + // Kontrola, zda je to naše role + if (payload != null && payload.ClientUuid == clientUuid) + { + Debug.Log($"[GeoSus] Moje role: {payload.Role}"); + + // Zobrazíme velkou notifikaci s rolí + if (payload.Role == PlayerRole.Impostor) + { + ShowNotification("JSI IMPOSTOR!", Color.red, 5f, "🔪"); + } + else + { + ShowNotification("Jsi Crewmate", Color.cyan, 3f, "👤"); + } + + // Aktualizujeme markery úkolů na mapě + CreateTaskMarkers(); + } + } + + /// + /// Hráč byl zabit + /// + private void HandlePlayerKilled(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // Vytvoříme marker těla na mapě + CreateBodyObject(payload.BodyId, payload.Location, GetPlayerName(payload.VictimId)); + + // Pokud jsme to my, kdo byl zabit + if (payload.VictimId == clientUuid) + { + ShowNotification("BYL JSI ZABIT!", Color.red, 5f, "💀"); + } + } + } + + /// + /// Tělo bylo nahlášeno + /// + private void HandleBodyReported(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // Najdeme jméno reportéra + string reporterName = GetPlayerName(payload.ReporterId); + ShowNotification($"{reporterName} nahlásil/a tělo!", Color.red, 3f, "🚨"); + } + } + + /// + /// Emergency meeting bylo svoláno + /// + private void HandleEmergencyMeetingCalled(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + string callerName = GetPlayerName(payload.CallerId); + ShowNotification($"{callerName} svolal/a emergency meeting!", Color.yellow, 3f, "🔔"); + } + } + + // ───────────────────────────────────────────────────────────────────────── + // MEETING HANDLERY + // ───────────────────────────────────────────────────────────────────────── + + /// + /// Meeting začal + /// + private void HandleMeetingStarted(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + Debug.Log($"[GeoSus] Meeting začal: {payload.Type}"); + + // Uložíme data meetingu + currentMeeting = payload; + meetingVotes.Clear(); + arrivedAtMeeting.Clear(); + iArrivedAtMeeting = false; + myVote = null; + canVote = false; + + // Určíme, zda můžeme hlasovat (jsme naživu) + bool amAlive = true; + if (client?.PlayerPositions != null && client.PlayerPositions.TryGetValue(clientUuid, out var myInfo)) + { + amAlive = myInfo.State == PlayerState.Alive; + } + + canVoteInMeeting = amAlive; + + // Notifikace s informací o meeting lokaci + string meetingInfo = payload.Type == MeetingType.BodyReport + ? "TĚLO NALEZENO! Běž na meeting lokaci!" + : "EMERGENCY MEETING! Běž na meeting lokaci!"; + ShowNotification(meetingInfo, Color.yellow, 5f, "📢"); + } + } + + /// + /// Hráč dorazil na meeting lokaci + /// + private void HandlePlayerArrivedAtMeeting(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + arrivedAtMeeting.Add(payload.ClientUuid); + + if (payload.ClientUuid == clientUuid) + { + iArrivedAtMeeting = true; + ShowNotification("Dorazil/a jsi na meeting!", Color.green, 2f, "✓"); + } + else + { + string playerName = GetPlayerName(payload.ClientUuid); + Debug.Log($"[GeoSus] {playerName} dorazil na meeting"); + } + } + } + + /// + /// Hráč hlasoval (vidíme pouze, že hlasoval, ne koho) + /// + private void HandlePlayerVoted(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + meetingVotes[payload.VoterId] = true; // Označíme, že hlasoval + + string voterName = GetPlayerName(payload.VoterId); + ShowNotification($"{voterName} hlasoval/a", Color.gray, 1f, "✓"); + } + } + + /// + /// Hlasování skončilo + /// + private void HandleVotingClosed(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // Uložíme výsledky pro zobrazení + votingResults = payload; + showVotingResults = true; + votingResultsEndTime = Time.time + 5f; // Zobrazíme na 5 sekund + + if (payload.EjectedPlayerId != null) + { + string ejectedName = GetPlayerName(payload.EjectedPlayerId); + ShowNotification($"{ejectedName} byl/a vyhozen/a!", Color.red, 5f, "🚪"); + } + else if (payload.WasTie) + { + ShowNotification("Remíza - nikdo nebyl vyhozen", Color.gray, 3f, "⚖"); + } + else + { + ShowNotification("Nikdo nebyl vyhozen", Color.gray, 3f, "✗"); + } + } + } + + /// + /// Hráč byl vyhozen + /// + private void HandlePlayerEjected(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // Pokud jsme to my + if (payload.ClientUuid == clientUuid) + { + ShowNotification("BYL JSI VYHOZEN!", Color.red, 5f, "🚪"); + } + + // Zavřeme meeting panel + currentMeeting = null; + } + } + + // ───────────────────────────────────────────────────────────────────────── + // TASK HANDLERY + // ───────────────────────────────────────────────────────────────────────── + + /// + /// Úkol byl dokončen (kýmkoli) + /// + private void HandleTaskCompleted(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // Pokud jsme to my, označíme task jako splněný + if (payload.ClientUuid == clientUuid) + { + myCompletedTaskIds.Add(payload.TaskId); + ShowNotification("Úkol dokončen!", Color.green, 2f, "✓"); + + // Aktualizuj marker + UpdateTaskMarker(payload.TaskId, true); + } + + // Aktualizujeme globální progress bar úkolů + totalTasksCompleted = payload.TotalCompleted; + totalTasksRequired = payload.TotalTasks; + + Debug.Log($"[GeoSus] Task completed: {payload.TaskId}, progress {payload.TotalCompleted}/{payload.TotalTasks}"); + } + } + + // ───────────────────────────────────────────────────────────────────────── + // SABOTAGE HANDLERY + // ───────────────────────────────────────────────────────────────────────── + + /// + /// Sabotáž byla spuštěna + /// + private void HandleSabotageStarted(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + Debug.Log($"[GeoSus] Sabotáž spuštěna: {payload.Type}, stanic: {payload.RepairStations?.Count ?? 0}"); + + if (payload.RepairStations != null) + { + foreach (var station in payload.RepairStations) + { + Debug.Log($"[GeoSus] Repair station: {station.StationId} '{station.Name}' @ {station.Location.Lat:F6}, {station.Location.Lon:F6}"); + } + } + + currentSabotage = payload; + + // Vytvoříme markery opravných stanic + CreateRepairStationMarkers(); + + // Zobrazíme notifikaci + string message = payload.Type == SabotageType.CommsBlackout + ? "⚠ COMMS BLACKOUT - Opravte komunikaci!" + : "⚠ CRITICAL MELTDOWN - Opravte reaktor!"; + + Color color = payload.Type == SabotageType.CriticalMeltdown ? Color.red : Color.yellow; + ShowNotification(message, color, 5f, "⚠"); + } + } + + /// + /// Někdo začal opravovat stanici + /// + private void HandleRepairStarted(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + // Aktualizujeme marker stanice + UpdateRepairStationMarker(payload.StationId, true); + } + } + + /// + /// Někdo přestal opravovat stanici + /// + private void HandleRepairStopped(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + UpdateRepairStationMarker(payload.StationId, false); + } + } + + /// + /// Sabotáž byla opravena + /// + private void HandleSabotageRepaired(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + Debug.Log($"[GeoSus] Sabotáž opravena: {payload.Type}"); + + currentSabotage = null; + isRepairing = false; + + // Odstraníme markery opravných stanic + ClearRepairStationMarkers(); + + ShowNotification("Sabotáž opravena!", Color.green, 3f, "✓"); + } + } + + /// + /// Meltdown - impostoři vyhráli + /// + private void HandleSabotageMeltdown(GameEvent evt) + { + ShowNotification("MELTDOWN! Impostoři vyhráli!", Color.red, 5f, "💥"); + } + + // ───────────────────────────────────────────────────────────────────────── + // KONEC HRY + // ───────────────────────────────────────────────────────────────────────── + + /// + /// Hra skončila + /// + private void HandleGameEnded(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload != null) + { + Debug.Log($"[GeoSus] Hra skončila! Vítěz: {payload.WinningFaction}"); + + gameEndData = payload; + currentState = AppState.GameEnded; + + // Notifikace + bool weWon = payload.Winners.Contains(clientUuid); + if (weWon) + { + ShowNotification("VÍTĚZSTVÍ!", Color.green, 5f, "🏆"); + } + else + { + ShowNotification("Prohra...", Color.red, 5f, "💔"); + } + } + } + + /// + /// Vráceno do lobby po skončení hry + /// + private void HandleReturnedToLobby(GameEvent evt) + { + Debug.Log("[GeoSus] Vráceno do lobby"); + + gameEndData = null; + currentSabotage = null; // Reset sabotage stavu! + currentState = AppState.Lobby; + CleanupMapObjects(); + + ShowNotification("Zpět v lobby!", Color.cyan, 3f, "🔄"); + } + + // ───────────────────────────────────────────────────────────────────────── + // SYSTÉMOVÉ ZPRÁVY (Admin broadcast) + // ───────────────────────────────────────────────────────────────────────── + + /// + /// Zpracování systémové zprávy od administrátora + /// + private void HandleSystemMessage(GameEvent evt) + { + var payload = evt.GetPayload(); + if (payload == null) return; + + Debug.Log($"[GeoSus] Systémová zpráva: {payload.Message}"); + + // Zobrazíme výraznou notifikaci s delším trváním (oranžová barva pro admin zprávy) + ShowNotification($"📢 ADMIN: {payload.Message}", new Color(1f, 0.8f, 0f), 8f, "📢"); + } + + #region ═══════════════════════════════════════════════════════════════════ + // ODESÍLÁNÍ ZPRÁV + // ════════════════════════════════════════════════════════════════════════ + // Tyto metody obalují volání GameClient pro pohodlnější použití. + // GameClient.Send() automaticky šifruje a odesílá zprávy. + #endregion + + /// + /// Vytvoření nového lobby + /// + /// Střed herní oblasti (GPS) + /// Poloměr herní oblasti v metrech + /// Počet impostorů + /// Počet úkolů + /// Heslo (volitelné) + protected void CreateLobby(Position center, double radius, int impostorCount, int taskCount, string password = null) + { + if (client == null || !client.IsConnected) + { + ShowError("Nejste připojeni k serveru!"); + return; + } + + Debug.Log($"[GeoSus] Vytvářím lobby: center={center.Lat},{center.Lon}, radius={radius}m"); + client.CreateLobby(center, impostorCount, taskCount, password, radius); + } + + /// + /// Připojení do existujícího lobby + /// + /// 6-místný kód pro připojení + /// Heslo (pokud je vyžadováno) + protected void JoinLobby(string joinCode, string password = null) + { + if (client == null || !client.IsConnected) + { + ShowError("Nejste připojeni k serveru!"); + return; + } + + Debug.Log($"[GeoSus] Připojuji do lobby: {joinCode}"); + client.JoinLobby(joinCode, password); + } + + /// + /// Opuštění lobby + /// + protected void LeaveLobby() + { + if (client != null) + { + client.LeaveLobby(); + } + + currentState = AppState.MainMenu; + CleanupMapObjects(); + } + + /// + /// Spuštění hry (pouze owner) + /// + protected void StartGame() + { + if (client == null || !client.IsConnected) + { + ShowError("Nejste připojeni k serveru!"); + return; + } + + // Kontrola, zda jsme owner (používáme novou vlastnost IsOwner) + if (!client.IsOwner) + { + ShowError("Pouze vlastník lobby může spustit hru!"); + return; + } + + Debug.Log("[GeoSus] Spouštím hru..."); + client.StartGame(); + } + + /// + /// Odeslání aktualizace pozice + /// + protected void SendPositionUpdate() + { + if (client != null && client.IsConnected && currentState == AppState.InGame) + { + client.UpdatePosition(playerPosition); + } + } + +} diff --git a/Assets/UnityTestClient/UnityTestClient_Network.cs.meta b/Assets/UnityTestClient/UnityTestClient_Network.cs.meta new file mode 100644 index 0000000..39be8f4 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_Network.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cdc71cfbe967d754189f3382fee78c6c \ No newline at end of file diff --git a/Assets/UnityTestClient/UnityTestClient_Stats.cs b/Assets/UnityTestClient/UnityTestClient_Stats.cs new file mode 100644 index 0000000..b47a9b3 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_Stats.cs @@ -0,0 +1,589 @@ +/* +╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ +║ ║ +║ STATISTIKY A HTTP API - UnityTestClient_Stats.cs ║ +║ ║ +║ Tento soubor obsahuje komunikaci s HTTP Stats API serveru: ║ +║ • Načítání statistik hráče ║ +║ • Načítání leaderboardu ║ +║ • Health check serveru ║ +║ ║ +║ API ENDPOINTY (port 8088): ║ +║ • GET /stats/{playerId} - statistiky konkrétního hráče ║ +║ • GET /leaderboard?limit=N - top N hráčů podle win rate ║ +║ • GET /health - stav serveru (aktivní lobby, hráči) ║ +║ ║ +║ STATISTIKY ZAHRNUJÍ: ║ +║ • Počet her, výher, proher ║ +║ • Win rate celkově, jako impostor, jako crew ║ +║ • Počet zabití, smrtí, K/D ratio ║ +║ • Dokončené úkoly ║ +║ • Přesnost hlasování (správně odhalení impostoři) ║ +║ ║ +║ POZNÁMKA PRO STUDENTY: ║ +║ Unity používá UnityWebRequest pro HTTP komunikaci. ║ +║ Všechny requesty musí běžet jako coroutiny (StartCoroutine). ║ +║ JSON parsing: JsonUtility (jednodušší) nebo Newtonsoft.Json (flexibilnější). ║ +║ ║ +║ Pro vlastní hru můžete rozšířit statistiky o: ║ +║ • Achievements/Badges ║ +║ • Sezónní ranky ║ +║ • Historii her ║ +║ ║ +╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ +*/ + +using UnityEngine; +using UnityEngine.Networking; +using System; +using System.Collections; +using System.Collections.Generic; + +public partial class UnityTestClient +{ + #region ═══════════════════════════════════════════════════════════════════ + // STATS PROMĚNNÉ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// Port pro Stats HTTP API + protected int statsApiPort = 8088; + + /// URL pro Stats API (automaticky používá HTTPS pokud je povoleno) + protected string StatsApiUrl => useHttps + ? $"https://{serverHost}" + : $"http://{serverHost}:{statsApiPort}"; + + /// Načtené statistiky hráče + protected PlayerStatistics playerStats = null; + + /// Načtený leaderboard + protected List leaderboard = null; + + /// Stav zdraví serveru + protected ServerHealthStatus healthStatus = null; + + /// Probíhá načítání statistik? + protected bool isLoadingStats = false; + + /// Probíhá načítání leaderboardu? + protected bool isLoadingLeaderboard = false; + + #region ═══════════════════════════════════════════════════════════════════ + // DATOVÉ STRUKTURY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Statistiky hráče. + /// Mapuje se z JSON response z /stats/{playerId}. + /// POZOR: Názvy polí musí přesně odpovídat JSON z serveru! + /// + [System.Serializable] + public class PlayerStatistics + { + /// UUID hráče + public string clientUuid; + + /// Zobrazované jméno + public string displayName; + + /// Celkový počet odehraných her + public int totalGames; + + /// Počet her jako crew + public int gamesAsCrew; + + /// Počet her jako impostor + public int gamesAsImpostor; + + /// Počet výher jako crew + public int crewWins; + + /// Počet výher jako impostor + public int impostorWins; + + /// Win rate jako crew (0-1) + public float crewWinRate; + + /// Win rate jako impostor (0-1) + public float impostorWinRate; + + /// Počet zabití (jako impostor) + public int totalKills; + + /// Počet smrtí + public int totalDeaths; + + /// Kill/Death ratio + public float killDeathRatio; + + /// Počet dokončených úkolů + public int tasksCompleted; + + /// Průměrný počet tasků za hru + public float averageTasksPerGame; + + /// Počet nahlášených těl + public int bodiesReported; + + /// Počet svolaných emergency meetingů + public int emergencyMeetingsCalled; + + /// Kolikrát byl vyhozen hlasováním + public int timesVotedOut; + + /// Počet úspěšných hlasů (správně identifikovaný impostor) + public int successfulVotes; + + /// Celkový čas hraní v sekundách + public long totalPlaytimeSeconds; + + /// Počet cheat incidentů + public int cheatIncidents; + + /// Kdy byl naposledy viděn + public string lastSeen; + + // Pomocné vlastnosti pro zobrazení v UI + public int GamesWon => crewWins + impostorWins; + public float WinRate => totalGames > 0 ? (float)GamesWon / totalGames : 0f; + } + + /// + /// Položka leaderboardu. + /// POZOR: Názvy polí musí přesně odpovídat JSON z serveru! + /// + [System.Serializable] + public class LeaderboardEntry + { + /// UUID hráče + public string clientUuid; + + /// Zobrazované jméno + public string displayName; + + /// Celkový počet her + public int totalGames; + + /// Výhry jako crew + public int crewWins; + + /// Výhry jako impostor + public int impostorWins; + + /// Počet zabití + public int totalKills; + + /// Počet dokončených tasků + public int tasksCompleted; + + // Pomocné vlastnosti + public int TotalWins => crewWins + impostorWins; + public float WinRate => totalGames > 0 ? (float)TotalWins / totalGames : 0f; + } + + /// + /// Wrapper pro leaderboard response (JSON array). + /// + [System.Serializable] + public class LeaderboardResponse + { + public List entries; + } + + /// + /// Stav serveru. + /// + [System.Serializable] + public class ServerHealthStatus + { + /// Stav: "healthy" nebo "unhealthy" + public string status; + + /// Verze serveru + public string version; + + /// Uptime v sekundách + public long uptimeSeconds; + + /// Počet aktivních lobby + public int activeLobbies; + + /// Počet připojených hráčů + public int connectedPlayers; + } + + #region ═══════════════════════════════════════════════════════════════════ + // NAČÍTÁNÍ STATISTIK + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Spustí načítání statistik hráče. + /// Výsledek bude v playerStats. + /// + protected void FetchPlayerStats() + { + Debug.Log($"[Stats] FetchPlayerStats called. isLoadingStats={isLoadingStats}, clientUuid={clientUuid}"); + + if (isLoadingStats) + { + Debug.Log("[Stats] Already loading, skipping"); + return; + } + if (string.IsNullOrEmpty(clientUuid)) + { + Debug.Log("[Stats] clientUuid is empty, skipping"); + return; + } + + Debug.Log($"[Stats] Starting coroutine for player {clientUuid}"); + StartCoroutine(FetchPlayerStatsCoroutine(clientUuid)); + } + + /// + /// Coroutine pro načtení statistik hráče. + /// + /// POZNÁMKA PRO STUDENTY: + /// Coroutiny v Unity umožňují asynchronní operace. + /// yield return čeká na dokončení operace před pokračováním. + /// UnityWebRequest.Get vytváří HTTP GET request. + /// + /// UUID hráče + private IEnumerator FetchPlayerStatsCoroutine(string playerId) + { + isLoadingStats = true; + + string url = $"{StatsApiUrl}/stats/{playerId}"; + Debug.Log($"[Stats] Fetching from: {url}"); + + using (UnityWebRequest request = UnityWebRequest.Get(url)) + { + // Nastavení timeoutu + request.timeout = 10; + + // Odeslání requestu a čekání na odpověď + yield return request.SendWebRequest(); + + Debug.Log($"[Stats] Request completed. Result: {request.result}, Code: {request.responseCode}"); + + // Kontrola chyb + if (request.result == UnityWebRequest.Result.Success) + { + // Parsování JSON + try + { + string json = request.downloadHandler.text; + playerStats = JsonUtility.FromJson(json); + + Debug.Log($"[Stats] Loaded stats for {playerStats.displayName}"); + } + catch (Exception e) + { + Debug.LogError($"[Stats] Failed to parse stats: {e.Message}"); + playerStats = null; + } + } + else + { + // Chyba při requestu + Debug.LogWarning($"[Stats] Failed to fetch stats: {request.error}"); + + // Pokud hráč neexistuje (404), vytvoříme prázdné statistiky + if (request.responseCode == 404) + { + playerStats = new PlayerStatistics + { + clientUuid = playerId, + displayName = displayName, + totalGames = 0, + gamesAsCrew = 0, + gamesAsImpostor = 0, + crewWins = 0, + impostorWins = 0, + crewWinRate = 0, + impostorWinRate = 0, + totalKills = 0, + totalDeaths = 0, + killDeathRatio = 0, + tasksCompleted = 0 + }; + } + } + } + + isLoadingStats = false; + } + + #region ═══════════════════════════════════════════════════════════════════ + // LEADERBOARD + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Spustí načítání leaderboardu. + /// + /// Počet hráčů k načtení (max 100) + protected void FetchLeaderboard(int limit = 10) + { + if (isLoadingLeaderboard) return; + + StartCoroutine(FetchLeaderboardCoroutine(limit)); + } + + /// + /// Coroutine pro načtení leaderboardu. + /// + private IEnumerator FetchLeaderboardCoroutine(int limit) + { + isLoadingLeaderboard = true; + + string url = $"{StatsApiUrl}/leaderboard?limit={limit}"; + + using (UnityWebRequest request = UnityWebRequest.Get(url)) + { + request.timeout = 10; + + yield return request.SendWebRequest(); + + if (request.result == UnityWebRequest.Result.Success) + { + try + { + string json = request.downloadHandler.text; + + // JsonUtility nemá přímou podporu pro arrays, potřebujeme wrapper + // nebo použijeme jednoduchý workaround + string wrappedJson = "{\"entries\":" + json + "}"; + LeaderboardResponse response = JsonUtility.FromJson(wrappedJson); + leaderboard = response.entries; + + Debug.Log($"[Stats] Loaded leaderboard with {leaderboard.Count} entries"); + } + catch (Exception e) + { + Debug.LogError($"[Stats] Failed to parse leaderboard: {e.Message}"); + leaderboard = null; + } + } + else + { + Debug.LogWarning($"[Stats] Failed to fetch leaderboard: {request.error}"); + } + } + + isLoadingLeaderboard = false; + } + + #region ═══════════════════════════════════════════════════════════════════ + // HEALTH CHECK + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Spustí health check serveru. + /// + protected void CheckServerHealth() + { + StartCoroutine(CheckServerHealthCoroutine()); + } + + /// + /// Coroutine pro health check. + /// + private IEnumerator CheckServerHealthCoroutine() + { + string url = $"{StatsApiUrl}/health"; + + using (UnityWebRequest request = UnityWebRequest.Get(url)) + { + request.timeout = 5; + + yield return request.SendWebRequest(); + + if (request.result == UnityWebRequest.Result.Success) + { + try + { + string json = request.downloadHandler.text; + healthStatus = JsonUtility.FromJson(json); + + Debug.Log($"[Stats] Server health: {healthStatus.status}, " + + $"uptime: {healthStatus.uptimeSeconds}s, " + + $"lobbies: {healthStatus.activeLobbies}, " + + $"players: {healthStatus.connectedPlayers}"); + } + catch (Exception e) + { + Debug.LogError($"[Stats] Failed to parse health: {e.Message}"); + healthStatus = null; + } + } + else + { + Debug.LogWarning($"[Stats] Health check failed: {request.error}"); + healthStatus = new ServerHealthStatus + { + status = "unreachable", + version = "unknown" + }; + } + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // UI PRO LEADERBOARD + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení leaderboard panelu. + /// Volá se z DrawStatsTab(). + /// + protected void DrawLeaderboardPanel() + { + if (leaderboard == null) + { + GUILayout.Label("Načítám leaderboard...", labelStyle); + + if (GUILayout.Button("Načíst", buttonStyle)) + { + FetchLeaderboard(10); + } + return; + } + + GUILayout.Label("TOP HRÁČI", subtitleStyle); + GUILayout.Space(5); + + // Hlavička + GUILayout.BeginHorizontal(); + GUILayout.Label("#", GUILayout.Width(30)); + GUILayout.Label("Jméno", GUILayout.Width(150)); + GUILayout.Label("Skóre", GUILayout.Width(80)); + GUILayout.Label("Win%", GUILayout.Width(60)); + GUILayout.EndHorizontal(); + + // Položky + int rank = 1; + foreach (var entry in leaderboard) + { + GUILayout.BeginHorizontal(); + + // Speciální barvy pro top 3 + if (rank == 1) GUI.color = Color.yellow; + else if (rank == 2) GUI.color = new Color(0.8f, 0.8f, 0.8f); + else if (rank == 3) GUI.color = new Color(0.8f, 0.5f, 0.2f); + else GUI.color = Color.white; + + GUILayout.Label($"{rank}.", GUILayout.Width(30)); + GUILayout.Label(entry.displayName, GUILayout.Width(150)); + GUILayout.Label(entry.TotalWins.ToString(), GUILayout.Width(80)); + GUILayout.Label($"{entry.WinRate * 100:F0}%", GUILayout.Width(60)); + + GUI.color = Color.white; + GUILayout.EndHorizontal(); + rank++; + } + + GUILayout.Space(10); + + if (GUILayout.Button("Obnovit", buttonStyle)) + { + leaderboard = null; + FetchLeaderboard(10); + } + } + + #region ═══════════════════════════════════════════════════════════════════ + // UI PRO SERVER HEALTH + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení panelu stavu serveru. + /// + protected void DrawServerHealthPanel() + { + GUILayout.BeginVertical(boxStyle); + + GUILayout.Label("STAV SERVERU", subtitleStyle); + + if (healthStatus == null) + { + GUILayout.Label("Neznámý", labelStyle); + + if (GUILayout.Button("Zkontrolovat", buttonStyle)) + { + CheckServerHealth(); + } + } + else + { + // Status + if (healthStatus.status == "healthy") + { + GUI.color = Color.green; + GUILayout.Label("● Online", labelStyle); + } + else + { + GUI.color = Color.red; + GUILayout.Label("● Offline", labelStyle); + } + GUI.color = Color.white; + + // Detaily + GUILayout.Label($"Verze: {healthStatus.version}", labelStyle); + + // Uptime + TimeSpan uptime = TimeSpan.FromSeconds(healthStatus.uptimeSeconds); + GUILayout.Label($"Uptime: {uptime.Days}d {uptime.Hours}h {uptime.Minutes}m", labelStyle); + + // Aktivita + GUILayout.Label($"Lobby: {healthStatus.activeLobbies}", labelStyle); + GUILayout.Label($"Hráči: {healthStatus.connectedPlayers}", labelStyle); + + GUILayout.Space(5); + + if (GUILayout.Button("Obnovit", buttonStyle)) + { + healthStatus = null; + CheckServerHealth(); + } + } + + GUILayout.EndVertical(); + } + + #region ═══════════════════════════════════════════════════════════════════ + // AUTOMATICKÉ NAČÍTÁNÍ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Interval automatického obnovení statistik (sekundy) + /// + protected float statsRefreshInterval = 60f; + + /// Čas posledního obnovení + protected float lastStatsRefresh = 0f; + + /// + /// Automatické načítání statistik. + /// Volá se v Update(). + /// + protected void UpdateStatsAutoRefresh() + { + if (currentState != AppState.MainMenu) return; + if (string.IsNullOrEmpty(clientUuid)) return; + + if (Time.time - lastStatsRefresh >= statsRefreshInterval) + { + FetchPlayerStats(); + CheckServerHealth(); + lastStatsRefresh = Time.time; + } + } +} diff --git a/Assets/UnityTestClient/UnityTestClient_Stats.cs.meta b/Assets/UnityTestClient/UnityTestClient_Stats.cs.meta new file mode 100644 index 0000000..2a75687 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_Stats.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8b7bb01435f46b842b79fe4836d1b44e \ No newline at end of file diff --git a/Assets/UnityTestClient/UnityTestClient_UI.cs b/Assets/UnityTestClient/UnityTestClient_UI.cs new file mode 100644 index 0000000..08d8e8a --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_UI.cs @@ -0,0 +1,1642 @@ +/* +╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ +║ ║ +║ UŽIVATELSKÉ ROZHRANÍ - UnityTestClient_UI.cs ║ +║ ║ +║ Tento soubor obsahuje veškeré UI pomocí Unity IMGUI: ║ +║ • Hlavní menu (připojení, vytvoření/vstup do lobby, statistiky) ║ +║ • Lobby obrazovka (nastavení, seznam hráčů, chat) ║ +║ • Loading obrazovka (progress bar načítání mapových dat) ║ +║ • Herní HUD (role, úkoly, minimap, sabotáž timer) ║ +║ • Meeting panel (hlasování, diskuze) ║ +║ • Konec hry (výsledky, statistiky) ║ +║ ║ +║ HERNÍ HUD OBSAHUJE: ║ +║ • Panel role (nahoře) - vaše role, jméno, stav ║ +║ • Panel úkolů (vpravo) - globální progress bar + seznam VAŠICH úkolů ║ +║ - Zelený checkmark = VY jste dokončili tento úkol ║ +║ - Progress bar = celkový pokrok VŠECH hráčů ║ +║ • Sabotáž timer (při aktivní sabotáži) - zbývající čas ║ +║ • Akční tlačítka (dole) - USE, KILL, SABOTAGE, REPORT ║ +║ ║ +║ POZNÁMKA PRO STUDENTY: ║ +║ IMGUI je vhodné pro prototypování a debug, ale pro produkční hru ║ +║ doporučujeme použít Unity UI (Canvas) nebo UI Toolkit, které nabízejí: ║ +║ • Lepší výkon (batching, atlasy) ║ +║ • WYSIWYG editor v Unity ║ +║ • Lepší podporu animací a přechodů ║ +║ • Snadnější lokalizaci a škálování ║ +║ • Lepší podporu dotykového ovládání ║ +║ ║ +╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ +*/ + +using UnityEngine; +using System; +using System.Collections.Generic; +using GeoSus.Client; + +public partial class UnityTestClient +{ + #region ═══════════════════════════════════════════════════════════════════ + // UI PROMĚNNÉ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + // ───────────────────────────────────────────────────────────────────────── + // GUI Styly - inicializují se v InitializeUIStyles() + // ───────────────────────────────────────────────────────────────────────── + + /// Styl pro velké nadpisy + protected GUIStyle titleStyle; + + /// Styl pro podnadpisy + protected GUIStyle subtitleStyle; + + /// Styl pro běžný text + protected GUIStyle labelStyle; + + /// Styl pro tlačítka + protected GUIStyle buttonStyle; + + /// Styl pro velká tlačítka + protected GUIStyle bigButtonStyle; + + /// Styl pro textová pole + protected GUIStyle textFieldStyle; + + /// Styl pro boxy/panely + protected GUIStyle boxStyle; + + /// Styl pro rich text + protected GUIStyle richTextStyle; + + /// Styl pro notifikace + protected GUIStyle notificationStyle; + + // ───────────────────────────────────────────────────────────────────────── + // Vstupy pro formuláře + // ───────────────────────────────────────────────────────────────────────── + + /// Vstupní pole pro jméno hráče + protected string inputPlayerName = ""; + + /// Vstupní pole pro kód lobby + protected string inputJoinCode = ""; + + /// Vstupní pole pro heslo + protected string inputPassword = ""; + + /// Vstupní pole pro zeměpisnou šířku + protected string inputLatitude = "50.7735892"; + + /// Vstupní pole pro zeměpisnou délku + protected string inputLongitude = "15.0721653"; + + /// Vstupní pole pro poloměr + protected string inputRadius = "300"; + + /// Počet impostorů + protected int inputImpostorCount = 1; + + /// Počet úkolů + protected int inputTaskCount = 5; + + // ───────────────────────────────────────────────────────────────────────── + // UI stav + // ───────────────────────────────────────────────────────────────────────── + + /// Aktuální záložka v hlavním menu + protected int mainMenuTab = 0; + + /// Scroll pozice pro seznam hráčů + protected Vector2 playerListScroll; + + /// Scroll pozice pro statistiky + protected Vector2 statsScroll; + + /// Škálovací faktor UI + protected float uiScale = 1f; + + // ───────────────────────────────────────────────────────────────────────── + // Loading stav + // ───────────────────────────────────────────────────────────────────────── + + /// Zpráva během načítání + protected string loadingMessage = "Načítání..."; + + /// Progress načítání (0-1) + protected float loadingProgress = 0f; + + // ───────────────────────────────────────────────────────────────────────── + // Meeting stav + // ───────────────────────────────────────────────────────────────────────── + + /// Aktuální meeting data + protected MeetingStartedPayload currentMeeting; + + /// Kdo už hlasoval + protected Dictionary meetingVotes = new Dictionary(); + + /// Kdo dorazil na meeting + protected HashSet arrivedAtMeeting = new HashSet(); + + /// Dorazili jsme na meeting? + protected bool iArrivedAtMeeting = false; + + /// Náš hlas (UUID nebo null pro skip) + protected string myVote; + + /// Můžeme hlasovat? + protected bool canVote = false; + + /// Můžeme hlasovat v tomto meetingu (jsme naživu)? + protected bool canVoteInMeeting = false; + + /// Výsledky hlasování + protected VotingClosedPayload votingResults; + + /// Zobrazit výsledky hlasování? + protected bool showVotingResults = false; + + /// Čas konce zobrazení výsledků + protected float votingResultsEndTime; + + // ───────────────────────────────────────────────────────────────────────── + // Herní HUD stav + // ───────────────────────────────────────────────────────────────────────── + + /// Celkový počet dokončených úkolů (globálně pro všechny hráče) + protected int totalTasksCompleted = 0; + + /// Celkový počet požadovaných úkolů (globálně) + protected int totalTasksRequired = 0; + + /// ID mých splněných úkolů + protected HashSet myCompletedTaskIds = new HashSet(); + + /// Zobrazit sabotage panel? + protected bool showSabotagePanel = false; + + #region ═══════════════════════════════════════════════════════════════════ + // INICIALIZACE STYLŮ + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Inicializace GUI stylů. + /// DŮLEŽITÉ: Musí se volat v Start() nebo později, ne v Awake()! + /// GUISkin není dostupný v Awake. + /// + protected void InitializeUIStyles() + { + // Styl pro velké nadpisy + titleStyle = new GUIStyle(GUI.skin.label) + { + fontSize = 32, + fontStyle = FontStyle.Bold, + alignment = TextAnchor.MiddleCenter + }; + titleStyle.normal.textColor = Color.white; + + // Styl pro podnadpisy + subtitleStyle = new GUIStyle(GUI.skin.label) + { + fontSize = 20, + fontStyle = FontStyle.Bold, + alignment = TextAnchor.MiddleCenter + }; + subtitleStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f); + + // Styl pro běžný text + labelStyle = new GUIStyle(GUI.skin.label) + { + fontSize = 16, + alignment = TextAnchor.MiddleLeft + }; + labelStyle.normal.textColor = Color.white; + + // Styl pro tlačítka + buttonStyle = new GUIStyle(GUI.skin.button) + { + fontSize = 16, + fontStyle = FontStyle.Bold + }; + + // Styl pro velká tlačítka + bigButtonStyle = new GUIStyle(GUI.skin.button) + { + fontSize = 20, + fontStyle = FontStyle.Bold, + fixedHeight = 50 + }; + + // Styl pro textová pole + textFieldStyle = new GUIStyle(GUI.skin.textField) + { + fontSize = 16, + fixedHeight = 30 + }; + + // Styl pro boxy + boxStyle = new GUIStyle(GUI.skin.box) + { + padding = new RectOffset(10, 10, 10, 10) + }; + + // Styl pro rich text + richTextStyle = new GUIStyle(GUI.skin.label) + { + richText = true, + fontSize = 14 + }; + + // Styl pro notifikace + notificationStyle = new GUIStyle(GUI.skin.box) + { + fontSize = 18, + fontStyle = FontStyle.Bold, + alignment = TextAnchor.MiddleCenter + }; + notificationStyle.normal.textColor = Color.white; + + // Načteme uložené jméno + inputPlayerName = displayName; + } + + /// + /// Aplikace škálování UI pro různá rozlišení. + /// Základní rozlišení je 1920x1080. + /// + protected void ApplyUIScaling() + { + // Výpočet škálovacího faktoru + float baseWidth = 1920f; + float baseHeight = 1080f; + + // Použijeme menší z obou faktorů pro zachování poměru stran + float scaleX = Screen.width / baseWidth; + float scaleY = Screen.height / baseHeight; + uiScale = Mathf.Min(scaleX, scaleY); + + // Minimální škálování + uiScale = Mathf.Max(uiScale, 0.5f); + + // Aplikace matice pro škálování + GUI.matrix = Matrix4x4.TRS( + Vector3.zero, + Quaternion.identity, + new Vector3(uiScale, uiScale, 1f) + ); + } + + #region ═══════════════════════════════════════════════════════════════════ + // HLAVNÍ MENU + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení hlavního menu. + /// Obsahuje záložky pro připojení, vytvoření lobby a statistiky. + /// + protected void DrawMainMenu() + { + // Reinicializace stylů pokud je potřeba (po změně skinu) + if (titleStyle == null) InitializeUIStyles(); + + // Centrovaný panel + float panelWidth = 500; + float panelHeight = 600; + float panelX = (Screen.width / uiScale - panelWidth) / 2; + float panelY = (Screen.height / uiScale - panelHeight) / 2; + + GUILayout.BeginArea(new Rect(panelX, panelY, panelWidth, panelHeight)); + + // Pozadí + GUI.Box(new Rect(0, 0, panelWidth, panelHeight), "", boxStyle); + + // Použijeme try-catch pro ošetření změn stavu během renderování + try + { + // ═══════════════════════════════════════════════════════════════════ + // NADPIS + // ═══════════════════════════════════════════════════════════════════ + + GUILayout.Space(20); + GUILayout.Label("GeoSus", titleStyle); + GUILayout.Label("GPS Multiplayer Game", subtitleStyle); + GUILayout.Space(20); + + // ═══════════════════════════════════════════════════════════════════ + // STAV PŘIPOJENÍ + // ═══════════════════════════════════════════════════════════════════ + + // Cache stav na začátku renderování pro konzistenci + bool isConnected = client != null && client.IsConnected; + + if (isConnected) + { + GUI.color = Color.green; + GUILayout.Label("● Připojeno k serveru", labelStyle); + GUI.color = Color.white; + } + else if (isConnecting) + { + GUI.color = Color.yellow; + GUILayout.Label("● Připojuji...", labelStyle); + GUI.color = Color.white; + } + else + { + GUI.color = Color.red; + GUILayout.Label("● Nepřipojeno", labelStyle); + GUI.color = Color.white; + } + + GUILayout.Space(10); + + // ═══════════════════════════════════════════════════════════════════ + // JMÉNO HRÁČE + // ═══════════════════════════════════════════════════════════════════ + + GUILayout.Label("Vaše jméno:", labelStyle); + inputPlayerName = GUILayout.TextField(inputPlayerName, 20, textFieldStyle); + + // Uložení jména + if (inputPlayerName != displayName && !string.IsNullOrWhiteSpace(inputPlayerName)) + { + displayName = inputPlayerName; + PlayerPrefs.SetString("PlayerName", displayName); + if (client != null) client.DisplayName = displayName; + } + + GUILayout.Space(10); + + // ═══════════════════════════════════════════════════════════════════ + // PŘIPOJENÍ K SERVERU + // ═══════════════════════════════════════════════════════════════════ + + if (!isConnected) + { + GUI.enabled = !isConnecting; + if (GUILayout.Button("Připojit k serveru", bigButtonStyle)) + { + ConnectToServer(); + } + GUI.enabled = true; + } + else + { + // ═══════════════════════════════════════════════════════════════ + // ZÁLOŽKY + // ═══════════════════════════════════════════════════════════════ + + string[] tabs = { "Připojit se", "Vytvořit hru", "Statistiky" }; + mainMenuTab = GUILayout.Toolbar(mainMenuTab, tabs); + + GUILayout.Space(10); + + switch (mainMenuTab) + { + case 0: + DrawJoinLobbyTab(); + break; + case 1: + DrawCreateLobbyTab(); + break; + case 2: + DrawStatsTab(); + break; + } + + GUILayout.Space(20); + + // Tlačítko odpojení + GUI.color = new Color(1f, 0.5f, 0.5f); + if (GUILayout.Button("Odpojit", buttonStyle)) + { + DisconnectFromServer(); + } + GUI.color = Color.white; + } + + } // end try + catch (System.ArgumentException) + { + // Ignorujeme chyby při změně stavu GUI mezi Layout a Repaint + // Příští frame se vykreslí správně + } + + GUILayout.EndArea(); + } + + /// + /// Záložka pro připojení do existujícího lobby + /// + private void DrawJoinLobbyTab() + { + GUILayout.Label("Kód lobby:", labelStyle); + + // Vstup pro kód - automaticky uppercase + inputJoinCode = GUILayout.TextField(inputJoinCode.ToUpper(), 6, textFieldStyle); + + GUILayout.Space(5); + + GUILayout.Label("Heslo (volitelné):", labelStyle); + inputPassword = GUILayout.PasswordField(inputPassword, '*', textFieldStyle); + + GUILayout.Space(20); + + GUI.enabled = inputJoinCode.Length == 6; + if (GUILayout.Button("Připojit do lobby", bigButtonStyle)) + { + JoinLobby(inputJoinCode, string.IsNullOrWhiteSpace(inputPassword) ? null : inputPassword); + } + GUI.enabled = true; + } + + /// + /// Záložka pro vytvoření nového lobby + /// + private void DrawCreateLobbyTab() + { + // ───────────────────────────────────────────────────────────────── + // GPS souřadnice + // ───────────────────────────────────────────────────────────────── + + GUILayout.Label("Střed herní oblasti (GPS):", labelStyle); + + GUILayout.BeginHorizontal(); + GUILayout.Label("Lat:", GUILayout.Width(40)); + inputLatitude = GUILayout.TextField(inputLatitude, textFieldStyle); + GUILayout.Label("Lon:", GUILayout.Width(40)); + inputLongitude = GUILayout.TextField(inputLongitude, textFieldStyle); + GUILayout.EndHorizontal(); + + GUILayout.Space(5); + + // ───────────────────────────────────────────────────────────────── + // Poloměr + // ───────────────────────────────────────────────────────────────── + + GUILayout.Label($"Poloměr herní oblasti: {inputRadius}m", labelStyle); + + // Slider pro poloměr + float radius = 300f; + float.TryParse(inputRadius, out radius); + radius = GUILayout.HorizontalSlider(radius, 100f, 1000f); + inputRadius = Mathf.RoundToInt(radius).ToString(); + + GUILayout.Space(10); + + // ───────────────────────────────────────────────────────────────── + // Počet impostorů + // ───────────────────────────────────────────────────────────────── + + GUILayout.Label($"Počet impostorů: {inputImpostorCount}", labelStyle); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("-", GUILayout.Width(40))) inputImpostorCount = Mathf.Max(1, inputImpostorCount - 1); + GUILayout.HorizontalSlider(inputImpostorCount, 1, 3); + if (GUILayout.Button("+", GUILayout.Width(40))) inputImpostorCount = Mathf.Min(3, inputImpostorCount + 1); + GUILayout.EndHorizontal(); + + GUILayout.Space(5); + + // ───────────────────────────────────────────────────────────────── + // Počet úkolů + // ───────────────────────────────────────────────────────────────── + + GUILayout.Label($"Počet úkolů: {inputTaskCount}", labelStyle); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("-", GUILayout.Width(40))) inputTaskCount = Mathf.Max(3, inputTaskCount - 1); + GUILayout.HorizontalSlider(inputTaskCount, 3, 10); + if (GUILayout.Button("+", GUILayout.Width(40))) inputTaskCount = Mathf.Min(10, inputTaskCount + 1); + GUILayout.EndHorizontal(); + + GUILayout.Space(5); + + // ───────────────────────────────────────────────────────────────── + // Heslo + // ───────────────────────────────────────────────────────────────── + + GUILayout.Label("Heslo (volitelné):", labelStyle); + inputPassword = GUILayout.PasswordField(inputPassword, '*', textFieldStyle); + + GUILayout.Space(20); + + // ───────────────────────────────────────────────────────────────── + // Tlačítko vytvoření + // ───────────────────────────────────────────────────────────────── + + if (GUILayout.Button("Vytvořit lobby", bigButtonStyle)) + { + double lat, lon, rad; + if (double.TryParse(inputLatitude, out lat) && + double.TryParse(inputLongitude, out lon) && + double.TryParse(inputRadius, out rad)) + { + Position center = new Position(lat, lon); + CreateLobby(center, rad, inputImpostorCount, inputTaskCount, + string.IsNullOrWhiteSpace(inputPassword) ? null : inputPassword); + } + else + { + ShowError("Neplatné souřadnice nebo poloměr!"); + } + } + } + + /// + /// Záložka pro statistiky hráče + /// + private void DrawStatsTab() + { + statsScroll = GUILayout.BeginScrollView(statsScroll, GUILayout.Height(350)); + + // ═══════════════════════════════════════════════════════════════ + // SERVER HEALTH + // ═══════════════════════════════════════════════════════════════ + GUILayout.Label("═══ SERVER STATUS ═══", labelStyle); + + if (healthStatus == null) + { + GUILayout.Label("Načítám stav serveru...", labelStyle); + } + else + { + Color statusColor = healthStatus.status == "ok" ? Color.green : Color.red; + GUI.color = statusColor; + DrawStatRow("Status", healthStatus.status.ToUpper()); + GUI.color = Color.white; + + if (healthStatus.uptimeSeconds > 0) + { + var uptime = TimeSpan.FromSeconds(healthStatus.uptimeSeconds); + DrawStatRow("Uptime", $"{uptime.Hours:D2}:{uptime.Minutes:D2}:{uptime.Seconds:D2}"); + } + DrawStatRow("Aktivní lobby", healthStatus.activeLobbies.ToString()); + DrawStatRow("Hráčů online", healthStatus.connectedPlayers.ToString()); + if (!string.IsNullOrEmpty(healthStatus.version)) + DrawStatRow("Verze", healthStatus.version); + } + + GUILayout.Space(10); + + // ═══════════════════════════════════════════════════════════════ + // MOJE STATISTIKY + // ═══════════════════════════════════════════════════════════════ + GUILayout.Label("═══ MOJE STATISTIKY ═══", labelStyle); + + if (playerStats == null) + { + GUILayout.Label("Načítám statistiky...", labelStyle); + } + else + { + DrawStatRow("Odehráno her", playerStats.totalGames.ToString()); + DrawStatRow("Výher", playerStats.GamesWon.ToString()); + DrawStatRow("Win rate", $"{(playerStats.WinRate * 100):F1}%"); + DrawStatRow("Zabití", playerStats.totalKills.ToString()); + DrawStatRow("Smrti", playerStats.totalDeaths.ToString()); + DrawStatRow("K/D ratio", $"{playerStats.killDeathRatio:F2}"); + DrawStatRow("Dokončené úkoly", playerStats.tasksCompleted.ToString()); + DrawStatRow("Her jako impostor", playerStats.gamesAsImpostor.ToString()); + DrawStatRow("Her jako crew", playerStats.gamesAsCrew.ToString()); + } + + GUILayout.Space(10); + + // ═══════════════════════════════════════════════════════════════ + // LEADERBOARD + // ═══════════════════════════════════════════════════════════════ + GUILayout.Label("═══ LEADERBOARD (TOP 5) ═══", labelStyle); + + if (leaderboard == null || leaderboard.Count == 0) + { + GUILayout.Label(isLoadingLeaderboard ? "Načítám leaderboard..." : "Žádní hráči v leaderboardu", labelStyle); + } + else + { + // Header + GUILayout.BeginHorizontal(); + GUILayout.Label("#", labelStyle, GUILayout.Width(25)); + GUILayout.Label("Hráč", labelStyle, GUILayout.Width(120)); + GUILayout.Label("Výhry", labelStyle, GUILayout.Width(50)); + GUILayout.Label("Win%", labelStyle, GUILayout.Width(50)); + GUILayout.EndHorizontal(); + + // Entries + int rank = 1; + foreach (var entry in leaderboard) + { + GUILayout.BeginHorizontal(); + + // Barvy pro top 3 + if (rank == 1) GUI.color = Color.yellow; + else if (rank == 2) GUI.color = new Color(0.8f, 0.8f, 0.8f); + else if (rank == 3) GUI.color = new Color(0.8f, 0.5f, 0.2f); + else GUI.color = Color.white; + + GUILayout.Label($"{rank}.", labelStyle, GUILayout.Width(25)); + GUILayout.Label(entry.displayName ?? "???", labelStyle, GUILayout.Width(120)); + GUILayout.Label(entry.TotalWins.ToString(), labelStyle, GUILayout.Width(50)); + GUILayout.Label($"{(entry.WinRate * 100):F0}%", labelStyle, GUILayout.Width(50)); + + GUI.color = Color.white; + GUILayout.EndHorizontal(); + rank++; + } + } + + GUILayout.EndScrollView(); + + // Refresh button + GUILayout.Space(5); + if (GUILayout.Button("Obnovit vše", buttonStyle)) + { + RefreshAllStats(); + } + } + + /// + /// Obnoví všechny statistiky (player stats, leaderboard, health) + /// + private void RefreshAllStats() + { + FetchPlayerStats(); + FetchLeaderboard(5); + CheckServerHealth(); + } + + /// + /// Pomocná metoda pro vykreslení řádku statistiky + /// + private void DrawStatRow(string label, string value) + { + GUILayout.BeginHorizontal(); + GUILayout.Label(label, labelStyle, GUILayout.Width(200)); + GUILayout.Label(value, labelStyle); + GUILayout.EndHorizontal(); + } + + #region ═══════════════════════════════════════════════════════════════════ + // LOBBY OBRAZOVKA + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení lobby obrazovky. + /// Zobrazuje seznam hráčů, nastavení a tlačítko start. + /// + protected void DrawLobbyScreen() + { + if (titleStyle == null) InitializeUIStyles(); + + float panelWidth = 600; + float panelHeight = 700; + float panelX = (Screen.width / uiScale - panelWidth) / 2; + float panelY = (Screen.height / uiScale - panelHeight) / 2; + + GUILayout.BeginArea(new Rect(panelX, panelY, panelWidth, panelHeight)); + GUI.Box(new Rect(0, 0, panelWidth, panelHeight), "", boxStyle); + + // ═══════════════════════════════════════════════════════════════════ + // NADPIS A KÓD + // ═══════════════════════════════════════════════════════════════════ + + GUILayout.Space(10); + GUILayout.Label("LOBBY", titleStyle); + + if (client?.JoinCode != null) + { + GUILayout.Label($"Kód: {client.JoinCode}", subtitleStyle); + } + + GUILayout.Space(10); + + // ═══════════════════════════════════════════════════════════════════ + // SEZNAM HRÁČŮ + // ═══════════════════════════════════════════════════════════════════ + + GUILayout.Label("Hráči:", labelStyle); + + playerListScroll = GUILayout.BeginScrollView(playerListScroll, GUILayout.Height(200)); + + if (client?.CurrentLobbyState?.Players != null) + { + foreach (var player in client.CurrentLobbyState.Players) + { + GUILayout.BeginHorizontal(boxStyle); + + // Ikona vlastníka + if (player.IsOwner) + { + GUILayout.Label("👑", GUILayout.Width(25)); + } + else + { + GUILayout.Space(25); + } + + // Jméno hráče + string nameColor = player.ClientUuid == clientUuid ? "yellow" : "white"; + GUILayout.Label($"{player.DisplayName}", richTextStyle); + + // Stav ready + if (player.IsReady) + { + GUI.color = Color.green; + GUILayout.Label("✓ Ready", GUILayout.Width(70)); + GUI.color = Color.white; + } + + GUILayout.EndHorizontal(); + } + } + + GUILayout.EndScrollView(); + + // ═══════════════════════════════════════════════════════════════════ + // NASTAVENÍ LOBBY (pouze pro vlastníka) + // ═══════════════════════════════════════════════════════════════════ + + bool isOwner = client?.IsOwner ?? false; + + GUILayout.Space(10); + GUILayout.Label("Nastavení hry:", labelStyle); + + GUILayout.BeginVertical(boxStyle); + + if (client?.CurrentLobbyState != null) + { + var state = client.CurrentLobbyState; + + GUILayout.Label($"Střed: {state.PlayAreaCenter.Lat:F4}, {state.PlayAreaCenter.Lon:F4}"); + GUILayout.Label($"Poloměr: {state.PlayAreaRadius}m"); + GUILayout.Label($"Impostorů: {state.ImpostorCount}"); + GUILayout.Label($"Heslo: {(state.HasPassword ? "Ano" : "Ne")}"); + } + + GUILayout.EndVertical(); + + // ═══════════════════════════════════════════════════════════════════ + // TLAČÍTKA + // ═══════════════════════════════════════════════════════════════════ + + GUILayout.Space(20); + + if (isOwner) + { + // Tlačítko START (pouze owner) + int playerCount = client?.CurrentLobbyState?.Players?.Count ?? 0; + GUI.enabled = playerCount >= 2; // Minimum 2 hráči + + GUI.color = Color.green; + if (GUILayout.Button($"SPUSTIT HRU ({playerCount} hráčů)", bigButtonStyle)) + { + StartGame(); + } + GUI.color = Color.white; + GUI.enabled = true; + + if (playerCount < 2) + { + GUILayout.Label("Potřeba minimálně 2 hráči", richTextStyle); + } + } + else + { + GUILayout.Label("Čekám na vlastníka lobby...", labelStyle); + } + + GUILayout.Space(10); + + // Tlačítko opuštění + GUI.color = new Color(1f, 0.5f, 0.5f); + if (GUILayout.Button("Opustit lobby", buttonStyle)) + { + LeaveLobby(); + } + GUI.color = Color.white; + + GUILayout.EndArea(); + } + + #region ═══════════════════════════════════════════════════════════════════ + // LOADING OBRAZOVKA + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení loading obrazovky. + /// Zobrazuje progress bar během načítání mapových dat. + /// + protected void DrawLoadingScreen() + { + if (titleStyle == null) InitializeUIStyles(); + + float panelWidth = 400; + float panelHeight = 200; + float panelX = (Screen.width / uiScale - panelWidth) / 2; + float panelY = (Screen.height / uiScale - panelHeight) / 2; + + GUILayout.BeginArea(new Rect(panelX, panelY, panelWidth, panelHeight)); + GUI.Box(new Rect(0, 0, panelWidth, panelHeight), "", boxStyle); + + GUILayout.Space(30); + GUILayout.Label("Načítání hry", titleStyle); + GUILayout.Space(20); + + // Progress bar + Rect progressRect = GUILayoutUtility.GetRect(panelWidth - 40, 30); + progressRect.x = 20; + + GUI.Box(progressRect, ""); + + Rect fillRect = new Rect(progressRect.x + 2, progressRect.y + 2, + (progressRect.width - 4) * loadingProgress, progressRect.height - 4); + GUI.color = Color.green; + GUI.DrawTexture(fillRect, Texture2D.whiteTexture); + GUI.color = Color.white; + + GUILayout.Space(10); + GUILayout.Label(loadingMessage, labelStyle); + + GUILayout.EndArea(); + } + + #region ═══════════════════════════════════════════════════════════════════ + // HERNÍ HUD + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení herního HUD. + /// Zobrazuje roli, úkoly, ovládání a stav hry. + /// + protected void DrawGameHUD() + { + if (titleStyle == null) InitializeUIStyles(); + + // ═══════════════════════════════════════════════════════════════════ + // HORNÍ PANEL - Role a stav + // ═══════════════════════════════════════════════════════════════════ + + GUILayout.BeginArea(new Rect(10, 10, 300, 150)); + GUI.Box(new Rect(0, 0, 300, 150), "", boxStyle); + + // Role + if (client?.MyRole != null) + { + string roleText = client.MyRole == PlayerRole.Impostor ? "IMPOSTOR" : "CREWMATE"; + Color roleColor = client.MyRole == PlayerRole.Impostor ? Color.red : Color.cyan; + + GUI.color = roleColor; + GUILayout.Label(roleText, subtitleStyle); + GUI.color = Color.white; + } + + // Stav (naživu/mrtvý) + if (client?.PlayerPositions != null && client.PlayerPositions.TryGetValue(clientUuid, out var myState)) + { + if (myState.State == PlayerState.Dead) + { + GUI.color = Color.gray; + GUILayout.Label("💀 MRTVÝ (duch)", labelStyle); + GUI.color = Color.white; + } + } + + // Sabotáž varování + if (currentSabotage != null) + { + GUI.color = Color.red; + string sabText = currentSabotage.Type == SabotageType.CriticalMeltdown + ? "⚠ MELTDOWN!" : "⚠ COMMS DOWN!"; + GUILayout.Label(sabText, labelStyle); + + if (currentSabotage.Deadline.HasValue) + { + float remaining = (float)(currentSabotage.Deadline.Value - DateTime.UtcNow).TotalSeconds; + GUILayout.Label($"Zbývá: {remaining:F0}s", labelStyle); + } + GUI.color = Color.white; + } + + // Ping + GUILayout.Label($"Ping: {client?.Ping ?? 0}ms", labelStyle); + + GUILayout.EndArea(); + + // ═══════════════════════════════════════════════════════════════════ + // PRAVÝ PANEL - Úkoly + // ═══════════════════════════════════════════════════════════════════ + + float rightPanelX = Screen.width / uiScale - 260; + GUILayout.BeginArea(new Rect(rightPanelX, 10, 250, 400)); + GUI.Box(new Rect(0, 0, 250, 400), "", boxStyle); + + GUILayout.Label("ÚKOLY", subtitleStyle); + + // Progress bar úkolů + GUILayout.Label($"Dokončeno: {totalTasksCompleted}/{totalTasksRequired}"); + + Rect taskProgressRect = GUILayoutUtility.GetRect(230, 20); + GUI.Box(taskProgressRect, ""); + + if (totalTasksRequired > 0) + { + float taskProgress = (float)totalTasksCompleted / totalTasksRequired; + Rect taskFillRect = new Rect(taskProgressRect.x + 2, taskProgressRect.y + 2, + (taskProgressRect.width - 4) * taskProgress, taskProgressRect.height - 4); + GUI.color = Color.green; + GUI.DrawTexture(taskFillRect, Texture2D.whiteTexture); + GUI.color = Color.white; + } + + GUILayout.Space(10); + + // Seznam úkolů + if (client?.MyTasks != null) + { + foreach (var task in client.MyTasks) + { + bool completed = myCompletedTaskIds.Contains(task.TaskId); + string taskColor = completed ? "green" : "white"; + string checkmark = completed ? "✓ " : "○ "; + + GUILayout.Label($"{checkmark}{task.Name}", richTextStyle); + } + } + + GUILayout.EndArea(); + + // ═══════════════════════════════════════════════════════════════════ + // SPODNÍ PANEL - Akce + // ═══════════════════════════════════════════════════════════════════ + + float bottomPanelY = Screen.height / uiScale - 100; + GUILayout.BeginArea(new Rect(10, bottomPanelY, Screen.width / uiScale - 20, 90)); + + GUILayout.BeginHorizontal(); + + // Tlačítko USE (úkoly, reporty) + GUI.enabled = CanPerformAction(); + if (GUILayout.Button(GetActionButtonText(), bigButtonStyle, GUILayout.Width(150))) + { + PerformPrimaryAction(); + } + GUI.enabled = true; + + GUILayout.Space(20); + + // Tlačítko KILL (pouze impostor) + if (client?.MyRole == PlayerRole.Impostor) + { + string nearbyTarget = client.FindNearbyPlayer(5.0, true); + GUI.enabled = nearbyTarget != null && !IsOnCooldown(); + GUI.color = Color.red; + if (GUILayout.Button("🔪 KILL", bigButtonStyle, GUILayout.Width(120))) + { + if (nearbyTarget != null) + { + AttemptKill(nearbyTarget); + } + } + GUI.color = Color.white; + GUI.enabled = true; + + GUILayout.Space(10); + + // Tlačítko SABOTAGE + GUI.enabled = currentSabotage == null; + if (GUILayout.Button("⚠ SABOTAGE", bigButtonStyle, GUILayout.Width(150))) + { + showSabotagePanel = !showSabotagePanel; + } + GUI.enabled = true; + } + + GUILayout.FlexibleSpace(); + + // Tlačítko MEETING + GUI.enabled = CanCallMeeting(); + if (GUILayout.Button("🔔 MEETING", bigButtonStyle, GUILayout.Width(150))) + { + CallEmergencyMeeting(); + } + GUI.enabled = true; + + GUILayout.EndHorizontal(); + + GUILayout.EndArea(); + + // ═══════════════════════════════════════════════════════════════════ + // SABOTAGE PANEL (popup) + // ═══════════════════════════════════════════════════════════════════ + + if (showSabotagePanel && client?.MyRole == PlayerRole.Impostor) + { + DrawSabotagePanel(); + } + + // ═══════════════════════════════════════════════════════════════════ + // PROGRESS BAR OPRAVY + // ═══════════════════════════════════════════════════════════════════ + + if (isRepairing) + { + DrawProgressBar(); + } + } + + /// + /// Vykreslení panelu sabotáží + /// + private void DrawSabotagePanel() + { + float panelWidth = 200; + float panelHeight = 120; + float panelX = (Screen.width / uiScale - panelWidth) / 2; + float panelY = Screen.height / uiScale - 220; + + GUILayout.BeginArea(new Rect(panelX, panelY, panelWidth, panelHeight)); + GUI.Box(new Rect(0, 0, panelWidth, panelHeight), "", boxStyle); + + GUILayout.Label("Sabotáž", subtitleStyle); + + if (GUILayout.Button("📡 Comms Blackout", buttonStyle)) + { + StartSabotage(SabotageType.CommsBlackout); + showSabotagePanel = false; + } + + if (GUILayout.Button("☢ Critical Meltdown", buttonStyle)) + { + StartSabotage(SabotageType.CriticalMeltdown); + showSabotagePanel = false; + } + + if (GUILayout.Button("Zavřít", buttonStyle)) + { + showSabotagePanel = false; + } + + GUILayout.EndArea(); + } + + /// + /// Vykreslení progress baru pro úkoly/opravy + /// + private void DrawProgressBar() + { + float barWidth = 300; + float barHeight = 30; + float barX = (Screen.width / uiScale - barWidth) / 2; + float barY = Screen.height / uiScale / 2; + + Rect bgRect = new Rect(barX - 10, barY - 10, barWidth + 20, barHeight + 40); + GUI.Box(bgRect, "", boxStyle); + + GUILayout.BeginArea(new Rect(barX, barY, barWidth, barHeight + 20)); + + string label = "Opravuji..."; + GUILayout.Label(label, labelStyle); + + Rect progressRect = GUILayoutUtility.GetRect(barWidth, barHeight); + GUI.Box(progressRect, ""); + + Rect fillRect = new Rect(progressRect.x + 2, progressRect.y + 2, + (progressRect.width - 4) * repairProgress, progressRect.height - 4); + GUI.color = Color.yellow; + GUI.DrawTexture(fillRect, Texture2D.whiteTexture); + GUI.color = Color.white; + + GUILayout.EndArea(); + } + + #region ═══════════════════════════════════════════════════════════════════ + // MEETING PANEL + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení hlasovacího panelu. + /// Zobrazuje seznam hráčů a tlačítka pro hlasování. + /// + protected void DrawMeetingPanel() + { + // Kontrola, zda je meeting aktivní nebo zobrazujeme výsledky + if (currentMeeting == null && !showVotingResults) return; + + // Kontrola herní fáze (povolíme i Playing když zobrazujeme výsledky) + var phase = client?.CurrentLobbyState?.Phase; + bool isInMeeting = phase == GamePhase.Meeting || phase == GamePhase.Voting; + if (!isInMeeting && !showVotingResults) return; + + float panelWidth = 500; + float panelHeight = 600; + float panelX = (Screen.width / uiScale - panelWidth) / 2; + float panelY = (Screen.height / uiScale - panelHeight) / 2; + + GUILayout.BeginArea(new Rect(panelX, panelY, panelWidth, panelHeight)); + GUI.Box(new Rect(0, 0, panelWidth, panelHeight), "", boxStyle); + + // ═══════════════════════════════════════════════════════════════════ + // NADPIS + // ═══════════════════════════════════════════════════════════════════ + + GUILayout.Space(10); + + // Pokud zobrazujeme výsledky, jiný nadpis + if (showVotingResults) + { + GUI.color = Color.yellow; + GUILayout.Label("VÝSLEDKY HLASOVÁNÍ", titleStyle); + GUI.color = Color.white; + } + else if (currentMeeting != null) + { + string meetingType = currentMeeting.Type == MeetingType.BodyReport + ? "TĚLO NALEZENO!" : "EMERGENCY MEETING!"; + GUI.color = Color.red; + GUILayout.Label(meetingType, titleStyle); + GUI.color = Color.white; + } + + // ═══════════════════════════════════════════════════════════════════ + // ČASOVAČ A FÁZE MEETINGU + // ═══════════════════════════════════════════════════════════════════ + + if (currentMeeting != null && !showVotingResults) + { + DateTime now = DateTime.UtcNow; + bool isArrival = now < currentMeeting.ArrivalDeadline; + bool isDiscussion = !isArrival && currentMeeting.DiscussionEndTime.HasValue && now < currentMeeting.DiscussionEndTime.Value; + bool isVoting = !isArrival && !isDiscussion && now < currentMeeting.VotingEndTime; + + // Fáze 1: Příchod na meeting + if (isArrival) + { + float remaining = (float)(currentMeeting.ArrivalDeadline - now).TotalSeconds; + + if (!iArrivedAtMeeting) + { + GUI.color = Color.yellow; + GUILayout.Label($"⚠ BĚŽ NA MEETING! ({remaining:F0}s)", subtitleStyle); + GUI.color = Color.white; + GUILayout.Label("Pokud nedorazíš včas, nebudeš moci hlasovat!", labelStyle); + } + else + { + GUI.color = Color.green; + GUILayout.Label($"✓ Dorazil/a jsi! Čekání: {remaining:F0}s", subtitleStyle); + GUI.color = Color.white; + } + + // Zobraz počet dorazivších + int arrivedCount = arrivedAtMeeting.Count; + int totalAlive = 0; + if (client?.CurrentLobbyState?.Players != null) + { + foreach (var p in client.CurrentLobbyState.Players) + { + if (client.PlayerPositions != null && client.PlayerPositions.TryGetValue(p.ClientUuid, out var info)) + { + if (info.State == PlayerState.Alive) totalAlive++; + } + else + { + totalAlive++; + } + } + } + GUILayout.Label($"Dorazilo: {arrivedCount}/{totalAlive}", labelStyle); + + canVote = false; + } + // Fáze 2: Diskuze + else if (isDiscussion && currentMeeting.DiscussionEndTime.HasValue) + { + float remaining = (float)(currentMeeting.DiscussionEndTime.Value - now).TotalSeconds; + GUILayout.Label($"Diskuze: {remaining:F0}s", subtitleStyle); + canVote = false; + } + // Fáze 3: Hlasování + else if (isVoting) + { + float remaining = (float)(currentMeeting.VotingEndTime - now).TotalSeconds; + GUILayout.Label($"Hlasování: {remaining:F0}s", subtitleStyle); + + // Můžeme hlasovat pouze pokud jsme dorazili a jsme naživu + if (!iArrivedAtMeeting) + { + GUI.color = Color.red; + GUILayout.Label("❌ Nedorazil/a jsi včas - nemůžeš hlasovat!", labelStyle); + GUI.color = Color.white; + canVote = false; + } + else + { + canVote = canVoteInMeeting && myVote == null; + } + } + else + { + GUILayout.Label("Čekám na výsledky...", subtitleStyle); + canVote = false; + } + } + + GUILayout.Space(10); + + // ═══════════════════════════════════════════════════════════════════ + // VÝSLEDKY HLASOVÁNÍ + // ═══════════════════════════════════════════════════════════════════ + + if (showVotingResults && votingResults != null) + { + GUILayout.BeginVertical(boxStyle); + + GUI.color = Color.yellow; + GUILayout.Label("═══ VÝSLEDKY HLASOVÁNÍ ═══", subtitleStyle); + GUI.color = Color.white; + + GUILayout.Space(5); + + if (votingResults.VoteCounts != null) + { + foreach (var kvp in votingResults.VoteCounts) + { + // Server používá "__SKIP__" pro skip vote + string name = (kvp.Key == "__SKIP__" || kvp.Key == "skip") + ? "⏭ Přeskočit" + : $"👤 {GetPlayerName(kvp.Key)}"; + + // Zvýrazníme vyhozeného hráče + if (kvp.Key == votingResults.EjectedPlayerId) + { + GUI.color = Color.red; + GUILayout.Label($"🚪 {name}: {kvp.Value} hlasů", labelStyle); + GUI.color = Color.white; + } + else + { + GUILayout.Label($" {name}: {kvp.Value} hlasů", labelStyle); + } + } + } + + GUILayout.Space(10); + + // Výsledek hlasování + if (votingResults.EjectedPlayerId != null) + { + string ejectedName = GetPlayerName(votingResults.EjectedPlayerId); + GUI.color = Color.red; + GUILayout.Label($"🚪 {ejectedName} byl/a vyhozen/a!", subtitleStyle); + GUI.color = Color.white; + } + else if (votingResults.WasTie) + { + GUI.color = Color.yellow; + GUILayout.Label("⚖ Remíza - nikdo nebyl vyhozen", subtitleStyle); + GUI.color = Color.white; + } + else + { + GUI.color = Color.gray; + GUILayout.Label("✗ Nikdo nebyl vyhozen", subtitleStyle); + GUI.color = Color.white; + } + + GUILayout.EndVertical(); + + GUILayout.Space(10); + + if (Time.time > votingResultsEndTime) + { + showVotingResults = false; + currentMeeting = null; + } + } + + // ═══════════════════════════════════════════════════════════════════ + // SEZNAM HRÁČŮ PRO HLASOVÁNÍ + // ═══════════════════════════════════════════════════════════════════ + + if (!showVotingResults) + { + playerListScroll = GUILayout.BeginScrollView(playerListScroll, GUILayout.Height(350)); + + if (client?.CurrentLobbyState?.Players != null) + { + foreach (var player in client.CurrentLobbyState.Players) + { + // Získáme stav hráče - bezpečný přístup + bool isAlive = true; + if (client.PlayerPositions != null && client.PlayerPositions.TryGetValue(player.ClientUuid, out var pInfo)) + { + isAlive = pInfo.State == PlayerState.Alive; + } + + GUILayout.BeginHorizontal(boxStyle); + + // Ikona stavu + if (!isAlive) + { + GUI.color = Color.gray; + GUILayout.Label("💀", GUILayout.Width(25)); + } + else + { + GUILayout.Label("👤", GUILayout.Width(25)); + } + + // Jméno + string nameColor = player.ClientUuid == clientUuid ? "yellow" : (isAlive ? "white" : "gray"); + GUILayout.Label($"{player.DisplayName}", richTextStyle, GUILayout.Width(150)); + + // Indikátor hlasování + if (meetingVotes.ContainsKey(player.ClientUuid)) + { + GUILayout.Label("✓ Hlasoval", GUILayout.Width(80)); + } + + // Tlačítko hlasování + GUI.enabled = canVote && isAlive && player.ClientUuid != clientUuid; + if (GUILayout.Button("Hlasovat", GUILayout.Width(80))) + { + CastVote(player.ClientUuid); + } + GUI.enabled = true; + + GUI.color = Color.white; + GUILayout.EndHorizontal(); + } + } + + GUILayout.EndScrollView(); + + // ═══════════════════════════════════════════════════════════════ + // TLAČÍTKO SKIP + // ═══════════════════════════════════════════════════════════════ + + GUILayout.Space(10); + + GUI.enabled = canVote; + GUI.color = Color.gray; + if (GUILayout.Button("⏭ Přeskočit hlasování", bigButtonStyle)) + { + CastVote(null); // null = skip + } + GUI.color = Color.white; + GUI.enabled = true; + } + + GUILayout.EndArea(); + } + + #region ═══════════════════════════════════════════════════════════════════ + // KONEC HRY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení obrazovky konce hry. + /// Zobrazuje vítěze a statistiky. + /// + protected void DrawGameEndScreen() + { + if (titleStyle == null) InitializeUIStyles(); + + float panelWidth = 500; + float panelHeight = 400; + float panelX = (Screen.width / uiScale - panelWidth) / 2; + float panelY = (Screen.height / uiScale - panelHeight) / 2; + + GUILayout.BeginArea(new Rect(panelX, panelY, panelWidth, panelHeight)); + GUI.Box(new Rect(0, 0, panelWidth, panelHeight), "", boxStyle); + + GUILayout.Space(20); + + // ═══════════════════════════════════════════════════════════════════ + // VÍTĚZ + // ═══════════════════════════════════════════════════════════════════ + + if (gameEndData != null) + { + // Určíme, zda jsme vyhráli + bool weWon = gameEndData.Winners.Contains(clientUuid); + + if (weWon) + { + GUI.color = Color.green; + GUILayout.Label("🏆 VÍTĚZSTVÍ!", titleStyle); + } + else + { + GUI.color = Color.red; + GUILayout.Label("💔 PROHRA", titleStyle); + } + GUI.color = Color.white; + + GUILayout.Space(20); + + // Vítězná frakce + string faction = gameEndData.WinningFaction == "Impostor" ? "Impostoři" : "Posádka"; + GUILayout.Label($"Vyhráli: {faction}", subtitleStyle); + + GUILayout.Space(10); + + // Důvod + GUILayout.Label($"Důvod: {gameEndData.Reason}", labelStyle); + + GUILayout.Space(20); + + // Seznam vítězů + GUILayout.Label("Vítězové:", labelStyle); + foreach (var winnerId in gameEndData.Winners) + { + string name = GetPlayerName(winnerId); + GUILayout.Label($" • {name}", labelStyle); + } + } + + GUILayout.Space(30); + + // ═══════════════════════════════════════════════════════════════════ + // TLAČÍTKA + // ═══════════════════════════════════════════════════════════════════ + + // Pouze owner může restartovat hru + bool isOwner = client?.IsOwner ?? false; + + if (isOwner) + { + if (GUILayout.Button("🔄 Nová hra (zpět do lobby)", bigButtonStyle)) + { + // Pošleme serveru požadavek na návrat do lobby + client?.ReturnToLobby(); + } + } + else + { + GUI.enabled = false; + GUILayout.Button("Čekám na hostitele...", bigButtonStyle); + GUI.enabled = true; + } + + GUILayout.Space(10); + + if (GUILayout.Button("Hlavní menu", buttonStyle)) + { + LeaveLobby(); + gameEndData = null; + } + + GUILayout.EndArea(); + } + + #region ═══════════════════════════════════════════════════════════════════ + // NOTIFIKACE A CHYBY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Vykreslení notifikací + /// + protected void DrawNotifications() + { + if (currentNotification.message == null) return; + + float notifWidth = 400; + float notifHeight = 60; + float notifX = (Screen.width / uiScale - notifWidth) / 2; + float notifY = 50; + + // Fade efekt + float remaining = notificationEndTime - Time.time; + float alpha = Mathf.Clamp01(remaining); + + Color bgColor = currentNotification.color; + bgColor.a = alpha * 0.9f; + + GUI.color = bgColor; + GUI.Box(new Rect(notifX, notifY, notifWidth, notifHeight), "", notificationStyle); + + GUI.color = new Color(1, 1, 1, alpha); + GUI.Label(new Rect(notifX, notifY, notifWidth, notifHeight), + $"{currentNotification.icon} {currentNotification.message}", notificationStyle); + + GUI.color = Color.white; + } + + /// + /// Vykreslení chybové zprávy + /// + protected void DrawErrorMessage() + { + if (string.IsNullOrEmpty(errorMessage) || Time.time > errorMessageEndTime) + { + errorMessage = null; + return; + } + + float errorWidth = 500; + float errorHeight = 40; + float errorX = (Screen.width / uiScale - errorWidth) / 2; + float errorY = Screen.height / uiScale - 60; + + GUI.color = new Color(0.8f, 0.2f, 0.2f, 0.9f); + GUI.Box(new Rect(errorX, errorY, errorWidth, errorHeight), "", notificationStyle); + + GUI.color = Color.white; + GUI.Label(new Rect(errorX, errorY, errorWidth, errorHeight), + $"⚠ {errorMessage}", notificationStyle); + } + + #region ═══════════════════════════════════════════════════════════════════ + // POMOCNÉ UI METODY + // ════════════════════════════════════════════════════════════════════════ + #endregion + + /// + /// Získá text pro hlavní akční tlačítko + /// + private string GetActionButtonText() + { + // Kontrola těla poblíž + var body = client?.FindNearbyBody(5.0); + if (body != null) return "🚨 REPORT"; + + // Kontrola úkolu poblíž + var task = client?.FindNearbyTask(5.0); + if (task != null) return "✋ USE"; + + // Kontrola opravné stanice poblíž + if (currentSabotage != null) + { + var station = FindNearbyRepairStation(5.0); + if (station != null) return "🔧 REPAIR"; + } + + return "USE"; + } + + /// + /// Zjistí, zda můžeme provést akci + /// + private bool CanPerformAction() + { + if (client == null) return false; + + // Zjistíme, jestli jsme duch + bool isGhost = false; + if (client.PlayerPositions != null && client.PlayerPositions.TryGetValue(clientUuid, out var playerInfo)) + { + isGhost = playerInfo.State != PlayerState.Alive; + } + + // Duchové NEMOHOU reportovat těla ani volat meeting + // Ale MOHOU plnit úkoly! + if (!isGhost && client.FindNearbyBody(5.0) != null) return true; + + // Kontrola úkolu - duchové i živí crew mohou dělat úkoly + if (client.FindNearbyTask(5.0) != null && client.MyRole == PlayerRole.Crew) return true; + + // Kontrola opravné stanice - pouze živí mohou opravovat + if (!isGhost && currentSabotage != null && FindNearbyRepairStation(5.0) != null) return true; + + return false; + } + + /// + /// Zjistí, zda můžeme svolat meeting + /// + private bool CanCallMeeting() + { + if (client == null) return false; + if (currentSabotage?.Type == SabotageType.CommsBlackout) return false; + + // Kontrola stavu hráče - bezpečný přístup + if (client.PlayerPositions != null && client.PlayerPositions.TryGetValue(clientUuid, out var playerInfo)) + { + if (playerInfo.State != PlayerState.Alive) + return false; + } + + return true; + } + + /// + /// Zjistí, zda je kill na cooldownu + /// + private bool IsOnCooldown() + { + // TODO: Implementovat cooldown tracking + return false; + } +} diff --git a/Assets/UnityTestClient/UnityTestClient_UI.cs.meta b/Assets/UnityTestClient/UnityTestClient_UI.cs.meta new file mode 100644 index 0000000..d3b81d8 --- /dev/null +++ b/Assets/UnityTestClient/UnityTestClient_UI.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ebca6f90ee582ea448b7a028626d8636 \ No newline at end of file diff --git a/Packages/manifest.json b/Packages/manifest.json new file mode 100644 index 0000000..7e42b3d --- /dev/null +++ b/Packages/manifest.json @@ -0,0 +1,48 @@ +{ + "dependencies": { + "com.unity.ai.navigation": "2.0.9", + "com.unity.collab-proxy": "2.9.3", + "com.unity.ide.rider": "3.0.38", + "com.unity.ide.visualstudio": "2.0.23", + "com.unity.inputsystem": "1.14.2", + "com.unity.multiplayer.center": "1.0.0", + "com.unity.nuget.newtonsoft-json": "3.2.2", + "com.unity.render-pipelines.universal": "17.2.0", + "com.unity.test-framework": "1.6.0", + "com.unity.timeline": "1.8.9", + "com.unity.ugui": "2.0.0", + "com.unity.visualscripting": "1.9.7", + "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json new file mode 100644 index 0000000..c4507fb --- /dev/null +++ b/Packages/packages-lock.json @@ -0,0 +1,472 @@ +{ + "dependencies": { + "com.unity.ai.navigation": { + "version": "2.0.9", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.ai": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.burst": { + "version": "1.8.25", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.collab-proxy": { + "version": "2.9.3", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.collections": { + "version": "2.5.7", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.8.19", + "com.unity.mathematics": "1.3.2", + "com.unity.test-framework": "1.4.6", + "com.unity.nuget.mono-cecil": "1.11.5", + "com.unity.test-framework.performance": "3.0.3" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "2.0.5", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.ide.rider": { + "version": "3.0.38", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.23", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, + "com.unity.inputsystem": { + "version": "1.14.2", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.mathematics": { + "version": "1.3.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.multiplayer.center": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + } + }, + "com.unity.nuget.mono-cecil": { + "version": "1.11.5", + "depth": 3, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.newtonsoft-json": { + "version": "3.2.2", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.render-pipelines.core": { + "version": "17.2.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.burst": "1.8.14", + "com.unity.mathematics": "1.3.2", + "com.unity.ugui": "2.0.0", + "com.unity.collections": "2.4.3", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.rendering.light-transport": "1.0.1" + } + }, + "com.unity.render-pipelines.universal": { + "version": "17.2.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.2.0", + "com.unity.shadergraph": "17.2.0", + "com.unity.render-pipelines.universal-config": "17.0.3" + } + }, + "com.unity.render-pipelines.universal-config": { + "version": "17.0.3", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.0.3" + } + }, + "com.unity.rendering.light-transport": { + "version": "1.0.1", + "depth": 2, + "source": "builtin", + "dependencies": { + "com.unity.collections": "2.2.0", + "com.unity.mathematics": "1.2.4", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.searcher": { + "version": "4.9.3", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.shadergraph": { + "version": "17.2.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.2.0", + "com.unity.searcher": "4.9.3" + } + }, + "com.unity.test-framework": { + "version": "1.6.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.ext.nunit": "2.0.3", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.test-framework.performance": { + "version": "3.2.0", + "depth": 3, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.33", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.timeline": { + "version": "1.8.9", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ugui": { + "version": "2.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.visualscripting": { + "version": "1.9.7", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.modules.accessibility": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.hierarchycore": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.hierarchycore": "1.0.0", + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/ProjectSettings/AudioManager.asset b/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..27287fe --- /dev/null +++ b/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 0 diff --git a/ProjectSettings/ClusterInputManager.asset b/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..fc90ab9 --- /dev/null +++ b/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0.1 + m_ClothInterCollisionStiffness: 0.2 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ClothGravity: {x: 0, y: -9.81, z: 0} + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_SolverType: 0 + m_DefaultMaxAngularSpeed: 50 diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..d057ba3 --- /dev/null +++ b/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,13 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: + - enabled: 1 + path: Assets/Scenes/SampleScene.unity + guid: 99c9720ab356a0642a771bea13969a05 + m_configObjects: + com.unity.input.settings.actions: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_UseUCBPForAssetBundles: 0 diff --git a/ProjectSettings/EditorSettings.asset b/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..878c4cb --- /dev/null +++ b/ProjectSettings/EditorSettings.asset @@ -0,0 +1,50 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 15 + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 0 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerCacheSize: 10 + m_SpritePackerPaddingPower: 1 + m_Bc7TextureCompressor: 0 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref + m_ProjectGenerationRootNamespace: + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_EnableEditorAsyncCPUTextureLoading: 0 + m_AsyncShaderCompilation: 1 + m_PrefabModeAllowAutoSave: 1 + m_EnterPlayModeOptionsEnabled: 1 + m_EnterPlayModeOptions: 0 + m_GameObjectNamingDigits: 1 + m_GameObjectNamingScheme: 0 + m_AssetNamingUsesSpace: 1 + m_InspectorUseIMGUIDefaultInspector: 0 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 + m_DisableCookiesInLightmapper: 0 + m_ShadowmaskStitching: 0 + m_AssetPipelineMode: 1 + m_RefreshImportMode: 0 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 + m_CacheServerEnableAuth: 0 + m_CacheServerEnableTls: 0 + m_CacheServerValidationMode: 2 + m_CacheServerDownloadBatchSize: 128 + m_EnableEnlightenBakedGI: 0 + m_ReferencedClipsExactNaming: 1 + m_ForceAssetUnloadAndGCOnSceneLoad: 1 diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..3a1a7b3 --- /dev/null +++ b/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,68 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 16 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_VideoShadersIncludeMode: 2 + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 24, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_PreloadShadersBatchTimeLimit: -1 + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} + m_CustomRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, type: 2} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_BrgStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_RenderPipelineGlobalSettingsMap: + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 18dc0cd2c080841dea60987a38ce93fa, type: 2} + m_LightsUseLinearIntensity: 1 + m_LightsUseColorTemperature: 1 + m_LogWhenShaderIsCompiled: 0 + m_LightProbeOutsideHullStrategy: 0 + m_CameraRelativeLightCulling: 0 + m_CameraRelativeShadowCulling: 0 diff --git a/ProjectSettings/InputManager.asset b/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..b16147e --- /dev/null +++ b/ProjectSettings/InputManager.asset @@ -0,0 +1,487 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: joystick button 8 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: backspace + altNegativeButton: + altPositiveButton: joystick button 9 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Reset + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Next + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page down + altNegativeButton: + altPositiveButton: joystick button 5 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Previous + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page up + altNegativeButton: + altPositiveButton: joystick button 4 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Validate + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Persistent + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: right shift + altNegativeButton: + altPositiveButton: joystick button 2 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Multiplier + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: joystick button 3 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 6 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 5 + joyNum: 0 diff --git a/ProjectSettings/MemorySettings.asset b/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/ProjectSettings/MultiplayerManager.asset b/ProjectSettings/MultiplayerManager.asset new file mode 100644 index 0000000..2a93664 --- /dev/null +++ b/ProjectSettings/MultiplayerManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!655991488 &1 +MultiplayerManager: + m_ObjectHideFlags: 0 + m_EnableMultiplayerRoles: 0 + m_StrippingTypes: {} diff --git a/ProjectSettings/NavMeshAreas.asset b/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..3b0b7c3 --- /dev/null +++ b/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..be4a797 --- /dev/null +++ b/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreviewPackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_ErrorMessage: + m_Original: + m_Id: + m_Name: + m_Url: + m_Scopes: [] + m_IsDefault: 0 + m_Capabilities: 0 + m_Modified: 0 + m_Name: + m_Url: + m_Scopes: + - + m_SelectedScopeIndex: 0 diff --git a/ProjectSettings/Physics2DSettings.asset b/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..6c5cf8a --- /dev/null +++ b/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 0 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/ProjectSettings/PresetManager.asset b/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..346db83 --- /dev/null +++ b/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,943 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 28 + productGUID: 786a0f5e10d1d11479dc64c9b196a360 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: GeoSusTestClient + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1024 + defaultScreenHeight: 768 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 1 + unsupportedMSAAFallback: 0 + m_SpriteBatchMaxVertexCount: 65535 + m_SpriteBatchVertexThreshold: 300 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 0 + androidDisplayOptions: 1 + androidBlitType: 0 + androidResizeableActivity: 1 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + androidAutoRotationBehavior: 1 + androidPredictiveBackSupport: 1 + androidApplicationEntry: 2 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 1 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + audioSpatialExperience: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + dedicatedServerOptimizations: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + meshDeformation: 2 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 3 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 1048576 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + switchMaxWorkerMultiple: 8 + switchNVNGraphicsFirmwareMemory: 32 + switchGraphicsJobsSyncAfterKick: 1 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 1 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 + visionOSBundleVersion: 1.0 + tvOSBundleVersion: 1.0 + bundleVersion: 0.1.0 + preloadedAssets: + - {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3} + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 + useHDRDisplay: 0 + hdrBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.4 + androidMinAspectRatio: 1 + applicationIdentifier: + Android: com.UnityTechnologies.com.unity.template.urpblank + Standalone: com.Unity-Technologies.com.unity.template.urp-blank + iPhone: com.Unity-Technologies.com.unity.template.urp-blank + buildNumber: + Standalone: 0 + VisionOS: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 1 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 23 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + androidSplitApplicationBinary: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 0 + strictShaderVariantMatching: 0 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSSimulatorArchitecture: 0 + iOSTargetOSVersionString: 13.0 + tvOSSdkVersion: 0 + tvOSSimulatorArchitecture: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 13.0 + VisionOSSdkVersion: 0 + VisionOSTargetOSVersionString: 1.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + metalCompileShaderBinary: 0 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + VisionOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: 3c72c65a16f0acb438eed22b8b16c24a + templatePackageId: com.unity.template.urp-blank@17.0.14 + templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 2 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 + AndroidEnableArm64MTE: 0 + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + androidAppCategory: 3 + useAndroidAppCategory: 1 + androidAppCategoryOther: + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + AndroidReportGooglePlayAppDependencies: 1 + androidSymbolsSizeThreshold: 800 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: iPhone + m_Icons: + - m_Textures: [] + m_Width: 180 + m_Height: 180 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 167 + m_Height: 167 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 152 + m_Height: 152 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 76 + m_Height: 76 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 87 + m_Height: 87 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 60 + m_Height: 60 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 20 + m_Height: 20 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 4 + m_SubKind: App Store + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: + - m_BuildTarget: tvOS + m_Icons: + - m_Textures: [] + m_Width: 1280 + m_Height: 768 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 800 + m_Height: 480 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 400 + m_Height: 240 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 4640 + m_Height: 1440 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 2320 + m_Height: 720 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 3840 + m_Height: 1440 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 1920 + m_Height: 720 + m_Kind: 1 + m_SubKind: + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: [] + m_BuildTargetGraphicsJobMode: [] + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AndroidPlayer + m_APIs: 150000000b000000 + m_Automatic: 0 + m_BuildTargetVRSettings: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: + - serializedVersion: 2 + m_BuildTarget: Android + m_EncodingQuality: 1 + m_BuildTargetGroupHDRCubemapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: + - m_BuildTarget: Android + m_Encoding: 1 + m_BuildTargetDefaultTextureCompressionFormat: + - serializedVersion: 3 + m_BuildTarget: Android + m_Formats: 03000000 + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + editorGfxJobOverride: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 11.0 + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchCompilerFlags: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchDisableHTCSPlayerConnection: 0 + switchUseNewStyleFilepaths: 0 + switchUseLegacyFmodPriorities: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + switchUpgradedPlayerSettingsToNMETA: 0 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 2 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 2 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 32 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 0 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLPowerPreference: 2 + webGLWebAssemblyTable: 0 + webGLWebAssemblyBigInt: 0 + webGLCloseOnQuit: 0 + webWasm2023: 0 + webEnableSubmoduleStrippingCompatibility: 0 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: + Android: 1 + il2cppCompilerConfiguration: {} + il2cppCodeGeneration: {} + il2cppStacktraceInformation: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + editorAssembliesCompatibilityLevel: 1 + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: GeoSusTestClient + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: GeoSusTestClient + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + syncCapabilities: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: {} + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + hmiPlayerDataPath: + hmiForceSRGBBlit: 1 + embeddedLinuxEnableGamepadInput: 0 + hmiCpuConfiguration: + hmiLogStartupTiming: 0 + qnxGraphicConfPath: + apiCompatibilityLevel: 6 + captureStartupLogs: {} + activeInputHandler: 0 + windowsGamepadBackendHint: 0 + cloudProjectId: 8a417728-efd8-4f20-8f11-a7b1c9ae4cd1 + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: GeoSusTestClient + organizationId: unity_dvyy2bhl4lcthq + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 + androidVulkanDenyFilterList: [] + androidVulkanAllowFilterList: [] + androidVulkanDeviceFilterListAsset: {fileID: 0} + d3d12DeviceFilterListAsset: {fileID: 0} diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..a9844fe --- /dev/null +++ b/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 6000.2.8f1 +m_EditorVersionWithRevision: 6000.2.8f1 (c9992ac36c34) diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..f55198a --- /dev/null +++ b/ProjectSettings/QualitySettings.asset @@ -0,0 +1,134 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 1 + m_QualitySettings: + - serializedVersion: 4 + name: Mobile + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 11400000, guid: 5e6cbd92db86f4b18aec3ed561671858, + type: 2} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: + - Standalone + - serializedVersion: 4 + name: PC + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 2 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 2 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, + type: 2} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: + - Android + - iPhone + m_TextureMipmapLimitGroupNames: [] + m_PerPlatformDefaultQuality: + Android: 0 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Lumin: 0 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + Server: 0 + Stadia: 0 + Standalone: 1 + WebGL: 0 + Windows Store Apps: 0 + XboxOne: 0 + iPhone: 0 + tvOS: 0 diff --git a/ProjectSettings/SceneTemplateSettings.json b/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..ede5887 --- /dev/null +++ b/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,121 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "defaultInstantiationMode": 0 + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "defaultInstantiationMode": 1 + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/ProjectSettings/ShaderGraphSettings.asset b/ProjectSettings/ShaderGraphSettings.asset new file mode 100644 index 0000000..ce8c243 --- /dev/null +++ b/ProjectSettings/ShaderGraphSettings.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de02f9e1d18f588468e474319d09a723, type: 3} + m_Name: + m_EditorClassIdentifier: + shaderVariantLimit: 128 + overrideShaderVariantLimit: 0 + customInterpolatorErrorThreshold: 32 + customInterpolatorWarningThreshold: 16 + customHeatmapValues: {fileID: 0} diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..6413d11 --- /dev/null +++ b/ProjectSettings/TagManager.asset @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 + m_RenderingLayers: + - Default + - Light Layer 1 + - Light Layer 2 + - Light Layer 3 + - Light Layer 4 + - Light Layer 5 + - Light Layer 6 + - Light Layer 7 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - diff --git a/ProjectSettings/TimeManager.asset b/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..558a017 --- /dev/null +++ b/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/ProjectSettings/URPProjectSettings.asset b/ProjectSettings/URPProjectSettings.asset new file mode 100644 index 0000000..64a8674 --- /dev/null +++ b/ProjectSettings/URPProjectSettings.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 247994e1f5a72c2419c26a37e9334c01, type: 3} + m_Name: + m_EditorClassIdentifier: + m_LastMaterialVersion: 10 diff --git a/ProjectSettings/UnityConnectSettings.asset b/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..7a17e8f --- /dev/null +++ b/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,40 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 1 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + InsightsSettings: + m_EngineDiagnosticsEnabled: 1 + m_Enabled: 0 + CrashReportingSettings: + serializedVersion: 2 + m_EventUrl: https://perf-events.cloud.unity3d.com + m_EnableCloudDiagnosticsReporting: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/ProjectSettings/VFXManager.asset b/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..3a95c98 --- /dev/null +++ b/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/ProjectSettings/VersionControlSettings.asset b/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/ProjectSettings/XRSettings.asset b/ProjectSettings/XRSettings.asset new file mode 100644 index 0000000..482590c --- /dev/null +++ b/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file