From e13975e6539c6b465a531b3f836d2f64f3563de8 Mon Sep 17 00:00:00 2001 From: stho Date: Fri, 10 Oct 2025 12:19:07 +0200 Subject: [PATCH 01/26] server code by claude --- CLAUDE.md | 138 +++++ hearts_game_instructions.txt | 82 +++ .../Games/Hearts/HeartsMessages.cs | 19 + .../Games/Hearts/HeartsNotifications.cs | 73 +++ .../Games/Hearts/PlayerViewOfGame.cs | 52 ++ src/Deckster.Games/Hearts/HeartsGame.cs | 560 ++++++++++++++++++ .../Hearts/HeartsGameCreatedEvent.cs | 9 + .../Hearts/HeartsGameStartedEvent.cs | 6 + src/Deckster.Games/Hearts/HeartsPlayer.cs | 31 + .../Games/Hearts/HeartsGameHost.cs | 20 + .../Games/Hearts/HeartsProjection.cs | 32 + 11 files changed, 1022 insertions(+) create mode 100644 CLAUDE.md create mode 100644 hearts_game_instructions.txt create mode 100644 src/Deckster.Core/Games/Hearts/HeartsMessages.cs create mode 100644 src/Deckster.Core/Games/Hearts/HeartsNotifications.cs create mode 100644 src/Deckster.Core/Games/Hearts/PlayerViewOfGame.cs create mode 100644 src/Deckster.Games/Hearts/HeartsGame.cs create mode 100644 src/Deckster.Games/Hearts/HeartsGameCreatedEvent.cs create mode 100644 src/Deckster.Games/Hearts/HeartsGameStartedEvent.cs create mode 100644 src/Deckster.Games/Hearts/HeartsPlayer.cs create mode 100644 src/Deckster.Server/Games/Hearts/HeartsGameHost.cs create mode 100644 src/Deckster.Server/Games/Hearts/HeartsProjection.cs diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..1908b9ca --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,138 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Deckster is a multi-platform card game framework built with .NET 9. It provides a WebSocket-based server architecture for hosting multiplayer card games with clients available in C# (.NET), Swift (iOS), and Kotlin (Android). + +## Commands + +### Building +```bash +# Build the entire solution +build.bat +# Or manually: +cd src/Deckster.Server +dotnet restore +dotnet build +``` + +### Running the Server +```bash +# Run the server +server.bat +# Or manually: +cd src/Deckster.Server +dotnet run +``` + +### Running Tests +```bash +# Run all tests +dotnet test src/Deckster.UnitTests/Deckster.UnitTests.csproj + +# Run tests with detailed output +dotnet test src/Deckster.UnitTests/Deckster.UnitTests.csproj --logger "console;verbosity=detailed" +``` + +### Running Sample Clients +Sample clients for different games can be run using the provided shell scripts or directly: +```bash +# Using convenience scripts (bash): +./crazyeights.sh +./chatroom.sh +./idiot.sh +./bullshit.sh + +# Or manually: +cd src/Deckster.[GameName].SampleClient +dotnet run +``` + +### Code Generation +The project uses OpenAPI/Swagger for code generation: +```bash +# Server generates OpenAPI spec at runtime +# Check decksterapi.yml and generated/ directory for OpenAPI outputs + +# Run code generator +cd src/Deckster.CodeGenerator +dotnet run +``` + +## Architecture + +### Multi-Layered Solution Structure + +The solution is organized into logical folders: +- **10. Server**: `Deckster.Server` - ASP.NET Core WebSocket server +- **15. Sample clients**: Multiple `Deckster.[GameName].SampleClient` projects demonstrating client implementation +- **20. Libs**: Core libraries (`Deckster.Core`, `Deckster.Client`, `Deckster.Games`) +- **30. Code generation**: `Deckster.CodeGenerator` and generated client code +- **90. Tests**: `Deckster.UnitTests` with NUnit + +### Core Components + +**Deckster.Core**: Shared data models, protocol definitions, serialization, and authentication models. Used by both server and clients. + +**Deckster.Server**: ASP.NET Core server hosting multiple card games. Contains: +- WebSocket communication layer (`Communication/IServerChannel`, `Communication/WebSocketServerChannel`) +- Game implementations in `Games/` directory +- Controllers for REST API endpoints +- Authentication middleware +- Swagger/OpenAPI integration + +**Deckster.Client**: .NET client library for connecting to Deckster servers. Provides: +- `DecksterClient` - Main client class with authentication +- `GameClient` - Base class for game-specific clients +- Generated game clients (`.g.cs` files) in `Games/` subdirectories + +**Deckster.Games**: Game logic and state management, shared between server and clients. Each game (CrazyEights, Uno, ChatRoom, Gabong, Idiot, Yaniv, TexasHoldEm, Bullshit) has its own subdirectory. + +### Communication Protocol + +The server uses a dual WebSocket architecture: +1. **Action Socket**: Request/response pattern for client actions +2. **Notification Socket**: Asynchronous push notifications from server + +Connection handshake: +1. Client initiates join (establishes action socket) +2. Client sends finish join (establishes notification socket) + +Disconnect procedures differ based on who initiates: +- **Client disconnect**: Client closes action socket with "Client disconnected" message +- **Server disconnect**: Server closes notification socket with "Server disconnected" message + +See README.md diagrams for detailed connection/disconnection flows. + +### Multi-Platform Support + +- **.NET**: `Deckster.Client` NuGet package +- **iOS**: Swift package defined in `Package.swift`, source in `ios/Sources/` +- **Android**: Kotlin library in `android/decksterlib/`, built with Gradle + +Code generation from OpenAPI spec creates platform-specific clients. + +### Code Generation + +- `Deckster.CodeGenerator` generates client code from the server's API +- Generated code appears in `generated/` directory +- The `Deckster.Generated.Client` project contains generated .NET clients +- Mobile platforms have their own generation scripts (`android/generate-code-from-openapi.sh`) + +## Dependencies + +- **.NET 9.0** +- **NUnit** (testing) +- **Marten** (document database for server) +- **Swashbuckle.AspNetCore** (OpenAPI/Swagger) +- **System.Text.Json** (serialization) + +## Project References + +The server references all sample clients for demonstration purposes. When adding new games: +1. Create game logic in `Deckster.Games` +2. Add server-side implementation in `Deckster.Server/Games` +3. Generate client code using `Deckster.CodeGenerator` +4. Create sample client project following naming pattern `Deckster.[GameName].SampleClient` diff --git a/hearts_game_instructions.txt b/hearts_game_instructions.txt new file mode 100644 index 00000000..13862036 --- /dev/null +++ b/hearts_game_instructions.txt @@ -0,0 +1,82 @@ +Of course 👍 +Here’s the English version of the same instructions — written clearly and precisely so another AI or engine can use it to recreate the classic Windows Hearts card game logic: + +🧭 Summary for AI Instructions: + +Create a digital card game that follows the rules of Microsoft Hearts (Windows 95–XP version). + +Basic Rules + +4 players (1 human + 3 computer opponents) + +Standard 52-card deck, 13 cards dealt to each player + +Goal: finish with the lowest total score + +Game ends when any player reaches 100 points — lowest total wins + +Passing Cards + +Round 1: pass 3 cards to the left + +Round 2: pass 3 cards to the right + +Round 3: pass 3 cards across (opposite player) + +Round 4: no passing + +Then repeat this 4-round cycle + +Gameplay + +Player holding ♣2 (Two of Clubs) starts the first trick + +Players must follow suit if possible + +If unable to follow suit: + +They may play any other card + +But hearts (♥) cannot be played until hearts are “broken” + +Breaking Hearts + +Hearts are “broken” the first time any heart is played because a player couldn’t follow suit + +After that, hearts can be played at any time + +Scoring + +Each heart (♥) = 1 point + +Queen of Spades (♠Q) = 13 points + +Total possible points per hand: 26 + +Shooting the Moon + +If a player captures all 13 hearts + the Queen of Spades, then: + +All other players receive +26 points (default Windows rule) + +(Optional alternative rule: the shooter gets −26 points) + +Trick Resolution + +Highest card of the lead suit wins the trick + +Trick winner leads the next round + +Round End + +After 13 tricks, total up points for each player + +Continue with the next round (apply the next pass direction) + +Game End + +When a player’s total score ≥ 100, the game ends + +The player with the lowest total score wins + +Would you like me to make a technical spec version next — something formatted like a design document or pseudocode outline for implementing the logic? \ No newline at end of file diff --git a/src/Deckster.Core/Games/Hearts/HeartsMessages.cs b/src/Deckster.Core/Games/Hearts/HeartsMessages.cs new file mode 100644 index 00000000..b3801400 --- /dev/null +++ b/src/Deckster.Core/Games/Hearts/HeartsMessages.cs @@ -0,0 +1,19 @@ +using Deckster.Core.Games.Common; +using Deckster.Core.Protocol; + +namespace Deckster.Core.Games.Hearts; + +public class PassCardsRequest : DecksterRequest +{ + public required List Cards { get; set; } +} + +public class PlayCardRequest : DecksterRequest +{ + public required Card Card { get; set; } +} + +public class PassCardsResponse : DecksterResponse +{ + public List? ReceivedCards { get; init; } +} diff --git a/src/Deckster.Core/Games/Hearts/HeartsNotifications.cs b/src/Deckster.Core/Games/Hearts/HeartsNotifications.cs new file mode 100644 index 00000000..1534fb51 --- /dev/null +++ b/src/Deckster.Core/Games/Hearts/HeartsNotifications.cs @@ -0,0 +1,73 @@ +using Deckster.Core.Games.Common; +using Deckster.Core.Protocol; + +namespace Deckster.Core.Games.Hearts; + +public class GameStartedNotification : DecksterNotification +{ + public Guid GameId { get; init; } + public PlayerViewOfGame PlayerViewOfGame { get; init; } = new(); +} + +public class PassingPhaseStartedNotification : DecksterNotification +{ + public PassDirection PassDirection { get; init; } +} + +public class AllPlayersPassedNotification : DecksterNotification +{ + public List ReceivedCards { get; init; } = []; +} + +public class PlayerPassedCardsNotification : DecksterNotification +{ + public Guid PlayerId { get; init; } +} + +public class ItsYourTurnNotification : DecksterNotification +{ + public PlayerViewOfGame PlayerViewOfGame { get; init; } = new(); +} + +public class ItsPlayersTurnNotification : DecksterNotification +{ + public Guid PlayerId { get; init; } +} + +public class PlayerPlayedCardNotification : DecksterNotification +{ + public Guid PlayerId { get; init; } + public required Card Card { get; init; } +} + +public class TrickCompletedNotification : DecksterNotification +{ + public Guid WinnerId { get; init; } + public required string WinnerName { get; init; } + public List TrickCards { get; init; } = []; + public int Points { get; init; } +} + +public class RoundEndedNotification : DecksterNotification +{ + public required List Scores { get; init; } + public Guid? MoonShooterId { get; init; } + public string? MoonShooterName { get; init; } +} + +public class GameEndedNotification : DecksterNotification +{ + public required List FinalScores { get; init; } + public Guid WinnerId { get; init; } + public required string WinnerName { get; init; } +} + +public class HeartsAreBrokenNotification : DecksterNotification; + +public class PlayerScore +{ + public Guid PlayerId { get; init; } + public required string PlayerName { get; init; } + public int RoundScore { get; init; } + public int TotalScore { get; init; } +} diff --git a/src/Deckster.Core/Games/Hearts/PlayerViewOfGame.cs b/src/Deckster.Core/Games/Hearts/PlayerViewOfGame.cs new file mode 100644 index 00000000..158791a1 --- /dev/null +++ b/src/Deckster.Core/Games/Hearts/PlayerViewOfGame.cs @@ -0,0 +1,52 @@ +using Deckster.Core.Games.Common; +using Deckster.Core.Protocol; + +namespace Deckster.Core.Games.Hearts; + +public class PlayerViewOfGame : DecksterResponse +{ + public List Cards { get; init; } = []; + public List OtherPlayers { get; init; } = []; + public int RoundNumber { get; init; } + public PassDirection PassDirection { get; init; } + public bool HasPassed { get; init; } + public List CurrentTrick { get; init; } = []; + public int TotalScore { get; init; } + public int RoundScore { get; init; } + public bool HeartsAreBroken { get; init; } + public bool IsMyTurn { get; init; } + + public PlayerViewOfGame() + { + } + + public PlayerViewOfGame(string error) + { + Error = error; + } +} + +public class OtherHeartsPlayer +{ + public Guid PlayerId { get; init; } + public required string Name { get; init; } + public int NumberOfCards { get; init; } + public int TotalScore { get; init; } + public int RoundScore { get; init; } + public Card? PlayedCard { get; init; } +} + +public class CardPlay +{ + public Guid PlayerId { get; init; } + public required string PlayerName { get; init; } + public required Card Card { get; init; } +} + +public enum PassDirection +{ + None, + Left, + Right, + Across +} diff --git a/src/Deckster.Games/Hearts/HeartsGame.cs b/src/Deckster.Games/Hearts/HeartsGame.cs new file mode 100644 index 00000000..fa0c6111 --- /dev/null +++ b/src/Deckster.Games/Hearts/HeartsGame.cs @@ -0,0 +1,560 @@ +using System.Diagnostics.CodeAnalysis; +using Deckster.Core.Collections; +using Deckster.Core.Games.Common; +using Deckster.Core.Games.Hearts; + +namespace Deckster.Games.Hearts; + +public class HeartsGame : GameObject +{ + public event NotifyPlayer? GameStarted; + public event NotifyAll? PassingPhaseStarted; + public event NotifyPlayer? AllPlayersPassed; + public event NotifyAll? PlayerPassedCards; + public event NotifyPlayer? ItsYourTurn; + public event NotifyAll? ItsPlayersTurn; + public event NotifyAll? PlayerPlayedCard; + public event NotifyAll? TrickCompleted; + public event NotifyAll? RoundEnded; + public event NotifyAll? GameEnded; + public event NotifyAll? HeartsWereBroken; + + public List Deck { get; init; } = []; + public List Players { get; init; } = []; + public int CurrentPlayerIndex { get; set; } + public int RoundNumber { get; set; } = 1; + public bool HeartsAreBroken { get; set; } + public List CurrentTrick { get; init; } = []; + public Suit? LeadSuit { get; set; } + public bool IsFirstTrick { get; set; } = true; + public GamePhase Phase { get; set; } = GamePhase.Passing; + + protected override GameState GetState() + { + return Players.Any(p => p.TotalScore >= 100) ? GameState.Finished : GameState.Running; + } + + public HeartsPlayer CurrentPlayer => Phase == GamePhase.Playing ? Players[CurrentPlayerIndex] : HeartsPlayer.Null; + + public PassDirection CurrentPassDirection => + RoundNumber % 4 == 1 ? PassDirection.Left : + RoundNumber % 4 == 2 ? PassDirection.Right : + RoundNumber % 4 == 3 ? PassDirection.Across : + PassDirection.None; + + public static HeartsGame Instantiate(HeartsGameCreatedEvent created) + { + var game = new HeartsGame + { + Id = created.Id, + Name = created.Name, + StartedTime = created.StartedTime, + Seed = created.InitialSeed, + Deck = created.Deck, + Players = created.Players.Select(p => new HeartsPlayer + { + Id = p.Id, + Name = p.Name + }).ToList() + }; + game.DealCards(); + return game; + } + + private void DealCards() + { + var cardIndex = 0; + foreach (var player in Players) + { + player.Cards.Clear(); + for (var i = 0; i < 13; i++) + { + player.Cards.Add(Deck[cardIndex++]); + } + player.Cards.Sort(); + } + } + + public async Task PassCards(PassCardsRequest request) + { + IncrementSeed(); + var playerId = request.PlayerId; + + if (!TryGetPlayer(playerId, out var player)) + { + var errorResponse = new PassCardsResponse { Error = "Player not found" }; + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + if (Phase != GamePhase.Passing) + { + var errorResponse = new PassCardsResponse { Error = "Not in passing phase" }; + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + if (CurrentPassDirection == PassDirection.None) + { + var errorResponse = new PassCardsResponse { Error = "No passing this round" }; + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + if (player.HasPassed) + { + var errorResponse = new PassCardsResponse { Error = "You have already passed cards" }; + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + if (request.Cards.Count != 3) + { + var errorResponse = new PassCardsResponse { Error = "You must pass exactly 3 cards" }; + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + if (request.Cards.Any(c => !player.HasCard(c))) + { + var errorResponse = new PassCardsResponse { Error = "You don't have all those cards" }; + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + player.CardsToPass.AddRange(request.Cards); + player.HasPassed = true; + + await PlayerPassedCards.InvokeOrDefault(() => new PlayerPassedCardsNotification + { + PlayerId = playerId + }); + + if (Players.All(p => p.HasPassed)) + { + DistributePassedCards(); + + foreach (var p in Players) + { + var receivedCards = p.CardsToPass.ToList(); + var response = new PassCardsResponse { ReceivedCards = receivedCards }; + await RespondAsync(p.Id, response); + await AllPlayersPassed.InvokeOrDefault(p.Id, () => new AllPlayersPassedNotification + { + ReceivedCards = receivedCards + }); + } + + await StartPlayingPhaseAsync(); + } + else + { + var response = new PassCardsResponse(); + await RespondAsync(playerId, response); + } + + return new PassCardsResponse(); + } + + private void DistributePassedCards() + { + var passedCards = Players.Select(p => p.CardsToPass.ToList()).ToList(); + + for (var i = 0; i < Players.Count; i++) + { + var player = Players[i]; + var cardsToReceive = CurrentPassDirection switch + { + PassDirection.Left => passedCards[(i + 1) % Players.Count], + PassDirection.Right => passedCards[(i + Players.Count - 1) % Players.Count], + PassDirection.Across => passedCards[(i + 2) % Players.Count], + _ => [] + }; + + foreach (var card in player.CardsToPass) + { + player.Cards.Remove(card); + } + + player.Cards.AddRange(cardsToReceive); + player.Cards.Sort(); + player.CardsToPass.Clear(); + } + } + + private async Task StartPlayingPhaseAsync() + { + Phase = GamePhase.Playing; + + var startingPlayerIndex = Players.FindIndex(p => p.HasTwoOfClubs()); + if (startingPlayerIndex == -1) + { + startingPlayerIndex = 0; + } + CurrentPlayerIndex = startingPlayerIndex; + + var currentPlayer = CurrentPlayer; + await ItsYourTurn.InvokeOrDefault(currentPlayer.Id, () => new ItsYourTurnNotification + { + PlayerViewOfGame = GetPlayerViewOfGame(currentPlayer) + }); + await ItsPlayersTurn.InvokeOrDefault(() => new ItsPlayersTurnNotification + { + PlayerId = currentPlayer.Id + }); + } + + public async Task PlayCard(PlayCardRequest request) + { + IncrementSeed(); + var playerId = request.PlayerId; + var card = request.Card; + + if (!TryGetPlayer(playerId, out var player)) + { + var errorResponse = new PlayerViewOfGame("Player not found"); + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + if (Phase != GamePhase.Playing) + { + var errorResponse = new PlayerViewOfGame("Not in playing phase"); + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + if (CurrentPlayer.Id != playerId) + { + var errorResponse = new PlayerViewOfGame("It is not your turn"); + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + if (!player.HasCard(card)) + { + var errorResponse = new PlayerViewOfGame($"You don't have '{card}'"); + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + var validationError = ValidateCardPlay(player, card); + if (validationError != null) + { + var errorResponse = new PlayerViewOfGame(validationError); + await RespondAsync(playerId, errorResponse); + return errorResponse; + } + + player.Cards.Remove(card); + player.PlayedCard = card; + CurrentTrick.Add(new CardPlay + { + PlayerId = player.Id, + PlayerName = player.Name, + Card = card + }); + + if (CurrentTrick.Count == 1) + { + LeadSuit = card.Suit; + } + + if (!HeartsAreBroken && card.Suit == Suit.Hearts && CurrentTrick.Count > 1) + { + HeartsAreBroken = true; + await HeartsWereBroken.InvokeOrDefault(() => new HeartsAreBrokenNotification()); + } + + var response = GetPlayerViewOfGame(player); + await RespondAsync(playerId, response); + + await PlayerPlayedCard.InvokeOrDefault(() => new PlayerPlayedCardNotification + { + PlayerId = playerId, + Card = card + }); + + if (CurrentTrick.Count == Players.Count) + { + await CompleteTrickAsync(); + } + else + { + MoveToNextPlayer(); + var nextPlayer = CurrentPlayer; + await ItsYourTurn.InvokeOrDefault(nextPlayer.Id, () => new ItsYourTurnNotification + { + PlayerViewOfGame = GetPlayerViewOfGame(nextPlayer) + }); + await ItsPlayersTurn.InvokeOrDefault(() => new ItsPlayersTurnNotification + { + PlayerId = nextPlayer.Id + }); + } + + return response; + } + + private string? ValidateCardPlay(HeartsPlayer player, Card card) + { + if (IsFirstTrick && player.HasTwoOfClubs() && card is not { Suit: Suit.Clubs, Rank: 2 }) + { + return "You must lead with the Two of Clubs on the first trick"; + } + + if (CurrentTrick.Count == 0) + { + if (!HeartsAreBroken && card.Suit == Suit.Hearts && player.Cards.Any(c => c.Suit != Suit.Hearts)) + { + return "Hearts have not been broken yet"; + } + + if (IsFirstTrick && card.Suit == Suit.Hearts) + { + return "Cannot lead with hearts on the first trick"; + } + + if (IsFirstTrick && card is { Suit: Suit.Spades, Rank: 12 }) + { + return "Cannot lead with Queen of Spades on the first trick"; + } + } + else + { + if (LeadSuit.HasValue && player.HasSuit(LeadSuit.Value) && card.Suit != LeadSuit.Value) + { + return $"You must follow suit ({LeadSuit.Value})"; + } + + if (IsFirstTrick && (card.Suit == Suit.Hearts || card is { Suit: Suit.Spades, Rank: 12 })) + { + if (player.Cards.Any(c => c.Suit != Suit.Hearts && c is not { Suit: Suit.Spades, Rank: 12 })) + { + return "Cannot play points on the first trick unless you only have point cards"; + } + } + } + + return null; + } + + private async Task CompleteTrickAsync() + { + var winningPlay = CurrentTrick + .Where(cp => cp.Card.Suit == LeadSuit) + .OrderByDescending(cp => cp.Card.Rank) + .First(); + + var winnerId = winningPlay.PlayerId; + var winner = Players.First(p => p.Id == winnerId); + + var points = CurrentTrick.Sum(cp => cp.Card.Suit == Suit.Hearts ? 1 : + cp.Card is { Suit: Suit.Spades, Rank: 12 } ? 13 : 0); + winner.RoundScore += points; + + await TrickCompleted.InvokeOrDefault(() => new TrickCompletedNotification + { + WinnerId = winnerId, + WinnerName = winner.Name, + TrickCards = CurrentTrick.ToList(), + Points = points + }); + + foreach (var player in Players) + { + player.ClearPlayedCard(); + } + CurrentTrick.Clear(); + LeadSuit = null; + IsFirstTrick = false; + + CurrentPlayerIndex = Players.FindIndex(p => p.Id == winnerId); + + if (Players.All(p => p.Cards.Count == 0)) + { + await EndRoundAsync(); + } + else + { + var nextPlayer = CurrentPlayer; + await ItsYourTurn.InvokeOrDefault(nextPlayer.Id, () => new ItsYourTurnNotification + { + PlayerViewOfGame = GetPlayerViewOfGame(nextPlayer) + }); + await ItsPlayersTurn.InvokeOrDefault(() => new ItsPlayersTurnNotification + { + PlayerId = nextPlayer.Id + }); + } + } + + private async Task EndRoundAsync() + { + var moonShooter = Players.FirstOrDefault(p => p.RoundScore == 26); + + if (moonShooter != null) + { + foreach (var player in Players.Where(p => p.Id != moonShooter.Id)) + { + player.TotalScore += 26; + } + moonShooter.RoundScore = 0; + } + else + { + foreach (var player in Players) + { + player.TotalScore += player.RoundScore; + } + } + + var scores = Players.Select(p => new PlayerScore + { + PlayerId = p.Id, + PlayerName = p.Name, + RoundScore = p.RoundScore, + TotalScore = p.TotalScore + }).ToList(); + + await RoundEnded.InvokeOrDefault(() => new RoundEndedNotification + { + Scores = scores, + MoonShooterId = moonShooter?.Id, + MoonShooterName = moonShooter?.Name + }); + + if (Players.Any(p => p.TotalScore >= 100)) + { + await EndGameAsync(); + } + else + { + await StartNextRoundAsync(); + } + } + + private async Task StartNextRoundAsync() + { + RoundNumber++; + HeartsAreBroken = false; + IsFirstTrick = true; + Phase = GamePhase.Passing; + + foreach (var player in Players) + { + player.RoundScore = 0; + player.HasPassed = false; + player.CardsToPass.Clear(); + player.PlayedCard = null; + } + + DealCards(); + + if (CurrentPassDirection == PassDirection.None) + { + await StartPlayingPhaseAsync(); + } + else + { + await PassingPhaseStarted.InvokeOrDefault(() => new PassingPhaseStartedNotification + { + PassDirection = CurrentPassDirection + }); + + foreach (var player in Players) + { + await ItsYourTurn.InvokeOrDefault(player.Id, () => new ItsYourTurnNotification + { + PlayerViewOfGame = GetPlayerViewOfGame(player) + }); + } + } + } + + private async Task EndGameAsync() + { + var winner = Players.OrderBy(p => p.TotalScore).First(); + + var finalScores = Players.Select(p => new PlayerScore + { + PlayerId = p.Id, + PlayerName = p.Name, + RoundScore = p.RoundScore, + TotalScore = p.TotalScore + }).ToList(); + + await GameEnded.InvokeOrDefault(() => new GameEndedNotification + { + FinalScores = finalScores, + WinnerId = winner.Id, + WinnerName = winner.Name + }); + } + + private void MoveToNextPlayer() + { + CurrentPlayerIndex = (CurrentPlayerIndex + 1) % Players.Count; + } + + private bool TryGetPlayer(Guid playerId, [MaybeNullWhen(false)] out HeartsPlayer player) + { + player = Players.FirstOrDefault(p => p.Id == playerId); + return player != null; + } + + private PlayerViewOfGame GetPlayerViewOfGame(HeartsPlayer player) + { + return new PlayerViewOfGame + { + Cards = player.Cards.ToList(), + OtherPlayers = Players.Where(p => p.Id != player.Id).Select(p => new OtherHeartsPlayer + { + PlayerId = p.Id, + Name = p.Name, + NumberOfCards = p.Cards.Count, + TotalScore = p.TotalScore, + RoundScore = p.RoundScore, + PlayedCard = p.PlayedCard + }).ToList(), + RoundNumber = RoundNumber, + PassDirection = CurrentPassDirection, + HasPassed = player.HasPassed, + CurrentTrick = CurrentTrick.ToList(), + TotalScore = player.TotalScore, + RoundScore = player.RoundScore, + HeartsAreBroken = HeartsAreBroken, + IsMyTurn = Phase == GamePhase.Playing && CurrentPlayer.Id == player.Id + }; + } + + public override async Task StartAsync() + { + foreach (var player in Players) + { + await GameStarted.InvokeOrDefault(player.Id, () => new GameStartedNotification + { + GameId = Id, + PlayerViewOfGame = GetPlayerViewOfGame(player) + }); + } + + if (CurrentPassDirection == PassDirection.None) + { + await StartPlayingPhaseAsync(); + } + else + { + await PassingPhaseStarted.InvokeOrDefault(() => new PassingPhaseStartedNotification + { + PassDirection = CurrentPassDirection + }); + } + } +} + +public enum GamePhase +{ + Passing, + Playing +} diff --git a/src/Deckster.Games/Hearts/HeartsGameCreatedEvent.cs b/src/Deckster.Games/Hearts/HeartsGameCreatedEvent.cs new file mode 100644 index 00000000..02130e16 --- /dev/null +++ b/src/Deckster.Games/Hearts/HeartsGameCreatedEvent.cs @@ -0,0 +1,9 @@ +using Deckster.Core.Games.Common; + +namespace Deckster.Games.Hearts; + +public class HeartsGameCreatedEvent : GameCreatedEvent +{ + public required List Players { get; init; } + public required List Deck { get; init; } +} diff --git a/src/Deckster.Games/Hearts/HeartsGameStartedEvent.cs b/src/Deckster.Games/Hearts/HeartsGameStartedEvent.cs new file mode 100644 index 00000000..d374c059 --- /dev/null +++ b/src/Deckster.Games/Hearts/HeartsGameStartedEvent.cs @@ -0,0 +1,6 @@ +namespace Deckster.Games.Hearts; + +public class HeartsGameStartedEvent +{ + public Guid GameId { get; init; } +} diff --git a/src/Deckster.Games/Hearts/HeartsPlayer.cs b/src/Deckster.Games/Hearts/HeartsPlayer.cs new file mode 100644 index 00000000..95c081b2 --- /dev/null +++ b/src/Deckster.Games/Hearts/HeartsPlayer.cs @@ -0,0 +1,31 @@ +using Deckster.Core.Games.Common; + +namespace Deckster.Games.Hearts; + +public class HeartsPlayer +{ + public Guid Id { get; init; } + public string Name { get; init; } = ""; + public List Cards { get; init; } = []; + public List CardsToPass { get; init; } = []; + public bool HasPassed { get; set; } + public int RoundScore { get; set; } + public int TotalScore { get; set; } + public Card? PlayedCard { get; set; } + + public static readonly HeartsPlayer Null = new() + { + Id = Guid.Empty, + Name = "Null Player" + }; + + public bool HasCard(Card card) => Cards.Contains(card); + + public bool HasTwoOfClubs() => Cards.Any(c => c.Suit == Suit.Clubs && c.Rank == 2); + + public bool HasOnlySuit(Suit suit) => Cards.All(c => c.Suit == suit); + + public bool HasSuit(Suit suit) => Cards.Any(c => c.Suit == suit); + + public void ClearPlayedCard() => PlayedCard = null; +} diff --git a/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs b/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs new file mode 100644 index 00000000..e40d1f9d --- /dev/null +++ b/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs @@ -0,0 +1,20 @@ +using System.Diagnostics.CodeAnalysis; +using Deckster.Games.Hearts; +using Deckster.Server.Data; + +namespace Deckster.Server.Games.Hearts; + +public class HeartsGameHost : StandardGameHost +{ + public override string GameType => "Hearts"; + + public HeartsGameHost(IRepo repo, ILoggerFactory loggerFactory) : base(repo, loggerFactory, new HeartsProjection(), 4) + { + } + + public override bool TryAddBot([MaybeNullWhen(true)] out string error) + { + error = "Bots are not yet supported for Hearts"; + return false; + } +} diff --git a/src/Deckster.Server/Games/Hearts/HeartsProjection.cs b/src/Deckster.Server/Games/Hearts/HeartsProjection.cs new file mode 100644 index 00000000..8a3815ee --- /dev/null +++ b/src/Deckster.Server/Games/Hearts/HeartsProjection.cs @@ -0,0 +1,32 @@ +using Deckster.Core.Games.Hearts; +using Deckster.Games; +using Deckster.Games.Hearts; + +namespace Deckster.Server.Games.Hearts; + +public class HeartsProjection : GameProjection +{ + public HeartsGame Create(HeartsGameCreatedEvent created) + { + var game = HeartsGame.Instantiate(created); + return game; + } + + public override (HeartsGame game, object startEvent) Create(IGameHost host) + { + var startEvent = new HeartsGameCreatedEvent + { + Id = Guid.NewGuid(), + Name = host.Name, + Players = host.GetPlayers(), + Deck = Decks.Standard().KnuthShuffle(new Random().Next(0, int.MaxValue)), + InitialSeed = new Random().Next(0, int.MaxValue), + StartedTime = DateTimeOffset.UtcNow + }; + var game = Create(startEvent); + return (game, startEvent); + } + + public Task Apply(PassCardsRequest @event, HeartsGame game) => game.PassCards(@event); + public Task Apply(PlayCardRequest @event, HeartsGame game) => game.PlayCard(@event); +} From 43975b19cf2c442482ef39db6c5291cdd89fd6d2 Mon Sep 17 00:00:00 2001 From: stho Date: Fri, 10 Oct 2025 12:35:55 +0200 Subject: [PATCH 02/26] display hearts game under games --- src/Deckster.Server/Controllers/HeartsController.cs | 11 +++++++++++ .../Games/DecksterServiceExtensions.cs | 2 ++ 2 files changed, 13 insertions(+) create mode 100644 src/Deckster.Server/Controllers/HeartsController.cs diff --git a/src/Deckster.Server/Controllers/HeartsController.cs b/src/Deckster.Server/Controllers/HeartsController.cs new file mode 100644 index 00000000..63905baf --- /dev/null +++ b/src/Deckster.Server/Controllers/HeartsController.cs @@ -0,0 +1,11 @@ +using Deckster.Games.Hearts; +using Deckster.Server.Data; +using Deckster.Server.Games; +using Deckster.Server.Games.Hearts; +using Microsoft.AspNetCore.Mvc; + +namespace Deckster.Server.Controllers; + +[Route("hearts")] +public class HeartsController(GameHostRegistry hostRegistry, IRepo repo) + : GameController(hostRegistry, repo); diff --git a/src/Deckster.Server/Games/DecksterServiceExtensions.cs b/src/Deckster.Server/Games/DecksterServiceExtensions.cs index 6f0c5785..0808fcba 100644 --- a/src/Deckster.Server/Games/DecksterServiceExtensions.cs +++ b/src/Deckster.Server/Games/DecksterServiceExtensions.cs @@ -2,6 +2,7 @@ using Deckster.Server.Games.ChatRoom; using Deckster.Server.Games.CrazyEights; using Deckster.Server.Games.Gabong; +using Deckster.Server.Games.Hearts; using Deckster.Server.Games.Idiot; using Deckster.Server.Games.TexasHoldEm; using Deckster.Server.Games.Uno; @@ -22,6 +23,7 @@ public static IServiceCollection AddDeckster(this IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); return services; } } \ No newline at end of file From 2431e85f2930830a5e11af10e7b38ba98a000273 Mon Sep 17 00:00:00 2001 From: stho Date: Fri, 10 Oct 2025 12:51:50 +0200 Subject: [PATCH 03/26] fix client generation --- decksterapi.yml | 3044 +++++++----- generated/deckster.opeanpi.json | 601 ++- generated/deckster.opeanpi.yaml | 363 +- .../hearts/HeartsClient.kt | 23 + .../no.forse.decksterlib/uno/UnoClient.kt | 2 - generated/shebang.opeanpi.json | 4117 +++++++++++------ generated/shebang.opeanpi.yaml | 3044 +++++++----- .../Games/Hearts/HeartsClient.g.cs | 136 + src/Deckster.Client/Games/Uno/UnoClient.g.cs | 8 - .../Generators/CsharpClientGenerator.cs | 2 +- .../UnoInteractive.cs | 4 +- src/Deckster.Uno.SampleClient/UnoPoorAi.cs | 4 +- 12 files changed, 7667 insertions(+), 3681 deletions(-) create mode 100644 generated/kotlin/no.forse.decksterlib/hearts/HeartsClient.kt create mode 100644 src/Deckster.Client/Games/Hearts/HeartsClient.g.cs diff --git a/decksterapi.yml b/decksterapi.yml index 45a55671..14d6d4c6 100644 --- a/decksterapi.yml +++ b/decksterapi.yml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.0.4 info: title: Deckster.Server version: '1.0' @@ -1547,48 +1547,17 @@ paths: responses: '200': description: OK - /: - get: - tags: - - Home - responses: - '200': - description: OK - /login: - get: - tags: - - Home - responses: - '200': - description: OK - post: - tags: - - Home - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/Controllers.LoginModel' - text/json: - schema: - $ref: '#/components/schemas/Controllers.LoginModel' - application/*+json: - schema: - $ref: '#/components/schemas/Controllers.LoginModel' - responses: - '200': - description: OK - /idiot/description: + /hearts/description: get: tags: - - Idiot + - Hearts responses: '200': description: OK - /idiot/metadata: + /hearts/metadata: get: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1602,10 +1571,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Meta.GameMeta' - /idiot: + /hearts: get: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1619,10 +1588,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.GameOverviewVm' - /idiot/games: + /hearts/games: get: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1642,10 +1611,10 @@ paths: type: array items: $ref: '#/components/schemas/Controllers.GameVm' - '/idiot/games/{name}': + '/hearts/games/{name}': get: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1679,7 +1648,7 @@ paths: $ref: '#/components/schemas/Controllers.ResponseMessage' delete: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1711,10 +1680,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/idiot/games/{name}/bot': + '/hearts/games/{name}/bot': post: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1734,10 +1703,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /idiot/previousgames: + /hearts/previousgames: get: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1746,21 +1715,21 @@ paths: schema: type: array items: - $ref: '#/components/schemas/Idiot.IdiotGame' + $ref: '#/components/schemas/Hearts.HeartsGame' application/json: schema: type: array items: - $ref: '#/components/schemas/Idiot.IdiotGame' + $ref: '#/components/schemas/Hearts.HeartsGame' text/json: schema: type: array items: - $ref: '#/components/schemas/Idiot.IdiotGame' - '/idiot/previousgames/{id}': + $ref: '#/components/schemas/Hearts.HeartsGame' + '/hearts/previousgames/{id}': get: tags: - - Idiot + - Hearts parameters: - name: id in: path @@ -1774,17 +1743,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' + $ref: '#/components/schemas/Data.HistoricHeartsGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' + $ref: '#/components/schemas/Data.HistoricHeartsGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' - '/idiot/previousgames/{id}/{version}': + $ref: '#/components/schemas/Data.HistoricHeartsGame' + '/hearts/previousgames/{id}/{version}': get: tags: - - Idiot + - Hearts parameters: - name: id in: path @@ -1804,17 +1773,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' + $ref: '#/components/schemas/Data.HistoricHeartsGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' + $ref: '#/components/schemas/Data.HistoricHeartsGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' - '/idiot/create/{name}': + $ref: '#/components/schemas/Data.HistoricHeartsGame' + '/hearts/create/{name}': post: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1846,10 +1815,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /idiot/create: + /hearts/create: post: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1875,10 +1844,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/idiot/games/{name}/start': + '/hearts/games/{name}/start': post: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1910,10 +1879,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/idiot/join/{gameName}': + '/hearts/join/{gameName}': get: tags: - - Idiot + - Hearts parameters: - name: gameName in: path @@ -1923,10 +1892,10 @@ paths: responses: '200': description: OK - '/idiot/join/{connectionId}/finish': + '/hearts/join/{connectionId}/finish': get: tags: - - Idiot + - Hearts parameters: - name: connectionId in: path @@ -1937,10 +1906,10 @@ paths: responses: '200': description: OK - '/idiot/spectate/{gameName}': + '/hearts/spectate/{gameName}': get: tags: - - Idiot + - Hearts parameters: - name: gameName in: path @@ -1950,10 +1919,10 @@ paths: responses: '200': description: OK - '/idiot/spectate/{connectionId}/finish': + '/hearts/spectate/{connectionId}/finish': get: tags: - - Idiot + - Hearts parameters: - name: connectionId in: path @@ -1964,24 +1933,48 @@ paths: responses: '200': description: OK - /meta/messages: + /: get: tags: - - Meta + - Home responses: '200': description: OK - /texasholdem/description: + /login: get: tags: - - TexasHoldEm + - Home responses: '200': description: OK - /texasholdem/metadata: + post: + tags: + - Home + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Controllers.LoginModel' + text/json: + schema: + $ref: '#/components/schemas/Controllers.LoginModel' + application/*+json: + schema: + $ref: '#/components/schemas/Controllers.LoginModel' + responses: + '200': + description: OK + /idiot/description: get: tags: - - TexasHoldEm + - Idiot + responses: + '200': + description: OK + /idiot/metadata: + get: + tags: + - Idiot responses: '200': description: OK @@ -1995,10 +1988,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Meta.GameMeta' - /texasholdem: + /idiot: get: tags: - - TexasHoldEm + - Idiot responses: '200': description: OK @@ -2012,10 +2005,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.GameOverviewVm' - /texasholdem/games: + /idiot/games: get: tags: - - TexasHoldEm + - Idiot responses: '200': description: OK @@ -2035,10 +2028,10 @@ paths: type: array items: $ref: '#/components/schemas/Controllers.GameVm' - '/texasholdem/games/{name}': + '/idiot/games/{name}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2072,7 +2065,7 @@ paths: $ref: '#/components/schemas/Controllers.ResponseMessage' delete: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2104,10 +2097,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/texasholdem/games/{name}/bot': + '/idiot/games/{name}/bot': post: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2127,10 +2120,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /texasholdem/previousgames: + /idiot/previousgames: get: tags: - - TexasHoldEm + - Idiot responses: '200': description: OK @@ -2139,21 +2132,21 @@ paths: schema: type: array items: - $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + $ref: '#/components/schemas/Idiot.IdiotGame' application/json: schema: type: array items: - $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + $ref: '#/components/schemas/Idiot.IdiotGame' text/json: schema: type: array items: - $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' - '/texasholdem/previousgames/{id}': + $ref: '#/components/schemas/Idiot.IdiotGame' + '/idiot/previousgames/{id}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: id in: path @@ -2167,17 +2160,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + $ref: '#/components/schemas/Data.HistoricIdiotGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + $ref: '#/components/schemas/Data.HistoricIdiotGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' - '/texasholdem/previousgames/{id}/{version}': + $ref: '#/components/schemas/Data.HistoricIdiotGame' + '/idiot/previousgames/{id}/{version}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: id in: path @@ -2197,17 +2190,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + $ref: '#/components/schemas/Data.HistoricIdiotGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + $ref: '#/components/schemas/Data.HistoricIdiotGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' - '/texasholdem/create/{name}': + $ref: '#/components/schemas/Data.HistoricIdiotGame' + '/idiot/create/{name}': post: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2239,10 +2232,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /texasholdem/create: + /idiot/create: post: tags: - - TexasHoldEm + - Idiot responses: '200': description: OK @@ -2268,10 +2261,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/texasholdem/games/{name}/start': + '/idiot/games/{name}/start': post: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2303,10 +2296,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/texasholdem/join/{gameName}': + '/idiot/join/{gameName}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: gameName in: path @@ -2316,10 +2309,10 @@ paths: responses: '200': description: OK - '/texasholdem/join/{connectionId}/finish': + '/idiot/join/{connectionId}/finish': get: tags: - - TexasHoldEm + - Idiot parameters: - name: connectionId in: path @@ -2330,10 +2323,10 @@ paths: responses: '200': description: OK - '/texasholdem/spectate/{gameName}': + '/idiot/spectate/{gameName}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: gameName in: path @@ -2343,10 +2336,10 @@ paths: responses: '200': description: OK - '/texasholdem/spectate/{connectionId}/finish': + '/idiot/spectate/{connectionId}/finish': get: tags: - - TexasHoldEm + - Idiot parameters: - name: connectionId in: path @@ -2357,17 +2350,24 @@ paths: responses: '200': description: OK - /uno/description: + /meta/messages: get: tags: - - Uno + - Meta responses: '200': description: OK - /uno/metadata: + /texasholdem/description: get: tags: - - Uno + - TexasHoldEm + responses: + '200': + description: OK + /texasholdem/metadata: + get: + tags: + - TexasHoldEm responses: '200': description: OK @@ -2381,10 +2381,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Meta.GameMeta' - /uno: + /texasholdem: get: tags: - - Uno + - TexasHoldEm responses: '200': description: OK @@ -2398,10 +2398,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.GameOverviewVm' - /uno/games: + /texasholdem/games: get: tags: - - Uno + - TexasHoldEm responses: '200': description: OK @@ -2421,10 +2421,10 @@ paths: type: array items: $ref: '#/components/schemas/Controllers.GameVm' - '/uno/games/{name}': + '/texasholdem/games/{name}': get: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2458,7 +2458,7 @@ paths: $ref: '#/components/schemas/Controllers.ResponseMessage' delete: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2490,10 +2490,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/uno/games/{name}/bot': + '/texasholdem/games/{name}/bot': post: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2513,10 +2513,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /uno/previousgames: + /texasholdem/previousgames: get: tags: - - Uno + - TexasHoldEm responses: '200': description: OK @@ -2525,21 +2525,21 @@ paths: schema: type: array items: - $ref: '#/components/schemas/Uno.UnoGame' + $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' application/json: schema: type: array items: - $ref: '#/components/schemas/Uno.UnoGame' + $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' text/json: schema: type: array items: - $ref: '#/components/schemas/Uno.UnoGame' - '/uno/previousgames/{id}': + $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + '/texasholdem/previousgames/{id}': get: tags: - - Uno + - TexasHoldEm parameters: - name: id in: path @@ -2553,17 +2553,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' - '/uno/previousgames/{id}/{version}': - get: + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + '/texasholdem/previousgames/{id}/{version}': + get: tags: - - Uno + - TexasHoldEm parameters: - name: id in: path @@ -2583,17 +2583,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' - '/uno/create/{name}': + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + '/texasholdem/create/{name}': post: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2625,10 +2625,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /uno/create: + /texasholdem/create: post: tags: - - Uno + - TexasHoldEm responses: '200': description: OK @@ -2654,10 +2654,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/uno/games/{name}/start': + '/texasholdem/games/{name}/start': post: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2689,10 +2689,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/uno/join/{gameName}': + '/texasholdem/join/{gameName}': get: tags: - - Uno + - TexasHoldEm parameters: - name: gameName in: path @@ -2702,10 +2702,10 @@ paths: responses: '200': description: OK - '/uno/join/{connectionId}/finish': + '/texasholdem/join/{connectionId}/finish': get: tags: - - Uno + - TexasHoldEm parameters: - name: connectionId in: path @@ -2716,10 +2716,10 @@ paths: responses: '200': description: OK - '/uno/spectate/{gameName}': + '/texasholdem/spectate/{gameName}': get: tags: - - Uno + - TexasHoldEm parameters: - name: gameName in: path @@ -2729,10 +2729,10 @@ paths: responses: '200': description: OK - '/uno/spectate/{connectionId}/finish': + '/texasholdem/spectate/{connectionId}/finish': get: tags: - - Uno + - TexasHoldEm parameters: - name: connectionId in: path @@ -2743,24 +2743,17 @@ paths: responses: '200': description: OK - /me: - get: - tags: - - User - responses: - '200': - description: OK - /yaniv/description: + /uno/description: get: tags: - - Yaniv + - Uno responses: '200': description: OK - /yaniv/metadata: + /uno/metadata: get: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -2774,10 +2767,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Meta.GameMeta' - /yaniv: + /uno: get: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -2791,10 +2784,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.GameOverviewVm' - /yaniv/games: + /uno/games: get: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -2814,10 +2807,10 @@ paths: type: array items: $ref: '#/components/schemas/Controllers.GameVm' - '/yaniv/games/{name}': + '/uno/games/{name}': get: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -2851,7 +2844,7 @@ paths: $ref: '#/components/schemas/Controllers.ResponseMessage' delete: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -2883,10 +2876,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/yaniv/games/{name}/bot': + '/uno/games/{name}/bot': post: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -2906,10 +2899,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /yaniv/previousgames: + /uno/previousgames: get: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -2918,21 +2911,21 @@ paths: schema: type: array items: - $ref: '#/components/schemas/Yaniv.YanivGame' + $ref: '#/components/schemas/Uno.UnoGame' application/json: schema: type: array items: - $ref: '#/components/schemas/Yaniv.YanivGame' + $ref: '#/components/schemas/Uno.UnoGame' text/json: schema: type: array items: - $ref: '#/components/schemas/Yaniv.YanivGame' - '/yaniv/previousgames/{id}': + $ref: '#/components/schemas/Uno.UnoGame' + '/uno/previousgames/{id}': get: tags: - - Yaniv + - Uno parameters: - name: id in: path @@ -2946,17 +2939,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' + $ref: '#/components/schemas/Data.HistoricUnoGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' + $ref: '#/components/schemas/Data.HistoricUnoGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' - '/yaniv/previousgames/{id}/{version}': + $ref: '#/components/schemas/Data.HistoricUnoGame' + '/uno/previousgames/{id}/{version}': get: tags: - - Yaniv + - Uno parameters: - name: id in: path @@ -2976,17 +2969,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' + $ref: '#/components/schemas/Data.HistoricUnoGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' + $ref: '#/components/schemas/Data.HistoricUnoGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' - '/yaniv/create/{name}': + $ref: '#/components/schemas/Data.HistoricUnoGame' + '/uno/create/{name}': post: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -3018,10 +3011,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /yaniv/create: + /uno/create: post: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -3047,10 +3040,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/yaniv/games/{name}/start': + '/uno/games/{name}/start': post: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -3082,10 +3075,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/yaniv/join/{gameName}': + '/uno/join/{gameName}': get: tags: - - Yaniv + - Uno parameters: - name: gameName in: path @@ -3095,10 +3088,10 @@ paths: responses: '200': description: OK - '/yaniv/join/{connectionId}/finish': + '/uno/join/{connectionId}/finish': get: tags: - - Yaniv + - Uno parameters: - name: connectionId in: path @@ -3109,10 +3102,10 @@ paths: responses: '200': description: OK - '/yaniv/spectate/{gameName}': + '/uno/spectate/{gameName}': get: tags: - - Yaniv + - Uno parameters: - name: gameName in: path @@ -3122,10 +3115,10 @@ paths: responses: '200': description: OK - '/yaniv/spectate/{connectionId}/finish': + '/uno/spectate/{connectionId}/finish': get: tags: - - Yaniv + - Uno parameters: - name: connectionId in: path @@ -3136,132 +3129,877 @@ paths: responses: '200': description: OK -components: - schemas: - Bullshit.BullshitBroadcastNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - actualCard - - claimedToBeCard - - playerId - - punishmentCardCount - type: object - properties: - playerId: - type: string - format: uuid - claimedToBeCard: - $ref: '#/components/schemas/Common.Card' - actualCard: - $ref: '#/components/schemas/Common.Card' - punishmentCardCount: - type: integer - format: int32 - additionalProperties: false - Bullshit.BullshitGame: - allOf: - - $ref: '#/components/schemas/Games.GameObject' - - required: - - cardsDrawn - - currentPlayer - - currentPlayerIndex - - deck - - discardPile - - donePlayers - - players - - stockPile - type: object - properties: - deck: - type: array - items: - $ref: '#/components/schemas/Common.Card' - stockPile: - type: array - items: - $ref: '#/components/schemas/Common.Card' - discardPile: - type: array - items: - $ref: '#/components/schemas/Common.Card' - players: - type: array - items: - $ref: '#/components/schemas/Bullshit.BullshitPlayer' - donePlayers: - type: array - items: - $ref: '#/components/schemas/Bullshit.BullshitPlayer' - currentPlayerIndex: - type: integer - format: int32 - claimedTopOfPile: - $ref: '#/components/schemas/Common.Card' - actualTopOfPile: - $ref: '#/components/schemas/Common.Card' - cardsDrawn: - type: integer - format: int32 - potentialBullshit: - $ref: '#/components/schemas/Bullshit.PotentialBullshit' - currentPlayer: - $ref: '#/components/schemas/Bullshit.BullshitPlayer' - additionalProperties: false - Bullshit.BullshitPlayer: - required: - - cards - - id - - name - type: object - properties: - id: - type: string - format: uuid - name: - type: string - cards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Bullshit.BullshitPlayerNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - calledByPlayerId - - card - - punishmentCards - type: object - properties: - calledByPlayerId: - type: string - format: uuid - card: - $ref: '#/components/schemas/Common.Card' - punishmentCards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Bullshit.BullshitRequest: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' - - type: object - additionalProperties: false - Bullshit.BullshitResponse: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' - - required: - - punishmentCards - type: object - properties: - punishmentCards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Bullshit.CardResponse: + /me: + get: + tags: + - User + responses: + '200': + description: OK + /yaniv/description: + get: + tags: + - Yaniv + responses: + '200': + description: OK + /yaniv/metadata: + get: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Meta.GameMeta' + application/json: + schema: + $ref: '#/components/schemas/Meta.GameMeta' + text/json: + schema: + $ref: '#/components/schemas/Meta.GameMeta' + /yaniv: + get: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.GameOverviewVm' + application/json: + schema: + $ref: '#/components/schemas/Controllers.GameOverviewVm' + text/json: + schema: + $ref: '#/components/schemas/Controllers.GameOverviewVm' + /yaniv/games: + get: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + type: array + items: + $ref: '#/components/schemas/Controllers.GameVm' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Controllers.GameVm' + text/json: + schema: + type: array + items: + $ref: '#/components/schemas/Controllers.GameVm' + '/yaniv/games/{name}': + get: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + application/json: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + text/json: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + '404': + description: Not Found + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + delete: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + application/json: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + text/json: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + '404': + description: Not Found + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + '/yaniv/games/{name}/bot': + post: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + /yaniv/previousgames: + get: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + type: array + items: + $ref: '#/components/schemas/Yaniv.YanivGame' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Yaniv.YanivGame' + text/json: + schema: + type: array + items: + $ref: '#/components/schemas/Yaniv.YanivGame' + '/yaniv/previousgames/{id}': + get: + tags: + - Yaniv + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + application/json: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + text/json: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + '/yaniv/previousgames/{id}/{version}': + get: + tags: + - Yaniv + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: version + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + application/json: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + text/json: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + '/yaniv/create/{name}': + post: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Core.GameInfo' + application/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + text/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + '400': + description: Bad Request + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + /yaniv/create: + post: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Core.GameInfo' + application/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + text/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + '400': + description: Bad Request + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + '/yaniv/games/{name}/start': + post: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Core.GameInfo' + application/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + text/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + '404': + description: Not Found + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + '/yaniv/join/{gameName}': + get: + tags: + - Yaniv + parameters: + - name: gameName + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '/yaniv/join/{connectionId}/finish': + get: + tags: + - Yaniv + parameters: + - name: connectionId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: OK + '/yaniv/spectate/{gameName}': + get: + tags: + - Yaniv + parameters: + - name: gameName + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '/yaniv/spectate/{connectionId}/finish': + get: + tags: + - Yaniv + parameters: + - name: connectionId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: OK +components: + schemas: + Bullshit.BullshitBroadcastNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - actualCard + - claimedToBeCard + - playerId + - punishmentCardCount + type: object + properties: + playerId: + type: string + format: uuid + claimedToBeCard: + $ref: '#/components/schemas/Common.Card' + actualCard: + $ref: '#/components/schemas/Common.Card' + punishmentCardCount: + type: integer + format: int32 + additionalProperties: false + Bullshit.BullshitGame: + allOf: + - $ref: '#/components/schemas/Games.GameObject' + - required: + - cardsDrawn + - currentPlayer + - currentPlayerIndex + - deck + - discardPile + - donePlayers + - players + - stockPile + type: object + properties: + deck: + type: array + items: + $ref: '#/components/schemas/Common.Card' + stockPile: + type: array + items: + $ref: '#/components/schemas/Common.Card' + discardPile: + type: array + items: + $ref: '#/components/schemas/Common.Card' + players: + type: array + items: + $ref: '#/components/schemas/Bullshit.BullshitPlayer' + donePlayers: + type: array + items: + $ref: '#/components/schemas/Bullshit.BullshitPlayer' + currentPlayerIndex: + type: integer + format: int32 + claimedTopOfPile: + $ref: '#/components/schemas/Common.Card' + actualTopOfPile: + $ref: '#/components/schemas/Common.Card' + cardsDrawn: + type: integer + format: int32 + potentialBullshit: + $ref: '#/components/schemas/Bullshit.PotentialBullshit' + currentPlayer: + $ref: '#/components/schemas/Bullshit.BullshitPlayer' + additionalProperties: false + Bullshit.BullshitPlayer: + required: + - cards + - id + - name + type: object + properties: + id: + type: string + format: uuid + name: + type: string + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.BullshitPlayerNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - calledByPlayerId + - card + - punishmentCards + type: object + properties: + calledByPlayerId: + type: string + format: uuid + card: + $ref: '#/components/schemas/Common.Card' + punishmentCards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.BullshitRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object + additionalProperties: false + Bullshit.BullshitResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - required: + - punishmentCards + type: object + properties: + punishmentCards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.CardResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - required: + - card + type: object + properties: + card: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.DiscardPileShuffledNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + additionalProperties: false + Bullshit.DrawCardRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object + additionalProperties: false + Bullshit.FalseBullshitCallNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - accusedPlayerId + - playerId + - punishmentCardCount + type: object + properties: + playerId: + type: string + format: uuid + accusedPlayerId: + type: string + format: uuid + punishmentCardCount: + type: integer + format: int32 + additionalProperties: false + Bullshit.GameEndedNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - loserId + - loserName + - players + type: object + properties: + players: + type: array + items: + $ref: '#/components/schemas/Common.PlayerData' + loserId: + type: string + format: uuid + loserName: + type: string + additionalProperties: false + Bullshit.GameStartedNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - gameId + - playerViewOfGame + type: object + properties: + gameId: + type: string + format: uuid + playerViewOfGame: + $ref: '#/components/schemas/Bullshit.PlayerViewOfGame' + additionalProperties: false + Bullshit.ItsPlayersTurnNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid + additionalProperties: false + Bullshit.ItsYourTurnNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + additionalProperties: false + Bullshit.OtherBullshitPlayer: + required: + - name + - numberOfCards + - playerId + type: object + properties: + playerId: + type: string + format: uuid + name: + type: string + numberOfCards: + type: integer + format: int32 + additionalProperties: false + Bullshit.PassRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object + additionalProperties: false + Bullshit.PlayerDrewCardNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid + additionalProperties: false + Bullshit.PlayerIsDoneNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid + additionalProperties: false + Bullshit.PlayerPassedNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid + additionalProperties: false + Bullshit.PlayerPutCardNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - claimedToBeCard + - playerId + type: object + properties: + playerId: + type: string + format: uuid + claimedToBeCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.PlayerViewOfGame: + required: + - cards + - discardPileCount + - otherPlayers + - stockPileCount + type: object + properties: + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + claimedTopOfPile: + $ref: '#/components/schemas/Common.Card' + stockPileCount: + type: integer + format: int32 + discardPileCount: + type: integer + format: int32 + otherPlayers: + type: array + items: + $ref: '#/components/schemas/Bullshit.OtherBullshitPlayer' + additionalProperties: false + Bullshit.PotentialBullshit: + required: + - claimedToBeCard + - playerId + type: object + properties: + playerId: + type: string + format: uuid + claimedToBeCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.PutCardRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - required: + - actualCard + - claimedToBeCard + type: object + properties: + actualCard: + $ref: '#/components/schemas/Common.Card' + claimedToBeCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + ChatRoom.ChatNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - message + - sender + type: object + properties: + sender: + type: string + message: + type: string + additionalProperties: false + ChatRoom.ChatResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + additionalProperties: false + ChatRoom.ChatRoom: + allOf: + - $ref: '#/components/schemas/Games.GameObject' + - required: + - transcript + type: object + properties: + transcript: + type: array + items: + $ref: '#/components/schemas/ChatRoom.SendChatRequest' + additionalProperties: false + ChatRoom.SendChatRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - required: + - message + type: object + properties: + message: + type: string + additionalProperties: false + Common.Card: + required: + - rank + - suit + type: object + properties: + rank: + type: integer + format: int32 + suit: + $ref: '#/components/schemas/Common.Suit' + additionalProperties: false + Common.EmptyResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + additionalProperties: false + Common.PlayerData: + required: + - cardsInHand + - id + - info + - name + - points + type: object + properties: + name: + type: string + points: + type: number + format: double + cardsInHand: + type: integer + format: int32 + id: + type: string + format: uuid + info: + type: object + additionalProperties: + type: string + additionalProperties: false + Common.Suit: + enum: + - Clubs + - Diamonds + - Hearts + - Spades + type: string + Controllers.GameOverviewVm: + required: + - games + - gameType + type: object + properties: + gameType: + type: string + games: + type: array + items: + $ref: '#/components/schemas/Controllers.GameVm' + additionalProperties: false + Controllers.GameVm: + required: + - gameType + - name + - players + - state + type: object + properties: + gameType: + type: string + name: + type: string + state: + $ref: '#/components/schemas/Games.GameState' + players: + type: array + items: + $ref: '#/components/schemas/Common.PlayerData' + additionalProperties: false + Controllers.LoginModel: + type: object + properties: + username: + type: string + nullable: true + password: + type: string + nullable: true + additionalProperties: false + Controllers.ResponseMessage: + type: object + properties: + message: + type: string + nullable: true + additionalProperties: false + Core.GameInfo: + required: + - id + type: object + properties: + id: + type: string + additionalProperties: false + CrazyEights.CardResponse: allOf: - $ref: '#/components/schemas/Protocol.DecksterResponse' - required: @@ -3271,36 +4009,106 @@ components: card: $ref: '#/components/schemas/Common.Card' additionalProperties: false - Bullshit.DiscardPileShuffledNotification: + CrazyEights.CrazyEightsGame: + allOf: + - $ref: '#/components/schemas/Games.GameObject' + - required: + - cardsDrawn + - currentPlayer + - currentPlayerIndex + - currentSuit + - deck + - discardPile + - donePlayers + - initialCardsPerPlayer + - players + - spectators + - stockPile + - topOfPile + type: object + properties: + initialCardsPerPlayer: + type: integer + format: int32 + currentPlayerIndex: + type: integer + format: int32 + cardsDrawn: + type: integer + format: int32 + donePlayers: + type: array + items: + $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + deck: + type: array + items: + $ref: '#/components/schemas/Common.Card' + stockPile: + type: array + items: + $ref: '#/components/schemas/Common.Card' + discardPile: + type: array + items: + $ref: '#/components/schemas/Common.Card' + players: + type: array + items: + $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + spectators: + type: array + items: + $ref: '#/components/schemas/CrazyEights.CrazyEightsSpectator' + newSuit: + $ref: '#/components/schemas/Common.Suit' + topOfPile: + $ref: '#/components/schemas/Common.Card' + currentSuit: + $ref: '#/components/schemas/Common.Suit' + currentPlayer: + $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + additionalProperties: false + CrazyEights.CrazyEightsPlayer: + required: + - cards + - id + - name + type: object + properties: + id: + type: string + format: uuid + name: + type: string + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + CrazyEights.CrazyEightsSpectator: + required: + - id + - name + type: object + properties: + id: + type: string + format: uuid + name: + type: string + additionalProperties: false + CrazyEights.DiscardPileShuffledNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - type: object additionalProperties: false - Bullshit.DrawCardRequest: + CrazyEights.DrawCardRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - type: object additionalProperties: false - Bullshit.FalseBullshitCallNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - accusedPlayerId - - playerId - - punishmentCardCount - type: object - properties: - playerId: - type: string - format: uuid - accusedPlayerId: - type: string - format: uuid - punishmentCardCount: - type: integer - format: int32 - additionalProperties: false - Bullshit.GameEndedNotification: + CrazyEights.GameEndedNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: @@ -3319,7 +4127,7 @@ components: loserName: type: string additionalProperties: false - Bullshit.GameStartedNotification: + CrazyEights.GameStartedNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: @@ -3331,9 +4139,9 @@ components: type: string format: uuid playerViewOfGame: - $ref: '#/components/schemas/Bullshit.PlayerViewOfGame' + $ref: '#/components/schemas/CrazyEights.PlayerViewOfGame' additionalProperties: false - Bullshit.ItsPlayersTurnNotification: + CrazyEights.ItsPlayersTurnNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: @@ -3344,12 +4152,17 @@ components: type: string format: uuid additionalProperties: false - Bullshit.ItsYourTurnNotification: + CrazyEights.ItsYourTurnNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - - type: object + - required: + - playerViewOfGame + type: object + properties: + playerViewOfGame: + $ref: '#/components/schemas/CrazyEights.PlayerViewOfGame' additionalProperties: false - Bullshit.OtherBullshitPlayer: + CrazyEights.OtherCrazyEightsPlayer: required: - name - numberOfCards @@ -3365,257 +4178,222 @@ components: type: integer format: int32 additionalProperties: false - Bullshit.PassRequest: + CrazyEights.PassRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - type: object additionalProperties: false - Bullshit.PlayerDrewCardNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid - additionalProperties: false - Bullshit.PlayerIsDoneNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid - additionalProperties: false - Bullshit.PlayerPassedNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid - additionalProperties: false - Bullshit.PlayerPutCardNotification: + CrazyEights.PlayerDrewCardNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - claimedToBeCard - playerId type: object properties: playerId: type: string format: uuid - claimedToBeCard: - $ref: '#/components/schemas/Common.Card' additionalProperties: false - Bullshit.PlayerViewOfGame: - required: - - cards - - discardPileCount - - otherPlayers - - stockPileCount - type: object - properties: - cards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - claimedTopOfPile: - $ref: '#/components/schemas/Common.Card' - stockPileCount: - type: integer - format: int32 - discardPileCount: - type: integer - format: int32 - otherPlayers: - type: array - items: - $ref: '#/components/schemas/Bullshit.OtherBullshitPlayer' - additionalProperties: false - Bullshit.PotentialBullshit: - required: - - claimedToBeCard - - playerId - type: object - properties: - playerId: - type: string - format: uuid - claimedToBeCard: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Bullshit.PutCardRequest: + CrazyEights.PlayerIsDoneNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - actualCard - - claimedToBeCard + - playerId type: object properties: - actualCard: - $ref: '#/components/schemas/Common.Card' - claimedToBeCard: - $ref: '#/components/schemas/Common.Card' + playerId: + type: string + format: uuid additionalProperties: false - ChatRoom.ChatNotification: + CrazyEights.PlayerPassedNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - message - - sender + - playerId type: object properties: - sender: + playerId: type: string - message: + format: uuid + additionalProperties: false + CrazyEights.PlayerPutCardNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - card + - playerId + type: object + properties: + playerId: type: string + format: uuid + card: + $ref: '#/components/schemas/Common.Card' additionalProperties: false - ChatRoom.ChatResponse: + CrazyEights.PlayerPutEightNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' - - type: object + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - card + - newSuit + - playerId + type: object + properties: + playerId: + type: string + format: uuid + card: + $ref: '#/components/schemas/Common.Card' + newSuit: + $ref: '#/components/schemas/Common.Suit' additionalProperties: false - ChatRoom.ChatRoom: + CrazyEights.PlayerViewOfGame: allOf: - - $ref: '#/components/schemas/Games.GameObject' + - $ref: '#/components/schemas/Protocol.DecksterResponse' - required: - - transcript + - cards + - currentSuit + - discardPileCount + - otherPlayers + - stockPileCount + - topOfPile type: object properties: - transcript: + cards: type: array items: - $ref: '#/components/schemas/ChatRoom.SendChatRequest' + $ref: '#/components/schemas/Common.Card' + topOfPile: + $ref: '#/components/schemas/Common.Card' + currentSuit: + $ref: '#/components/schemas/Common.Suit' + stockPileCount: + type: integer + format: int32 + discardPileCount: + type: integer + format: int32 + otherPlayers: + type: array + items: + $ref: '#/components/schemas/CrazyEights.OtherCrazyEightsPlayer' additionalProperties: false - ChatRoom.SendChatRequest: + CrazyEights.PutCardRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - required: - - message + - card type: object properties: - message: - type: string + card: + $ref: '#/components/schemas/Common.Card' additionalProperties: false - Common.Card: - required: - - rank - - suit - type: object - properties: - rank: - type: integer - format: int32 - suit: - $ref: '#/components/schemas/Common.Suit' - additionalProperties: false - Common.EmptyResponse: + CrazyEights.PutEightRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' - - type: object + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - required: + - card + - newSuit + type: object + properties: + card: + $ref: '#/components/schemas/Common.Card' + newSuit: + $ref: '#/components/schemas/Common.Suit' additionalProperties: false - Common.PlayerData: + Data.DatabaseObject: required: - - cardsInHand - id - - info - - name - - points + - type type: object properties: - name: + type: type: string - points: - type: number - format: double - cardsInHand: - type: integer - format: int32 + readOnly: true id: type: string format: uuid - info: - type: object - additionalProperties: - type: string additionalProperties: false - Common.Suit: - enum: - - Clubs - - Diamonds - - Hearts - - Spades - type: string - Controllers.GameOverviewVm: - required: - - games - - gameType + discriminator: + propertyName: type + mapping: + Games.GameObject: '#/components/schemas/Games.GameObject' + Yaniv.YanivGame: '#/components/schemas/Yaniv.YanivGame' + Uno.UnoGame: '#/components/schemas/Uno.UnoGame' + TexasHoldEm.TexasHoldEmGame: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + Idiot.IdiotGame: '#/components/schemas/Idiot.IdiotGame' + Hearts.HeartsGame: '#/components/schemas/Hearts.HeartsGame' + Gabong.GabongGame: '#/components/schemas/Gabong.GabongGame' + CrazyEights.CrazyEightsGame: '#/components/schemas/CrazyEights.CrazyEightsGame' + ChatRoom.ChatRoom: '#/components/schemas/ChatRoom.ChatRoom' + Bullshit.BullshitGame: '#/components/schemas/Bullshit.BullshitGame' + Data.HistoricBullshitGame: type: object properties: - gameType: - type: string - games: - type: array - items: - $ref: '#/components/schemas/Controllers.GameVm' + game: + $ref: '#/components/schemas/Bullshit.BullshitGame' additionalProperties: false - Controllers.GameVm: - required: - - gameType - - name - - players - - state + Data.HistoricChatRoom: type: object properties: - gameType: - type: string - name: - type: string - state: - $ref: '#/components/schemas/Games.GameState' - players: - type: array - items: - $ref: '#/components/schemas/Common.PlayerData' + game: + $ref: '#/components/schemas/ChatRoom.ChatRoom' additionalProperties: false - Controllers.LoginModel: + Data.HistoricCrazyEightsGame: type: object properties: - username: - type: string - nullable: true - password: - type: string - nullable: true + game: + $ref: '#/components/schemas/CrazyEights.CrazyEightsGame' additionalProperties: false - Controllers.ResponseMessage: + Data.HistoricGabongGame: type: object properties: - message: - type: string - nullable: true + game: + $ref: '#/components/schemas/Gabong.GabongGame' additionalProperties: false - Core.GameInfo: - required: - - id + Data.HistoricHeartsGame: type: object properties: - id: - type: string + game: + $ref: '#/components/schemas/Hearts.HeartsGame' additionalProperties: false - CrazyEights.CardResponse: + Data.HistoricIdiotGame: + type: object + properties: + game: + $ref: '#/components/schemas/Idiot.IdiotGame' + additionalProperties: false + Data.HistoricTexasHoldEmGame: + type: object + properties: + game: + $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + additionalProperties: false + Data.HistoricUnoGame: + type: object + properties: + game: + $ref: '#/components/schemas/Uno.UnoGame' + additionalProperties: false + Data.HistoricYanivGame: + type: object + properties: + game: + $ref: '#/components/schemas/Yaniv.YanivGame' + additionalProperties: false + Gabong.ActionResponse: allOf: - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + additionalProperties: false + Gabong.DrawCardRequest: + allOf: + - $ref: '#/components/schemas/Gabong.GabongRequest' + - type: object + additionalProperties: false + Gabong.GabongCardResponse: + allOf: + - $ref: '#/components/schemas/Gabong.GabongResponse' - required: - card type: object @@ -3623,37 +4401,42 @@ components: card: $ref: '#/components/schemas/Common.Card' additionalProperties: false - CrazyEights.CrazyEightsGame: + Gabong.GabongGame: allOf: - $ref: '#/components/schemas/Games.GameObject' - required: - cardsDrawn + - cardsToDraw - currentPlayer - - currentPlayerIndex - currentSuit - deck - discardPile - - donePlayers - - initialCardsPerPlayer + - gabongMasterId + - gameDirection + - isBetweenRounds + - lastPlayMadeByPlayerIndex - players - - spectators - stockPile - topOfPile type: object properties: - initialCardsPerPlayer: + lastPlayMadeByPlayerIndex: type: integer format: int32 - currentPlayerIndex: + cardsToDraw: type: integer format: int32 cardsDrawn: type: integer format: int32 - donePlayers: - type: array - items: - $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + gameDirection: + type: integer + format: int32 + gabongMasterId: + type: string + format: uuid + isBetweenRounds: + type: boolean deck: type: array items: @@ -3669,11 +4452,7 @@ components: players: type: array items: - $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' - spectators: - type: array - items: - $ref: '#/components/schemas/CrazyEights.CrazyEightsSpectator' + $ref: '#/components/schemas/Gabong.GabongPlayer' newSuit: $ref: '#/components/schemas/Common.Suit' topOfPile: @@ -3681,13 +4460,47 @@ components: currentSuit: $ref: '#/components/schemas/Common.Suit' currentPlayer: - $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + $ref: '#/components/schemas/Gabong.GabongPlayer' additionalProperties: false - CrazyEights.CrazyEightsPlayer: + Gabong.GabongGameNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + additionalProperties: false + discriminator: + propertyName: type + mapping: + Gabong.GabongPlayerNotification: '#/components/schemas/Gabong.GabongPlayerNotification' + Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' + Gabong.PlayerDrewCardNotification: '#/components/schemas/Gabong.PlayerDrewCardNotification' + Gabong.PlayerDrewPenaltyCardNotification: '#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification' + Gabong.GameStartedNotification: '#/components/schemas/Gabong.GameStartedNotification' + Gabong.GameEndedNotification: '#/components/schemas/Gabong.GameEndedNotification' + Gabong.RoundStartedNotification: '#/components/schemas/Gabong.RoundStartedNotification' + Gabong.RoundEndedNotification: '#/components/schemas/Gabong.RoundEndedNotification' + Gabong.PlayerLostTheirTurnNotification: '#/components/schemas/Gabong.PlayerLostTheirTurnNotification' + Gabong.GabongPlay: + enum: + - CardPlayed + - TurnLost + - RoundStarted + type: string + Gabong.GabongPlayer: required: + - bongas - cards + - cardsPlayed + - debtDrawn + - gabongs + - hasWon - id - name + - passes + - penalties + - roundsWon + - score + - shots + - turnsLost type: object properties: id: @@ -3699,35 +4512,93 @@ components: type: array items: $ref: '#/components/schemas/Common.Card' + readOnly: true + score: + type: integer + format: int32 + hasWon: + type: boolean + readOnly: true + penalties: + type: integer + format: int32 + gabongs: + type: integer + format: int32 + bongas: + type: integer + format: int32 + shots: + type: integer + format: int32 + cardsPlayed: + type: integer + format: int32 + debtDrawn: + type: integer + format: int32 + passes: + type: integer + format: int32 + turnsLost: + type: integer + format: int32 + roundsWon: + type: integer + format: int32 additionalProperties: false - CrazyEights.CrazyEightsSpectator: - required: - - id - - name - type: object - properties: - id: - type: string - format: uuid - name: - type: string - additionalProperties: false - CrazyEights.DiscardPileShuffledNotification: + Gabong.GabongPlayerNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - type: object + - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid additionalProperties: false - CrazyEights.DrawCardRequest: + discriminator: + propertyName: type + mapping: + Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' + Gabong.PlayerDrewCardNotification: '#/components/schemas/Gabong.PlayerDrewCardNotification' + Gabong.PlayerDrewPenaltyCardNotification: '#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification' + Gabong.PlayerLostTheirTurnNotification: '#/components/schemas/Gabong.PlayerLostTheirTurnNotification' + Gabong.GabongRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - type: object additionalProperties: false - CrazyEights.GameEndedNotification: + discriminator: + propertyName: type + mapping: + Gabong.PutCardRequest: '#/components/schemas/Gabong.PutCardRequest' + Gabong.DrawCardRequest: '#/components/schemas/Gabong.DrawCardRequest' + Gabong.PassRequest: '#/components/schemas/Gabong.PassRequest' + Gabong.PlayGabongRequest: '#/components/schemas/Gabong.PlayGabongRequest' + Gabong.PlayBongaRequest: '#/components/schemas/Gabong.PlayBongaRequest' + Gabong.GabongResponse: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - required: + - cardsAdded + type: object + properties: + cardsAdded: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + discriminator: + propertyName: type + mapping: + Gabong.GabongCardResponse: '#/components/schemas/Gabong.GabongCardResponse' + Gabong.PlayerViewOfGame: '#/components/schemas/Gabong.PlayerViewOfGame' + Gabong.GameEndedNotification: + allOf: + - $ref: '#/components/schemas/Gabong.GabongGameNotification' - required: - - loserId - - loserName - players type: object properties: @@ -3735,140 +4606,110 @@ components: type: array items: $ref: '#/components/schemas/Common.PlayerData' - loserId: - type: string - format: uuid - loserName: - type: string additionalProperties: false - CrazyEights.GameStartedNotification: + Gabong.GameStartedNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Gabong.GabongGameNotification' - required: - gameId - - playerViewOfGame type: object properties: gameId: type: string format: uuid - playerViewOfGame: - $ref: '#/components/schemas/CrazyEights.PlayerViewOfGame' additionalProperties: false - CrazyEights.ItsPlayersTurnNotification: + Gabong.PassRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid + - $ref: '#/components/schemas/Gabong.GabongRequest' + - type: object additionalProperties: false - CrazyEights.ItsYourTurnNotification: + Gabong.PenalizePlayerForTakingTooLongRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerViewOfGame - type: object - properties: - playerViewOfGame: - $ref: '#/components/schemas/CrazyEights.PlayerViewOfGame' + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object additionalProperties: false - CrazyEights.OtherCrazyEightsPlayer: - required: - - name - - numberOfCards - - playerId - type: object - properties: - playerId: - type: string - format: uuid - name: - type: string - numberOfCards: - type: integer - format: int32 - additionalProperties: false - CrazyEights.PassRequest: + Gabong.PenalizePlayerForTooManyCardsRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - type: object additionalProperties: false - CrazyEights.PlayerDrewCardNotification: + Gabong.PenaltyReason: + enum: + - PlayOutOfTurn + - TookTooLong + - WrongPlay + - WrongGabong + - WrongBonga + - UnpaidDebt + - PassWithoutDrawing + type: string + Gabong.PlayBongaRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid + - $ref: '#/components/schemas/Gabong.GabongRequest' + - type: object additionalProperties: false - CrazyEights.PlayerIsDoneNotification: + Gabong.PlayGabongRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid + - $ref: '#/components/schemas/Gabong.GabongRequest' + - type: object additionalProperties: false - CrazyEights.PlayerPassedNotification: + Gabong.PlayerDrewCardNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - type: object + additionalProperties: false + Gabong.PlayerDrewPenaltyCardNotification: + allOf: + - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' - required: - - playerId + - penaltyReason type: object properties: - playerId: - type: string - format: uuid + penaltyReason: + $ref: '#/components/schemas/Gabong.PenaltyReason' additionalProperties: false - CrazyEights.PlayerPutCardNotification: + Gabong.PlayerLostTheirTurnNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' - required: - - card - - playerId + - lostTurnReason type: object properties: - playerId: - type: string - format: uuid - card: - $ref: '#/components/schemas/Common.Card' + lostTurnReason: + $ref: '#/components/schemas/Gabong.PlayerLostTurnReason' additionalProperties: false - CrazyEights.PlayerPutEightNotification: + Gabong.PlayerLostTurnReason: + enum: + - Passed + - WrongPlay + - TookTooLong + - FinishedDrawingCardDebt + type: string + Gabong.PlayerPutCardNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' - required: - card - - newSuit - - playerId type: object properties: - playerId: - type: string - format: uuid card: $ref: '#/components/schemas/Common.Card' newSuit: $ref: '#/components/schemas/Common.Suit' additionalProperties: false - CrazyEights.PlayerViewOfGame: + Gabong.PlayerViewOfGame: allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' + - $ref: '#/components/schemas/Gabong.GabongResponse' - required: + - cardDebtToDraw - cards - currentSuit - discardPileCount - - otherPlayers + - lastPlay + - lastPlayMadeByPlayerId + - players + - playersOrder + - roundStarted - stockPileCount - topOfPile type: object @@ -3887,27 +4728,31 @@ components: discardPileCount: type: integer format: int32 - otherPlayers: + roundStarted: + type: boolean + lastPlayMadeByPlayerId: + type: string + format: uuid + lastPlay: + $ref: '#/components/schemas/Gabong.GabongPlay' + players: type: array items: - $ref: '#/components/schemas/CrazyEights.OtherCrazyEightsPlayer' - additionalProperties: false - CrazyEights.PutCardRequest: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' - - required: - - card - type: object - properties: - card: - $ref: '#/components/schemas/Common.Card' + $ref: '#/components/schemas/Gabong.SlimGabongPlayer' + playersOrder: + type: array + items: + type: string + format: uuid + cardDebtToDraw: + type: integer + format: int32 additionalProperties: false - CrazyEights.PutEightRequest: + Gabong.PutCardRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' + - $ref: '#/components/schemas/Gabong.GabongRequest' - required: - card - - newSuit type: object properties: card: @@ -3915,199 +4760,37 @@ components: newSuit: $ref: '#/components/schemas/Common.Suit' additionalProperties: false - Data.DatabaseObject: - required: - - id - - type - type: object - properties: - type: - type: string - readOnly: true - id: - type: string - format: uuid - additionalProperties: false - discriminator: - propertyName: type - mapping: - Games.GameObject: '#/components/schemas/Games.GameObject' - Yaniv.YanivGame: '#/components/schemas/Yaniv.YanivGame' - Uno.UnoGame: '#/components/schemas/Uno.UnoGame' - TexasHoldEm.TexasHoldEmGame: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' - Idiot.IdiotGame: '#/components/schemas/Idiot.IdiotGame' - Gabong.GabongGame: '#/components/schemas/Gabong.GabongGame' - CrazyEights.CrazyEightsGame: '#/components/schemas/CrazyEights.CrazyEightsGame' - ChatRoom.ChatRoom: '#/components/schemas/ChatRoom.ChatRoom' - Bullshit.BullshitGame: '#/components/schemas/Bullshit.BullshitGame' - Data.HistoricBullshitGame: - type: object - properties: - game: - $ref: '#/components/schemas/Bullshit.BullshitGame' - additionalProperties: false - Data.HistoricChatRoom: - type: object - properties: - game: - $ref: '#/components/schemas/ChatRoom.ChatRoom' - additionalProperties: false - Data.HistoricCrazyEightsGame: - type: object - properties: - game: - $ref: '#/components/schemas/CrazyEights.CrazyEightsGame' - additionalProperties: false - Data.HistoricGabongGame: - type: object - properties: - game: - $ref: '#/components/schemas/Gabong.GabongGame' - additionalProperties: false - Data.HistoricIdiotGame: - type: object - properties: - game: - $ref: '#/components/schemas/Idiot.IdiotGame' - additionalProperties: false - Data.HistoricTexasHoldEmGame: - type: object - properties: - game: - $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' - additionalProperties: false - Data.HistoricUnoGame: - type: object - properties: - game: - $ref: '#/components/schemas/Uno.UnoGame' - additionalProperties: false - Data.HistoricYanivGame: - type: object - properties: - game: - $ref: '#/components/schemas/Yaniv.YanivGame' - additionalProperties: false - Gabong.ActionResponse: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' - - type: object - additionalProperties: false - Gabong.DrawCardRequest: - allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' - - type: object - additionalProperties: false - Gabong.GabongCardResponse: - allOf: - - $ref: '#/components/schemas/Gabong.GabongResponse' - - required: - - card - type: object - properties: - card: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Gabong.GabongGame: + Gabong.RoundEndedNotification: allOf: - - $ref: '#/components/schemas/Games.GameObject' + - $ref: '#/components/schemas/Gabong.GabongGameNotification' - required: - - cardsDrawn - - cardsToDraw - - currentPlayer - - currentSuit - - deck - - discardPile - - gabongMasterId - - gameDirection - - isBetweenRounds - - lastPlayMadeByPlayerIndex - players - - stockPile - - topOfPile type: object properties: - lastPlayMadeByPlayerIndex: - type: integer - format: int32 - cardsToDraw: - type: integer - format: int32 - cardsDrawn: - type: integer - format: int32 - gameDirection: - type: integer - format: int32 - gabongMasterId: - type: string - format: uuid - isBetweenRounds: - type: boolean - deck: - type: array - items: - $ref: '#/components/schemas/Common.Card' - stockPile: - type: array - items: - $ref: '#/components/schemas/Common.Card' - discardPile: - type: array - items: - $ref: '#/components/schemas/Common.Card' players: type: array items: - $ref: '#/components/schemas/Gabong.GabongPlayer' - newSuit: - $ref: '#/components/schemas/Common.Suit' - topOfPile: - $ref: '#/components/schemas/Common.Card' - currentSuit: - $ref: '#/components/schemas/Common.Suit' - currentPlayer: - $ref: '#/components/schemas/Gabong.GabongPlayer' + $ref: '#/components/schemas/Common.PlayerData' additionalProperties: false - Gabong.GabongGameNotification: + Gabong.RoundStartedNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - type: object - additionalProperties: false - discriminator: - propertyName: type - mapping: - Gabong.GabongPlayerNotification: '#/components/schemas/Gabong.GabongPlayerNotification' - Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' - Gabong.PlayerDrewCardNotification: '#/components/schemas/Gabong.PlayerDrewCardNotification' - Gabong.PlayerDrewPenaltyCardNotification: '#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification' - Gabong.GameStartedNotification: '#/components/schemas/Gabong.GameStartedNotification' - Gabong.GameEndedNotification: '#/components/schemas/Gabong.GameEndedNotification' - Gabong.RoundStartedNotification: '#/components/schemas/Gabong.RoundStartedNotification' - Gabong.RoundEndedNotification: '#/components/schemas/Gabong.RoundEndedNotification' - Gabong.PlayerLostTheirTurnNotification: '#/components/schemas/Gabong.PlayerLostTheirTurnNotification' - Gabong.GabongPlay: - enum: - - CardPlayed - - TurnLost - - RoundStarted - type: string - Gabong.GabongPlayer: + - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - required: + - playerViewOfGame + - startingPlayerId + type: object + properties: + playerViewOfGame: + $ref: '#/components/schemas/Gabong.PlayerViewOfGame' + startingPlayerId: + type: string + format: uuid + additionalProperties: false + Gabong.SlimGabongPlayer: required: - - bongas - - cards - - cardsPlayed - - debtDrawn - - gabongs - - hasWon - id - name - - passes - - penalties - - roundsWon - - score - - shots - - turnsLost + - numberOfCards type: object properties: id: @@ -4115,382 +4798,475 @@ components: format: uuid name: type: string - cards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - readOnly: true - score: - type: integer - format: int32 - hasWon: - type: boolean - readOnly: true - penalties: - type: integer - format: int32 - gabongs: - type: integer - format: int32 - bongas: - type: integer - format: int32 - shots: - type: integer - format: int32 - cardsPlayed: - type: integer - format: int32 - debtDrawn: - type: integer - format: int32 - passes: - type: integer - format: int32 - turnsLost: - type: integer - format: int32 - roundsWon: + numberOfCards: type: integer format: int32 additionalProperties: false - Gabong.GabongPlayerNotification: + Games.GameObject: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Data.DatabaseObject' - required: - - playerId + - name + - seed + - startedTime + - state + - version type: object properties: - playerId: + name: type: string - format: uuid + startedTime: + type: string + format: date-time + state: + $ref: '#/components/schemas/Games.GameState' + version: + type: integer + format: int32 + seed: + type: integer + format: int32 additionalProperties: false discriminator: propertyName: type mapping: - Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' - Gabong.PlayerDrewCardNotification: '#/components/schemas/Gabong.PlayerDrewCardNotification' - Gabong.PlayerDrewPenaltyCardNotification: '#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification' - Gabong.PlayerLostTheirTurnNotification: '#/components/schemas/Gabong.PlayerLostTheirTurnNotification' - Gabong.GabongRequest: + Yaniv.YanivGame: '#/components/schemas/Yaniv.YanivGame' + Uno.UnoGame: '#/components/schemas/Uno.UnoGame' + TexasHoldEm.TexasHoldEmGame: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + Idiot.IdiotGame: '#/components/schemas/Idiot.IdiotGame' + Hearts.HeartsGame: '#/components/schemas/Hearts.HeartsGame' + Gabong.GabongGame: '#/components/schemas/Gabong.GabongGame' + CrazyEights.CrazyEightsGame: '#/components/schemas/CrazyEights.CrazyEightsGame' + ChatRoom.ChatRoom: '#/components/schemas/ChatRoom.ChatRoom' + Bullshit.BullshitGame: '#/components/schemas/Bullshit.BullshitGame' + Games.GameState: + enum: + - Waiting + - Running + - Finished + - RoundFinished + type: string + Handshake.ConnectFailureMessage: allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' + - $ref: '#/components/schemas/Handshake.ConnectMessage' + - required: + - errorMessage + type: object + properties: + errorMessage: + type: string + additionalProperties: false + Handshake.ConnectMessage: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterMessage' - type: object additionalProperties: false discriminator: propertyName: type mapping: - Gabong.PutCardRequest: '#/components/schemas/Gabong.PutCardRequest' - Gabong.DrawCardRequest: '#/components/schemas/Gabong.DrawCardRequest' - Gabong.PassRequest: '#/components/schemas/Gabong.PassRequest' - Gabong.PlayGabongRequest: '#/components/schemas/Gabong.PlayGabongRequest' - Gabong.PlayBongaRequest: '#/components/schemas/Gabong.PlayBongaRequest' - Gabong.GabongResponse: + Handshake.HelloSuccessMessage: '#/components/schemas/Handshake.HelloSuccessMessage' + Handshake.ConnectSuccessMessage: '#/components/schemas/Handshake.ConnectSuccessMessage' + Handshake.ConnectFailureMessage: '#/components/schemas/Handshake.ConnectFailureMessage' + Handshake.ConnectSuccessMessage: allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' + - $ref: '#/components/schemas/Handshake.ConnectMessage' + - type: object + additionalProperties: false + Handshake.HelloSuccessMessage: + allOf: + - $ref: '#/components/schemas/Handshake.ConnectMessage' - required: - - cardsAdded + - connectionId + - player type: object properties: - cardsAdded: + player: + $ref: '#/components/schemas/Common.PlayerData' + connectionId: + type: string + format: uuid + additionalProperties: false + Hearts.AllPlayersPassedNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - receivedCards + type: object + properties: + receivedCards: type: array items: $ref: '#/components/schemas/Common.Card' additionalProperties: false - discriminator: - propertyName: type - mapping: - Gabong.GabongCardResponse: '#/components/schemas/Gabong.GabongCardResponse' - Gabong.PlayerViewOfGame: '#/components/schemas/Gabong.PlayerViewOfGame' - Gabong.GameEndedNotification: + Hearts.CardPlay: + required: + - card + - playerId + - playerName + type: object + properties: + playerId: + type: string + format: uuid + playerName: + type: string + card: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Hearts.GameEndedNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - players + - finalScores + - winnerId + - winnerName type: object properties: - players: + finalScores: type: array items: - $ref: '#/components/schemas/Common.PlayerData' + $ref: '#/components/schemas/Hearts.PlayerScore' + winnerId: + type: string + format: uuid + winnerName: + type: string additionalProperties: false - Gabong.GameStartedNotification: + Hearts.GamePhase: + enum: + - Passing + - Playing + type: string + Hearts.GameStartedNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - gameId + - playerViewOfGame type: object properties: gameId: type: string format: uuid + playerViewOfGame: + $ref: '#/components/schemas/Hearts.PlayerViewOfGame' additionalProperties: false - Gabong.PassRequest: - allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' - - type: object - additionalProperties: false - Gabong.PenalizePlayerForTakingTooLongRequest: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' - - type: object - additionalProperties: false - Gabong.PenalizePlayerForTooManyCardsRequest: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' - - type: object - additionalProperties: false - Gabong.PenaltyReason: - enum: - - PlayOutOfTurn - - TookTooLong - - WrongPlay - - WrongGabong - - WrongBonga - - UnpaidDebt - - PassWithoutDrawing - type: string - Gabong.PlayBongaRequest: - allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' - - type: object - additionalProperties: false - Gabong.PlayGabongRequest: - allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' - - type: object - additionalProperties: false - Gabong.PlayerDrewCardNotification: + Hearts.HeartsAreBrokenNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - type: object additionalProperties: false - Gabong.PlayerDrewPenaltyCardNotification: + Hearts.HeartsGame: allOf: - - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - $ref: '#/components/schemas/Games.GameObject' - required: - - penaltyReason + - currentPassDirection + - currentPlayer + - currentPlayerIndex + - currentTrick + - deck + - heartsAreBroken + - isFirstTrick + - phase + - players + - roundNumber type: object properties: - penaltyReason: - $ref: '#/components/schemas/Gabong.PenaltyReason' + deck: + type: array + items: + $ref: '#/components/schemas/Common.Card' + players: + type: array + items: + $ref: '#/components/schemas/Hearts.HeartsPlayer' + currentPlayerIndex: + type: integer + format: int32 + roundNumber: + type: integer + format: int32 + heartsAreBroken: + type: boolean + currentTrick: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + leadSuit: + $ref: '#/components/schemas/Common.Suit' + isFirstTrick: + type: boolean + phase: + $ref: '#/components/schemas/Hearts.GamePhase' + currentPlayer: + $ref: '#/components/schemas/Hearts.HeartsPlayer' + currentPassDirection: + $ref: '#/components/schemas/Hearts.PassDirection' additionalProperties: false - Gabong.PlayerLostTheirTurnNotification: + Hearts.HeartsPlayer: + required: + - cards + - cardsToPass + - hasPassed + - id + - name + - roundScore + - totalScore + type: object + properties: + id: + type: string + format: uuid + name: + type: string + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + cardsToPass: + type: array + items: + $ref: '#/components/schemas/Common.Card' + hasPassed: + type: boolean + roundScore: + type: integer + format: int32 + totalScore: + type: integer + format: int32 + playedCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Hearts.ItsPlayersTurnNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - lostTurnReason + - playerId type: object properties: - lostTurnReason: - $ref: '#/components/schemas/Gabong.PlayerLostTurnReason' + playerId: + type: string + format: uuid additionalProperties: false - Gabong.PlayerLostTurnReason: - enum: - - Passed - - WrongPlay - - TookTooLong - - FinishedDrawingCardDebt - type: string - Gabong.PlayerPutCardNotification: + Hearts.ItsYourTurnNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - card + - playerViewOfGame type: object properties: - card: - $ref: '#/components/schemas/Common.Card' - newSuit: - $ref: '#/components/schemas/Common.Suit' + playerViewOfGame: + $ref: '#/components/schemas/Hearts.PlayerViewOfGame' additionalProperties: false - Gabong.PlayerViewOfGame: + Hearts.OtherHeartsPlayer: + required: + - name + - numberOfCards + - playerId + - roundScore + - totalScore + type: object + properties: + playerId: + type: string + format: uuid + name: + type: string + numberOfCards: + type: integer + format: int32 + totalScore: + type: integer + format: int32 + roundScore: + type: integer + format: int32 + playedCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Hearts.PassCardsRequest: allOf: - - $ref: '#/components/schemas/Gabong.GabongResponse' + - $ref: '#/components/schemas/Protocol.DecksterRequest' - required: - - cardDebtToDraw - cards - - currentSuit - - discardPileCount - - lastPlay - - lastPlayMadeByPlayerId - - players - - playersOrder - - roundStarted - - stockPileCount - - topOfPile type: object properties: cards: type: array items: $ref: '#/components/schemas/Common.Card' - topOfPile: - $ref: '#/components/schemas/Common.Card' - currentSuit: - $ref: '#/components/schemas/Common.Suit' - stockPileCount: - type: integer - format: int32 - discardPileCount: - type: integer - format: int32 - roundStarted: - type: boolean - lastPlayMadeByPlayerId: - type: string - format: uuid - lastPlay: - $ref: '#/components/schemas/Gabong.GabongPlay' - players: - type: array - items: - $ref: '#/components/schemas/Gabong.SlimGabongPlayer' - playersOrder: + additionalProperties: false + Hearts.PassCardsResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + properties: + receivedCards: type: array items: - type: string - format: uuid - cardDebtToDraw: - type: integer - format: int32 + $ref: '#/components/schemas/Common.Card' + nullable: true additionalProperties: false - Gabong.PutCardRequest: + Hearts.PassDirection: + enum: + - None + - Left + - Right + - Across + type: string + Hearts.PassingPhaseStartedNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - passDirection + type: object + properties: + passDirection: + $ref: '#/components/schemas/Hearts.PassDirection' + additionalProperties: false + Hearts.PlayCardRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' - required: - card type: object properties: card: $ref: '#/components/schemas/Common.Card' - newSuit: - $ref: '#/components/schemas/Common.Suit' additionalProperties: false - Gabong.RoundEndedNotification: + Hearts.PlayerPassedCardsNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - players + - playerId type: object properties: - players: - type: array - items: - $ref: '#/components/schemas/Common.PlayerData' + playerId: + type: string + format: uuid additionalProperties: false - Gabong.RoundStartedNotification: + Hearts.PlayerPlayedCardNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - playerViewOfGame - - startingPlayerId + - card + - playerId type: object properties: - playerViewOfGame: - $ref: '#/components/schemas/Gabong.PlayerViewOfGame' - startingPlayerId: + playerId: type: string format: uuid + card: + $ref: '#/components/schemas/Common.Card' additionalProperties: false - Gabong.SlimGabongPlayer: + Hearts.PlayerScore: required: - - id - - name - - numberOfCards + - playerId + - playerName + - roundScore + - totalScore type: object properties: - id: + playerId: type: string format: uuid - name: + playerName: type: string - numberOfCards: + roundScore: + type: integer + format: int32 + totalScore: type: integer format: int32 additionalProperties: false - Games.GameObject: + Hearts.PlayerViewOfGame: allOf: - - $ref: '#/components/schemas/Data.DatabaseObject' + - $ref: '#/components/schemas/Protocol.DecksterResponse' - required: - - name - - seed - - startedTime - - state - - version + - cards + - currentTrick + - hasPassed + - heartsAreBroken + - isMyTurn + - otherPlayers + - passDirection + - roundNumber + - roundScore + - totalScore type: object properties: - name: - type: string - startedTime: - type: string - format: date-time - state: - $ref: '#/components/schemas/Games.GameState' - version: + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + otherPlayers: + type: array + items: + $ref: '#/components/schemas/Hearts.OtherHeartsPlayer' + roundNumber: type: integer format: int32 - seed: + passDirection: + $ref: '#/components/schemas/Hearts.PassDirection' + hasPassed: + type: boolean + currentTrick: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + totalScore: type: integer format: int32 + roundScore: + type: integer + format: int32 + heartsAreBroken: + type: boolean + isMyTurn: + type: boolean additionalProperties: false - discriminator: - propertyName: type - mapping: - Yaniv.YanivGame: '#/components/schemas/Yaniv.YanivGame' - Uno.UnoGame: '#/components/schemas/Uno.UnoGame' - TexasHoldEm.TexasHoldEmGame: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' - Idiot.IdiotGame: '#/components/schemas/Idiot.IdiotGame' - Gabong.GabongGame: '#/components/schemas/Gabong.GabongGame' - CrazyEights.CrazyEightsGame: '#/components/schemas/CrazyEights.CrazyEightsGame' - ChatRoom.ChatRoom: '#/components/schemas/ChatRoom.ChatRoom' - Bullshit.BullshitGame: '#/components/schemas/Bullshit.BullshitGame' - Games.GameState: - enum: - - Waiting - - Running - - Finished - - RoundFinished - type: string - Handshake.ConnectFailureMessage: + Hearts.RoundEndedNotification: allOf: - - $ref: '#/components/schemas/Handshake.ConnectMessage' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - errorMessage + - scores type: object properties: - errorMessage: + scores: + type: array + items: + $ref: '#/components/schemas/Hearts.PlayerScore' + moonShooterId: type: string + format: uuid + nullable: true + moonShooterName: + type: string + nullable: true additionalProperties: false - Handshake.ConnectMessage: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterMessage' - - type: object - additionalProperties: false - discriminator: - propertyName: type - mapping: - Handshake.HelloSuccessMessage: '#/components/schemas/Handshake.HelloSuccessMessage' - Handshake.ConnectSuccessMessage: '#/components/schemas/Handshake.ConnectSuccessMessage' - Handshake.ConnectFailureMessage: '#/components/schemas/Handshake.ConnectFailureMessage' - Handshake.ConnectSuccessMessage: - allOf: - - $ref: '#/components/schemas/Handshake.ConnectMessage' - - type: object - additionalProperties: false - Handshake.HelloSuccessMessage: + Hearts.TrickCompletedNotification: allOf: - - $ref: '#/components/schemas/Handshake.ConnectMessage' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - connectionId - - player + - points + - trickCards + - winnerId + - winnerName type: object properties: - player: - $ref: '#/components/schemas/Common.PlayerData' - connectionId: + winnerId: type: string format: uuid + winnerName: + type: string + trickCards: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + points: + type: integer + format: int32 additionalProperties: false Idiot.DiscardPileFlushedNotification: allOf: @@ -5047,6 +5823,21 @@ components: Idiot.GameStartedNotification: '#/components/schemas/Idiot.GameStartedNotification' Idiot.GameEndedNotification: '#/components/schemas/Idiot.GameEndedNotification' Idiot.ItsTimeToSwapCardsNotification: '#/components/schemas/Idiot.ItsTimeToSwapCardsNotification' + Hearts.PassCardsRequest: '#/components/schemas/Hearts.PassCardsRequest' + Hearts.PlayCardRequest: '#/components/schemas/Hearts.PlayCardRequest' + Hearts.PassCardsResponse: '#/components/schemas/Hearts.PassCardsResponse' + Hearts.GameStartedNotification: '#/components/schemas/Hearts.GameStartedNotification' + Hearts.PassingPhaseStartedNotification: '#/components/schemas/Hearts.PassingPhaseStartedNotification' + Hearts.AllPlayersPassedNotification: '#/components/schemas/Hearts.AllPlayersPassedNotification' + Hearts.PlayerPassedCardsNotification: '#/components/schemas/Hearts.PlayerPassedCardsNotification' + Hearts.ItsYourTurnNotification: '#/components/schemas/Hearts.ItsYourTurnNotification' + Hearts.ItsPlayersTurnNotification: '#/components/schemas/Hearts.ItsPlayersTurnNotification' + Hearts.PlayerPlayedCardNotification: '#/components/schemas/Hearts.PlayerPlayedCardNotification' + Hearts.TrickCompletedNotification: '#/components/schemas/Hearts.TrickCompletedNotification' + Hearts.RoundEndedNotification: '#/components/schemas/Hearts.RoundEndedNotification' + Hearts.GameEndedNotification: '#/components/schemas/Hearts.GameEndedNotification' + Hearts.HeartsAreBrokenNotification: '#/components/schemas/Hearts.HeartsAreBrokenNotification' + Hearts.PlayerViewOfGame: '#/components/schemas/Hearts.PlayerViewOfGame' Gabong.GabongGameNotification: '#/components/schemas/Gabong.GabongGameNotification' Gabong.GabongPlayerNotification: '#/components/schemas/Gabong.GabongPlayerNotification' Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' @@ -5158,6 +5949,17 @@ components: Idiot.GameStartedNotification: '#/components/schemas/Idiot.GameStartedNotification' Idiot.GameEndedNotification: '#/components/schemas/Idiot.GameEndedNotification' Idiot.ItsTimeToSwapCardsNotification: '#/components/schemas/Idiot.ItsTimeToSwapCardsNotification' + Hearts.GameStartedNotification: '#/components/schemas/Hearts.GameStartedNotification' + Hearts.PassingPhaseStartedNotification: '#/components/schemas/Hearts.PassingPhaseStartedNotification' + Hearts.AllPlayersPassedNotification: '#/components/schemas/Hearts.AllPlayersPassedNotification' + Hearts.PlayerPassedCardsNotification: '#/components/schemas/Hearts.PlayerPassedCardsNotification' + Hearts.ItsYourTurnNotification: '#/components/schemas/Hearts.ItsYourTurnNotification' + Hearts.ItsPlayersTurnNotification: '#/components/schemas/Hearts.ItsPlayersTurnNotification' + Hearts.PlayerPlayedCardNotification: '#/components/schemas/Hearts.PlayerPlayedCardNotification' + Hearts.TrickCompletedNotification: '#/components/schemas/Hearts.TrickCompletedNotification' + Hearts.RoundEndedNotification: '#/components/schemas/Hearts.RoundEndedNotification' + Hearts.GameEndedNotification: '#/components/schemas/Hearts.GameEndedNotification' + Hearts.HeartsAreBrokenNotification: '#/components/schemas/Hearts.HeartsAreBrokenNotification' Gabong.GabongGameNotification: '#/components/schemas/Gabong.GabongGameNotification' Gabong.GabongPlayerNotification: '#/components/schemas/Gabong.GabongPlayerNotification' Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' @@ -5223,6 +6025,8 @@ components: Idiot.DrawCardsRequest: '#/components/schemas/Idiot.DrawCardsRequest' Idiot.PullInDiscardPileRequest: '#/components/schemas/Idiot.PullInDiscardPileRequest' Idiot.PutChanceCardRequest: '#/components/schemas/Idiot.PutChanceCardRequest' + Hearts.PassCardsRequest: '#/components/schemas/Hearts.PassCardsRequest' + Hearts.PlayCardRequest: '#/components/schemas/Hearts.PlayCardRequest' Gabong.PenalizePlayerForTakingTooLongRequest: '#/components/schemas/Gabong.PenalizePlayerForTakingTooLongRequest' Gabong.PenalizePlayerForTooManyCardsRequest: '#/components/schemas/Gabong.PenalizePlayerForTooManyCardsRequest' Gabong.GabongRequest: '#/components/schemas/Gabong.GabongRequest' @@ -5265,6 +6069,8 @@ components: Idiot.PullInResponse: '#/components/schemas/Idiot.PullInResponse' Idiot.DrawCardsResponse: '#/components/schemas/Idiot.DrawCardsResponse' Idiot.PutBlindCardResponse: '#/components/schemas/Idiot.PutBlindCardResponse' + Hearts.PassCardsResponse: '#/components/schemas/Hearts.PassCardsResponse' + Hearts.PlayerViewOfGame: '#/components/schemas/Hearts.PlayerViewOfGame' Gabong.GabongResponse: '#/components/schemas/Gabong.GabongResponse' Gabong.GabongCardResponse: '#/components/schemas/Gabong.GabongCardResponse' Gabong.ActionResponse: '#/components/schemas/Gabong.ActionResponse' diff --git a/generated/deckster.opeanpi.json b/generated/deckster.opeanpi.json index e6889130..f4412858 100644 --- a/generated/deckster.opeanpi.json +++ b/generated/deckster.opeanpi.json @@ -1,5 +1,5 @@ { - "openapi": "3.0.1", + "openapi": "3.0.4", "info": { "title": "Deckster", "description": "Deckster", @@ -91,6 +91,21 @@ "Idiot.GameStartedNotification": "#/components/schemas/Idiot.GameStartedNotification", "Idiot.GameEndedNotification": "#/components/schemas/Idiot.GameEndedNotification", "Idiot.ItsTimeToSwapCardsNotification": "#/components/schemas/Idiot.ItsTimeToSwapCardsNotification", + "Hearts.PassCardsRequest": "#/components/schemas/Hearts.PassCardsRequest", + "Hearts.PlayCardRequest": "#/components/schemas/Hearts.PlayCardRequest", + "Hearts.PassCardsResponse": "#/components/schemas/Hearts.PassCardsResponse", + "Hearts.GameStartedNotification": "#/components/schemas/Hearts.GameStartedNotification", + "Hearts.PlayerViewOfGame": "#/components/schemas/Hearts.PlayerViewOfGame", + "Hearts.PassingPhaseStartedNotification": "#/components/schemas/Hearts.PassingPhaseStartedNotification", + "Hearts.AllPlayersPassedNotification": "#/components/schemas/Hearts.AllPlayersPassedNotification", + "Hearts.PlayerPassedCardsNotification": "#/components/schemas/Hearts.PlayerPassedCardsNotification", + "Hearts.ItsYourTurnNotification": "#/components/schemas/Hearts.ItsYourTurnNotification", + "Hearts.ItsPlayersTurnNotification": "#/components/schemas/Hearts.ItsPlayersTurnNotification", + "Hearts.PlayerPlayedCardNotification": "#/components/schemas/Hearts.PlayerPlayedCardNotification", + "Hearts.TrickCompletedNotification": "#/components/schemas/Hearts.TrickCompletedNotification", + "Hearts.RoundEndedNotification": "#/components/schemas/Hearts.RoundEndedNotification", + "Hearts.GameEndedNotification": "#/components/schemas/Hearts.GameEndedNotification", + "Hearts.HeartsAreBrokenNotification": "#/components/schemas/Hearts.HeartsAreBrokenNotification", "Gabong.PenalizePlayerForTakingTooLongRequest": "#/components/schemas/Gabong.PenalizePlayerForTakingTooLongRequest", "Gabong.PenalizePlayerForTooManyCardsRequest": "#/components/schemas/Gabong.PenalizePlayerForTooManyCardsRequest", "Gabong.ActionResponse": "#/components/schemas/Gabong.ActionResponse", @@ -191,6 +206,8 @@ "Idiot.DrawCardsRequest": "#/components/schemas/Idiot.DrawCardsRequest", "Idiot.PullInDiscardPileRequest": "#/components/schemas/Idiot.PullInDiscardPileRequest", "Idiot.PutChanceCardRequest": "#/components/schemas/Idiot.PutChanceCardRequest", + "Hearts.PassCardsRequest": "#/components/schemas/Hearts.PassCardsRequest", + "Hearts.PlayCardRequest": "#/components/schemas/Hearts.PlayCardRequest", "Gabong.PenalizePlayerForTakingTooLongRequest": "#/components/schemas/Gabong.PenalizePlayerForTakingTooLongRequest", "Gabong.PenalizePlayerForTooManyCardsRequest": "#/components/schemas/Gabong.PenalizePlayerForTooManyCardsRequest", "CrazyEights.PutCardRequest": "#/components/schemas/CrazyEights.PutCardRequest", @@ -264,6 +281,17 @@ "Idiot.GameStartedNotification": "#/components/schemas/Idiot.GameStartedNotification", "Idiot.GameEndedNotification": "#/components/schemas/Idiot.GameEndedNotification", "Idiot.ItsTimeToSwapCardsNotification": "#/components/schemas/Idiot.ItsTimeToSwapCardsNotification", + "Hearts.GameStartedNotification": "#/components/schemas/Hearts.GameStartedNotification", + "Hearts.PassingPhaseStartedNotification": "#/components/schemas/Hearts.PassingPhaseStartedNotification", + "Hearts.AllPlayersPassedNotification": "#/components/schemas/Hearts.AllPlayersPassedNotification", + "Hearts.PlayerPassedCardsNotification": "#/components/schemas/Hearts.PlayerPassedCardsNotification", + "Hearts.ItsYourTurnNotification": "#/components/schemas/Hearts.ItsYourTurnNotification", + "Hearts.ItsPlayersTurnNotification": "#/components/schemas/Hearts.ItsPlayersTurnNotification", + "Hearts.PlayerPlayedCardNotification": "#/components/schemas/Hearts.PlayerPlayedCardNotification", + "Hearts.TrickCompletedNotification": "#/components/schemas/Hearts.TrickCompletedNotification", + "Hearts.RoundEndedNotification": "#/components/schemas/Hearts.RoundEndedNotification", + "Hearts.GameEndedNotification": "#/components/schemas/Hearts.GameEndedNotification", + "Hearts.HeartsAreBrokenNotification": "#/components/schemas/Hearts.HeartsAreBrokenNotification", "CrazyEights.PlayerPutCardNotification": "#/components/schemas/CrazyEights.PlayerPutCardNotification", "CrazyEights.PlayerPutEightNotification": "#/components/schemas/CrazyEights.PlayerPutEightNotification", "CrazyEights.PlayerDrewCardNotification": "#/components/schemas/CrazyEights.PlayerDrewCardNotification", @@ -328,6 +356,8 @@ "Idiot.PullInResponse": "#/components/schemas/Idiot.PullInResponse", "Idiot.DrawCardsResponse": "#/components/schemas/Idiot.DrawCardsResponse", "Idiot.PutBlindCardResponse": "#/components/schemas/Idiot.PutBlindCardResponse", + "Hearts.PassCardsResponse": "#/components/schemas/Hearts.PassCardsResponse", + "Hearts.PlayerViewOfGame": "#/components/schemas/Hearts.PlayerViewOfGame", "Gabong.ActionResponse": "#/components/schemas/Gabong.ActionResponse", "CrazyEights.CardResponse": "#/components/schemas/CrazyEights.CardResponse", "CrazyEights.PlayerViewOfGame": "#/components/schemas/CrazyEights.PlayerViewOfGame", @@ -2375,6 +2405,539 @@ } } }, + "Hearts.PassCardsRequest": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterRequest" + }, + { + "type": "object", + "properties": { + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + } + } + } + ] + }, + "Hearts.PlayCardRequest": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterRequest" + }, + { + "type": "object", + "properties": { + "card": { + "type": "object", + "properties": { + "rank": { + "type": "integer", + "format": "int32" + }, + "suit": { + "type": "string" + } + } + } + } + } + ] + }, + "Hearts.PassCardsResponse": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "type": "object", + "properties": { + "receivedCards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + } + } + } + ] + }, + "Hearts.GameStartedNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "gameId": { + "type": "string", + "format": "uuid" + }, + "playerViewOfGame": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "type": "object", + "properties": { + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "otherPlayers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.OtherHeartsPlayer" + } + }, + "roundNumber": { + "type": "integer", + "format": "int32" + }, + "passDirection": { + "type": "string" + }, + "hasPassed": { + "type": "boolean" + }, + "currentTrick": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.CardPlay" + } + }, + "totalScore": { + "type": "integer", + "format": "int32" + }, + "roundScore": { + "type": "integer", + "format": "int32" + }, + "heartsAreBroken": { + "type": "boolean" + }, + "isMyTurn": { + "type": "boolean" + } + } + } + ] + } + } + } + ] + }, + "Hearts.PlayerViewOfGame": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "type": "object", + "properties": { + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "otherPlayers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.OtherHeartsPlayer" + } + }, + "roundNumber": { + "type": "integer", + "format": "int32" + }, + "passDirection": { + "type": "string" + }, + "hasPassed": { + "type": "boolean" + }, + "currentTrick": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.CardPlay" + } + }, + "totalScore": { + "type": "integer", + "format": "int32" + }, + "roundScore": { + "type": "integer", + "format": "int32" + }, + "heartsAreBroken": { + "type": "boolean" + }, + "isMyTurn": { + "type": "boolean" + } + } + } + ] + }, + "Hearts.OtherHeartsPlayer": { + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "numberOfCards": { + "type": "integer", + "format": "int32" + }, + "totalScore": { + "type": "integer", + "format": "int32" + }, + "roundScore": { + "type": "integer", + "format": "int32" + }, + "playedCard": { + "type": "object", + "properties": { + "rank": { + "type": "integer", + "format": "int32" + }, + "suit": { + "type": "string" + } + }, + "nullable": true + } + } + }, + "Hearts.CardPlay": { + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "playerName": { + "type": "string" + }, + "card": { + "type": "object", + "properties": { + "rank": { + "type": "integer", + "format": "int32" + }, + "suit": { + "type": "string" + } + }, + "nullable": true + } + } + }, + "Hearts.PassingPhaseStartedNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "passDirection": { + "type": "string" + } + } + } + ] + }, + "Hearts.AllPlayersPassedNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "receivedCards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + } + } + } + ] + }, + "Hearts.PlayerPassedCardsNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + } + } + } + ] + }, + "Hearts.ItsYourTurnNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "playerViewOfGame": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "type": "object", + "properties": { + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "otherPlayers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.OtherHeartsPlayer" + } + }, + "roundNumber": { + "type": "integer", + "format": "int32" + }, + "passDirection": { + "type": "string" + }, + "hasPassed": { + "type": "boolean" + }, + "currentTrick": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.CardPlay" + } + }, + "totalScore": { + "type": "integer", + "format": "int32" + }, + "roundScore": { + "type": "integer", + "format": "int32" + }, + "heartsAreBroken": { + "type": "boolean" + }, + "isMyTurn": { + "type": "boolean" + } + } + } + ] + } + } + } + ] + }, + "Hearts.ItsPlayersTurnNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + } + } + } + ] + }, + "Hearts.PlayerPlayedCardNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "card": { + "type": "object", + "properties": { + "rank": { + "type": "integer", + "format": "int32" + }, + "suit": { + "type": "string" + } + }, + "nullable": true + } + } + } + ] + }, + "Hearts.TrickCompletedNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "winnerId": { + "type": "string", + "format": "uuid" + }, + "winnerName": { + "type": "string" + }, + "trickCards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.CardPlay" + } + }, + "points": { + "type": "integer", + "format": "int32" + } + } + } + ] + }, + "Hearts.RoundEndedNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "scores": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.PlayerScore" + } + }, + "moonShooterId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "moonShooterName": { + "type": "string" + } + } + } + ] + }, + "Hearts.PlayerScore": { + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "playerName": { + "type": "string" + }, + "roundScore": { + "type": "integer", + "format": "int32" + }, + "totalScore": { + "type": "integer", + "format": "int32" + } + } + }, + "Hearts.GameEndedNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "properties": { + "finalScores": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.PlayerScore" + } + }, + "winnerId": { + "type": "string", + "format": "uuid" + }, + "winnerName": { + "type": "string" + } + } + } + ] + }, + "Hearts.HeartsAreBrokenNotification": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object" + } + ] + }, "Gabong.PenalizePlayerForTakingTooLongRequest": { "type": "object", "allOf": [ @@ -2427,7 +2990,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true } } } @@ -2452,7 +3016,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true }, "newSuit": { "type": "string" @@ -2502,7 +3067,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true } } } @@ -2531,7 +3097,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true } } } @@ -2560,7 +3127,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true }, "newSuit": { "type": "string" @@ -2637,7 +3205,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true }, "currentSuit": { "type": "string" @@ -2689,7 +3258,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true }, "currentSuit": { "type": "string" @@ -2783,7 +3353,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true }, "currentSuit": { "type": "string" @@ -2940,7 +3511,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true }, "claimedToBeCard": { "type": "object", @@ -2952,7 +3524,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true } } } @@ -2981,7 +3554,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true } } } @@ -3058,7 +3632,8 @@ "suit": { "type": "string" } - } + }, + "nullable": true } } } diff --git a/generated/deckster.opeanpi.yaml b/generated/deckster.opeanpi.yaml index 44c5ae90..ccce77eb 100644 --- a/generated/deckster.opeanpi.yaml +++ b/generated/deckster.opeanpi.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.0.4 info: title: Deckster description: Deckster @@ -87,6 +87,21 @@ components: Idiot.GameStartedNotification: '#/components/schemas/Idiot.GameStartedNotification' Idiot.GameEndedNotification: '#/components/schemas/Idiot.GameEndedNotification' Idiot.ItsTimeToSwapCardsNotification: '#/components/schemas/Idiot.ItsTimeToSwapCardsNotification' + Hearts.PassCardsRequest: '#/components/schemas/Hearts.PassCardsRequest' + Hearts.PlayCardRequest: '#/components/schemas/Hearts.PlayCardRequest' + Hearts.PassCardsResponse: '#/components/schemas/Hearts.PassCardsResponse' + Hearts.GameStartedNotification: '#/components/schemas/Hearts.GameStartedNotification' + Hearts.PlayerViewOfGame: '#/components/schemas/Hearts.PlayerViewOfGame' + Hearts.PassingPhaseStartedNotification: '#/components/schemas/Hearts.PassingPhaseStartedNotification' + Hearts.AllPlayersPassedNotification: '#/components/schemas/Hearts.AllPlayersPassedNotification' + Hearts.PlayerPassedCardsNotification: '#/components/schemas/Hearts.PlayerPassedCardsNotification' + Hearts.ItsYourTurnNotification: '#/components/schemas/Hearts.ItsYourTurnNotification' + Hearts.ItsPlayersTurnNotification: '#/components/schemas/Hearts.ItsPlayersTurnNotification' + Hearts.PlayerPlayedCardNotification: '#/components/schemas/Hearts.PlayerPlayedCardNotification' + Hearts.TrickCompletedNotification: '#/components/schemas/Hearts.TrickCompletedNotification' + Hearts.RoundEndedNotification: '#/components/schemas/Hearts.RoundEndedNotification' + Hearts.GameEndedNotification: '#/components/schemas/Hearts.GameEndedNotification' + Hearts.HeartsAreBrokenNotification: '#/components/schemas/Hearts.HeartsAreBrokenNotification' Gabong.PenalizePlayerForTakingTooLongRequest: '#/components/schemas/Gabong.PenalizePlayerForTakingTooLongRequest' Gabong.PenalizePlayerForTooManyCardsRequest: '#/components/schemas/Gabong.PenalizePlayerForTooManyCardsRequest' Gabong.ActionResponse: '#/components/schemas/Gabong.ActionResponse' @@ -177,6 +192,8 @@ components: Idiot.DrawCardsRequest: '#/components/schemas/Idiot.DrawCardsRequest' Idiot.PullInDiscardPileRequest: '#/components/schemas/Idiot.PullInDiscardPileRequest' Idiot.PutChanceCardRequest: '#/components/schemas/Idiot.PutChanceCardRequest' + Hearts.PassCardsRequest: '#/components/schemas/Hearts.PassCardsRequest' + Hearts.PlayCardRequest: '#/components/schemas/Hearts.PlayCardRequest' Gabong.PenalizePlayerForTakingTooLongRequest: '#/components/schemas/Gabong.PenalizePlayerForTakingTooLongRequest' Gabong.PenalizePlayerForTooManyCardsRequest: '#/components/schemas/Gabong.PenalizePlayerForTooManyCardsRequest' CrazyEights.PutCardRequest: '#/components/schemas/CrazyEights.PutCardRequest' @@ -242,6 +259,17 @@ components: Idiot.GameStartedNotification: '#/components/schemas/Idiot.GameStartedNotification' Idiot.GameEndedNotification: '#/components/schemas/Idiot.GameEndedNotification' Idiot.ItsTimeToSwapCardsNotification: '#/components/schemas/Idiot.ItsTimeToSwapCardsNotification' + Hearts.GameStartedNotification: '#/components/schemas/Hearts.GameStartedNotification' + Hearts.PassingPhaseStartedNotification: '#/components/schemas/Hearts.PassingPhaseStartedNotification' + Hearts.AllPlayersPassedNotification: '#/components/schemas/Hearts.AllPlayersPassedNotification' + Hearts.PlayerPassedCardsNotification: '#/components/schemas/Hearts.PlayerPassedCardsNotification' + Hearts.ItsYourTurnNotification: '#/components/schemas/Hearts.ItsYourTurnNotification' + Hearts.ItsPlayersTurnNotification: '#/components/schemas/Hearts.ItsPlayersTurnNotification' + Hearts.PlayerPlayedCardNotification: '#/components/schemas/Hearts.PlayerPlayedCardNotification' + Hearts.TrickCompletedNotification: '#/components/schemas/Hearts.TrickCompletedNotification' + Hearts.RoundEndedNotification: '#/components/schemas/Hearts.RoundEndedNotification' + Hearts.GameEndedNotification: '#/components/schemas/Hearts.GameEndedNotification' + Hearts.HeartsAreBrokenNotification: '#/components/schemas/Hearts.HeartsAreBrokenNotification' CrazyEights.PlayerPutCardNotification: '#/components/schemas/CrazyEights.PlayerPutCardNotification' CrazyEights.PlayerPutEightNotification: '#/components/schemas/CrazyEights.PlayerPutEightNotification' CrazyEights.PlayerDrewCardNotification: '#/components/schemas/CrazyEights.PlayerDrewCardNotification' @@ -295,6 +323,8 @@ components: Idiot.PullInResponse: '#/components/schemas/Idiot.PullInResponse' Idiot.DrawCardsResponse: '#/components/schemas/Idiot.DrawCardsResponse' Idiot.PutBlindCardResponse: '#/components/schemas/Idiot.PutBlindCardResponse' + Hearts.PassCardsResponse: '#/components/schemas/Hearts.PassCardsResponse' + Hearts.PlayerViewOfGame: '#/components/schemas/Hearts.PlayerViewOfGame' Gabong.ActionResponse: '#/components/schemas/Gabong.ActionResponse' CrazyEights.CardResponse: '#/components/schemas/CrazyEights.CardResponse' CrazyEights.PlayerViewOfGame: '#/components/schemas/CrazyEights.PlayerViewOfGame' @@ -1494,6 +1524,325 @@ components: cardsFacingDownCount: type: integer format: int32 + Hearts.PassCardsRequest: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object + properties: + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + Hearts.PlayCardRequest: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object + properties: + card: + type: object + properties: + rank: + type: integer + format: int32 + suit: + type: string + Hearts.PassCardsResponse: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + properties: + receivedCards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + Hearts.GameStartedNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + gameId: + type: string + format: uuid + playerViewOfGame: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + properties: + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + otherPlayers: + type: array + items: + $ref: '#/components/schemas/Hearts.OtherHeartsPlayer' + roundNumber: + type: integer + format: int32 + passDirection: + type: string + hasPassed: + type: boolean + currentTrick: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + totalScore: + type: integer + format: int32 + roundScore: + type: integer + format: int32 + heartsAreBroken: + type: boolean + isMyTurn: + type: boolean + Hearts.PlayerViewOfGame: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + properties: + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + otherPlayers: + type: array + items: + $ref: '#/components/schemas/Hearts.OtherHeartsPlayer' + roundNumber: + type: integer + format: int32 + passDirection: + type: string + hasPassed: + type: boolean + currentTrick: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + totalScore: + type: integer + format: int32 + roundScore: + type: integer + format: int32 + heartsAreBroken: + type: boolean + isMyTurn: + type: boolean + Hearts.OtherHeartsPlayer: + type: object + properties: + playerId: + type: string + format: uuid + name: + type: string + numberOfCards: + type: integer + format: int32 + totalScore: + type: integer + format: int32 + roundScore: + type: integer + format: int32 + playedCard: + type: object + properties: + rank: + type: integer + format: int32 + suit: + type: string + nullable: true + Hearts.CardPlay: + type: object + properties: + playerId: + type: string + format: uuid + playerName: + type: string + card: + type: object + properties: + rank: + type: integer + format: int32 + suit: + type: string + nullable: true + Hearts.PassingPhaseStartedNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + passDirection: + type: string + Hearts.AllPlayersPassedNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + receivedCards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + Hearts.PlayerPassedCardsNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + playerId: + type: string + format: uuid + Hearts.ItsYourTurnNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + playerViewOfGame: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + properties: + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + otherPlayers: + type: array + items: + $ref: '#/components/schemas/Hearts.OtherHeartsPlayer' + roundNumber: + type: integer + format: int32 + passDirection: + type: string + hasPassed: + type: boolean + currentTrick: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + totalScore: + type: integer + format: int32 + roundScore: + type: integer + format: int32 + heartsAreBroken: + type: boolean + isMyTurn: + type: boolean + Hearts.ItsPlayersTurnNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + playerId: + type: string + format: uuid + Hearts.PlayerPlayedCardNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + playerId: + type: string + format: uuid + card: + type: object + properties: + rank: + type: integer + format: int32 + suit: + type: string + nullable: true + Hearts.TrickCompletedNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + winnerId: + type: string + format: uuid + winnerName: + type: string + trickCards: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + points: + type: integer + format: int32 + Hearts.RoundEndedNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + scores: + type: array + items: + $ref: '#/components/schemas/Hearts.PlayerScore' + moonShooterId: + type: string + format: uuid + nullable: true + moonShooterName: + type: string + Hearts.PlayerScore: + type: object + properties: + playerId: + type: string + format: uuid + playerName: + type: string + roundScore: + type: integer + format: int32 + totalScore: + type: integer + format: int32 + Hearts.GameEndedNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + properties: + finalScores: + type: array + items: + $ref: '#/components/schemas/Hearts.PlayerScore' + winnerId: + type: string + format: uuid + winnerName: + type: string + Hearts.HeartsAreBrokenNotification: + type: object + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object Gabong.PenalizePlayerForTakingTooLongRequest: type: object allOf: @@ -1523,6 +1872,7 @@ components: format: int32 suit: type: string + nullable: true CrazyEights.PutEightRequest: type: object allOf: @@ -1537,6 +1887,7 @@ components: format: int32 suit: type: string + nullable: true newSuit: type: string CrazyEights.DrawCardRequest: @@ -1563,6 +1914,7 @@ components: format: int32 suit: type: string + nullable: true CrazyEights.PlayerPutCardNotification: type: object allOf: @@ -1580,6 +1932,7 @@ components: format: int32 suit: type: string + nullable: true CrazyEights.PlayerPutEightNotification: type: object allOf: @@ -1597,6 +1950,7 @@ components: format: int32 suit: type: string + nullable: true newSuit: type: string CrazyEights.PlayerDrewCardNotification: @@ -1641,6 +1995,7 @@ components: format: int32 suit: type: string + nullable: true currentSuit: type: string stockPileCount: @@ -1671,6 +2026,7 @@ components: format: int32 suit: type: string + nullable: true currentSuit: type: string stockPileCount: @@ -1730,6 +2086,7 @@ components: format: int32 suit: type: string + nullable: true currentSuit: type: string stockPileCount: @@ -1813,6 +2170,7 @@ components: format: int32 suit: type: string + nullable: true claimedToBeCard: type: object properties: @@ -1821,6 +2179,7 @@ components: format: int32 suit: type: string + nullable: true Bullshit.PlayerPutCardNotification: type: object allOf: @@ -1838,6 +2197,7 @@ components: format: int32 suit: type: string + nullable: true Bullshit.BullshitRequest: type: object allOf: @@ -1877,6 +2237,7 @@ components: format: int32 suit: type: string + nullable: true Bullshit.PlayerDrewCardNotification: type: object allOf: diff --git a/generated/kotlin/no.forse.decksterlib/hearts/HeartsClient.kt b/generated/kotlin/no.forse.decksterlib/hearts/HeartsClient.kt new file mode 100644 index 00000000..7c8b7d23 --- /dev/null +++ b/generated/kotlin/no.forse.decksterlib/hearts/HeartsClient.kt @@ -0,0 +1,23 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * Notifications (events) for this game: + * GameStarted: GameStartedNotification + * PassingPhaseStarted: PassingPhaseStartedNotification + * AllPlayersPassed: AllPlayersPassedNotification + * PlayerPassedCards: PlayerPassedCardsNotification + * ItsYourTurn: ItsYourTurnNotification + * ItsPlayersTurn: ItsPlayersTurnNotification + * PlayerPlayedCard: PlayerPlayedCardNotification + * TrickCompleted: TrickCompletedNotification + * RoundEnded: RoundEndedNotification + * GameEnded: GameEndedNotification + * HeartsWereBroken: HeartsAreBrokenNotification + * +*/ +package no.forse.decksterlib.hearts + +interface HeartsClient { + suspend fun passCards(request: PassCardsRequest): PassCardsResponse + suspend fun playCard(request: PlayCardRequest): PlayerViewOfGame +} diff --git a/generated/kotlin/no.forse.decksterlib/uno/UnoClient.kt b/generated/kotlin/no.forse.decksterlib/uno/UnoClient.kt index 4295864b..feb23fac 100644 --- a/generated/kotlin/no.forse.decksterlib/uno/UnoClient.kt +++ b/generated/kotlin/no.forse.decksterlib/uno/UnoClient.kt @@ -9,8 +9,6 @@ * PlayerPassed: PlayerPassedNotification * GameEnded: GameEndedNotification * ItsYourTurn: ItsYourTurnNotification - * RoundStarted: RoundStartedNotification - * RoundEnded: RoundEndedNotification * */ package no.forse.decksterlib.uno diff --git a/generated/shebang.opeanpi.json b/generated/shebang.opeanpi.json index 8839cdd9..4bbffa88 100644 --- a/generated/shebang.opeanpi.json +++ b/generated/shebang.opeanpi.json @@ -1,5 +1,5 @@ { - "openapi": "3.0.1", + "openapi": "3.0.4", "info": { "title": "Deckster.Server", "version": "1.0" @@ -2593,63 +2593,10 @@ } } }, - "/": { - "get": { - "tags": [ - "Home" - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/login": { - "get": { - "tags": [ - "Home" - ], - "responses": { - "200": { - "description": "OK" - } - } - }, - "post": { - "tags": [ - "Home" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Controllers.LoginModel" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/Controllers.LoginModel" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/Controllers.LoginModel" - } - } - } - }, - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/idiot/description": { + "/hearts/description": { "get": { "tags": [ - "Idiot" + "Hearts" ], "responses": { "200": { @@ -2658,10 +2605,10 @@ } } }, - "/idiot/metadata": { + "/hearts/metadata": { "get": { "tags": [ - "Idiot" + "Hearts" ], "responses": { "200": { @@ -2687,10 +2634,10 @@ } } }, - "/idiot": { + "/hearts": { "get": { "tags": [ - "Idiot" + "Hearts" ], "responses": { "200": { @@ -2716,10 +2663,10 @@ } } }, - "/idiot/games": { + "/hearts/games": { "get": { "tags": [ - "Idiot" + "Hearts" ], "responses": { "200": { @@ -2754,10 +2701,10 @@ } } }, - "/idiot/games/{name}": { + "/hearts/games/{name}": { "get": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -2814,7 +2761,7 @@ }, "delete": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -2870,10 +2817,10 @@ } } }, - "/idiot/games/{name}/bot": { + "/hearts/games/{name}/bot": { "post": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -2909,10 +2856,10 @@ } } }, - "/idiot/previousgames": { + "/hearts/previousgames": { "get": { "tags": [ - "Idiot" + "Hearts" ], "responses": { "200": { @@ -2922,7 +2869,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Idiot.IdiotGame" + "$ref": "#/components/schemas/Hearts.HeartsGame" } } }, @@ -2930,7 +2877,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Idiot.IdiotGame" + "$ref": "#/components/schemas/Hearts.HeartsGame" } } }, @@ -2938,7 +2885,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Idiot.IdiotGame" + "$ref": "#/components/schemas/Hearts.HeartsGame" } } } @@ -2947,10 +2894,10 @@ } } }, - "/idiot/previousgames/{id}": { + "/hearts/previousgames/{id}": { "get": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -2969,17 +2916,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/Data.HistoricIdiotGame" + "$ref": "#/components/schemas/Data.HistoricHeartsGame" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricIdiotGame" + "$ref": "#/components/schemas/Data.HistoricHeartsGame" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricIdiotGame" + "$ref": "#/components/schemas/Data.HistoricHeartsGame" } } } @@ -2987,10 +2934,10 @@ } } }, - "/idiot/previousgames/{id}/{version}": { + "/hearts/previousgames/{id}/{version}": { "get": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -3018,17 +2965,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/Data.HistoricIdiotGame" + "$ref": "#/components/schemas/Data.HistoricHeartsGame" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricIdiotGame" + "$ref": "#/components/schemas/Data.HistoricHeartsGame" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricIdiotGame" + "$ref": "#/components/schemas/Data.HistoricHeartsGame" } } } @@ -3036,10 +2983,10 @@ } } }, - "/idiot/create/{name}": { + "/hearts/create/{name}": { "post": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -3095,10 +3042,10 @@ } } }, - "/idiot/create": { + "/hearts/create": { "post": { "tags": [ - "Idiot" + "Hearts" ], "responses": { "200": { @@ -3144,10 +3091,10 @@ } } }, - "/idiot/games/{name}/start": { + "/hearts/games/{name}/start": { "post": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -3203,10 +3150,10 @@ } } }, - "/idiot/join/{gameName}": { + "/hearts/join/{gameName}": { "get": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -3225,10 +3172,10 @@ } } }, - "/idiot/join/{connectionId}/finish": { + "/hearts/join/{connectionId}/finish": { "get": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -3248,10 +3195,10 @@ } } }, - "/idiot/spectate/{gameName}": { + "/hearts/spectate/{gameName}": { "get": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -3270,10 +3217,10 @@ } } }, - "/idiot/spectate/{connectionId}/finish": { + "/hearts/spectate/{connectionId}/finish": { "get": { "tags": [ - "Idiot" + "Hearts" ], "parameters": [ { @@ -3293,10 +3240,10 @@ } } }, - "/meta/messages": { + "/": { "get": { "tags": [ - "Meta" + "Home" ], "responses": { "200": { @@ -3305,10 +3252,51 @@ } } }, - "/texasholdem/description": { + "/login": { "get": { "tags": [ - "TexasHoldEm" + "Home" + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "post": { + "tags": [ + "Home" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.LoginModel" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.LoginModel" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/Controllers.LoginModel" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/idiot/description": { + "get": { + "tags": [ + "Idiot" ], "responses": { "200": { @@ -3317,10 +3305,10 @@ } } }, - "/texasholdem/metadata": { + "/idiot/metadata": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "responses": { "200": { @@ -3346,10 +3334,10 @@ } } }, - "/texasholdem": { + "/idiot": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "responses": { "200": { @@ -3375,10 +3363,10 @@ } } }, - "/texasholdem/games": { + "/idiot/games": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "responses": { "200": { @@ -3413,10 +3401,10 @@ } } }, - "/texasholdem/games/{name}": { + "/idiot/games/{name}": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3473,7 +3461,7 @@ }, "delete": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3529,10 +3517,10 @@ } } }, - "/texasholdem/games/{name}/bot": { + "/idiot/games/{name}/bot": { "post": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3568,10 +3556,10 @@ } } }, - "/texasholdem/previousgames": { + "/idiot/previousgames": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "responses": { "200": { @@ -3581,7 +3569,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/TexasHoldEm.TexasHoldEmGame" + "$ref": "#/components/schemas/Idiot.IdiotGame" } } }, @@ -3589,7 +3577,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/TexasHoldEm.TexasHoldEmGame" + "$ref": "#/components/schemas/Idiot.IdiotGame" } } }, @@ -3597,7 +3585,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/TexasHoldEm.TexasHoldEmGame" + "$ref": "#/components/schemas/Idiot.IdiotGame" } } } @@ -3606,10 +3594,10 @@ } } }, - "/texasholdem/previousgames/{id}": { + "/idiot/previousgames/{id}": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3628,17 +3616,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" + "$ref": "#/components/schemas/Data.HistoricIdiotGame" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" + "$ref": "#/components/schemas/Data.HistoricIdiotGame" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" + "$ref": "#/components/schemas/Data.HistoricIdiotGame" } } } @@ -3646,10 +3634,10 @@ } } }, - "/texasholdem/previousgames/{id}/{version}": { + "/idiot/previousgames/{id}/{version}": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3677,17 +3665,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" + "$ref": "#/components/schemas/Data.HistoricIdiotGame" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" + "$ref": "#/components/schemas/Data.HistoricIdiotGame" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" + "$ref": "#/components/schemas/Data.HistoricIdiotGame" } } } @@ -3695,10 +3683,10 @@ } } }, - "/texasholdem/create/{name}": { + "/idiot/create/{name}": { "post": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3754,10 +3742,10 @@ } } }, - "/texasholdem/create": { + "/idiot/create": { "post": { "tags": [ - "TexasHoldEm" + "Idiot" ], "responses": { "200": { @@ -3803,10 +3791,10 @@ } } }, - "/texasholdem/games/{name}/start": { + "/idiot/games/{name}/start": { "post": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3862,10 +3850,10 @@ } } }, - "/texasholdem/join/{gameName}": { + "/idiot/join/{gameName}": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3884,10 +3872,10 @@ } } }, - "/texasholdem/join/{connectionId}/finish": { + "/idiot/join/{connectionId}/finish": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3907,10 +3895,10 @@ } } }, - "/texasholdem/spectate/{gameName}": { + "/idiot/spectate/{gameName}": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3929,10 +3917,10 @@ } } }, - "/texasholdem/spectate/{connectionId}/finish": { + "/idiot/spectate/{connectionId}/finish": { "get": { "tags": [ - "TexasHoldEm" + "Idiot" ], "parameters": [ { @@ -3952,10 +3940,10 @@ } } }, - "/uno/description": { + "/meta/messages": { "get": { "tags": [ - "Uno" + "Meta" ], "responses": { "200": { @@ -3964,10 +3952,22 @@ } } }, - "/uno/metadata": { + "/texasholdem/description": { "get": { "tags": [ - "Uno" + "TexasHoldEm" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/texasholdem/metadata": { + "get": { + "tags": [ + "TexasHoldEm" ], "responses": { "200": { @@ -3993,10 +3993,10 @@ } } }, - "/uno": { + "/texasholdem": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "responses": { "200": { @@ -4022,10 +4022,10 @@ } } }, - "/uno/games": { + "/texasholdem/games": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "responses": { "200": { @@ -4060,10 +4060,10 @@ } } }, - "/uno/games/{name}": { + "/texasholdem/games/{name}": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4120,7 +4120,7 @@ }, "delete": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4176,10 +4176,10 @@ } } }, - "/uno/games/{name}/bot": { + "/texasholdem/games/{name}/bot": { "post": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4215,10 +4215,10 @@ } } }, - "/uno/previousgames": { + "/texasholdem/previousgames": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "responses": { "200": { @@ -4228,7 +4228,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Uno.UnoGame" + "$ref": "#/components/schemas/TexasHoldEm.TexasHoldEmGame" } } }, @@ -4236,7 +4236,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Uno.UnoGame" + "$ref": "#/components/schemas/TexasHoldEm.TexasHoldEmGame" } } }, @@ -4244,7 +4244,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Uno.UnoGame" + "$ref": "#/components/schemas/TexasHoldEm.TexasHoldEmGame" } } } @@ -4253,10 +4253,10 @@ } } }, - "/uno/previousgames/{id}": { + "/texasholdem/previousgames/{id}": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4275,17 +4275,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/Data.HistoricUnoGame" + "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricUnoGame" + "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricUnoGame" + "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" } } } @@ -4293,10 +4293,10 @@ } } }, - "/uno/previousgames/{id}/{version}": { + "/texasholdem/previousgames/{id}/{version}": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4324,17 +4324,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/Data.HistoricUnoGame" + "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricUnoGame" + "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricUnoGame" + "$ref": "#/components/schemas/Data.HistoricTexasHoldEmGame" } } } @@ -4342,10 +4342,10 @@ } } }, - "/uno/create/{name}": { + "/texasholdem/create/{name}": { "post": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4401,10 +4401,10 @@ } } }, - "/uno/create": { + "/texasholdem/create": { "post": { "tags": [ - "Uno" + "TexasHoldEm" ], "responses": { "200": { @@ -4450,10 +4450,10 @@ } } }, - "/uno/games/{name}/start": { + "/texasholdem/games/{name}/start": { "post": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4509,10 +4509,10 @@ } } }, - "/uno/join/{gameName}": { + "/texasholdem/join/{gameName}": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4531,10 +4531,10 @@ } } }, - "/uno/join/{connectionId}/finish": { + "/texasholdem/join/{connectionId}/finish": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4554,10 +4554,10 @@ } } }, - "/uno/spectate/{gameName}": { + "/texasholdem/spectate/{gameName}": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4576,10 +4576,10 @@ } } }, - "/uno/spectate/{connectionId}/finish": { + "/texasholdem/spectate/{connectionId}/finish": { "get": { "tags": [ - "Uno" + "TexasHoldEm" ], "parameters": [ { @@ -4599,22 +4599,10 @@ } } }, - "/me": { - "get": { - "tags": [ - "User" - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/yaniv/description": { + "/uno/description": { "get": { "tags": [ - "Yaniv" + "Uno" ], "responses": { "200": { @@ -4623,10 +4611,10 @@ } } }, - "/yaniv/metadata": { + "/uno/metadata": { "get": { "tags": [ - "Yaniv" + "Uno" ], "responses": { "200": { @@ -4652,10 +4640,10 @@ } } }, - "/yaniv": { + "/uno": { "get": { "tags": [ - "Yaniv" + "Uno" ], "responses": { "200": { @@ -4681,10 +4669,10 @@ } } }, - "/yaniv/games": { + "/uno/games": { "get": { "tags": [ - "Yaniv" + "Uno" ], "responses": { "200": { @@ -4719,10 +4707,10 @@ } } }, - "/yaniv/games/{name}": { + "/uno/games/{name}": { "get": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -4779,7 +4767,7 @@ }, "delete": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -4835,10 +4823,10 @@ } } }, - "/yaniv/games/{name}/bot": { + "/uno/games/{name}/bot": { "post": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -4874,10 +4862,10 @@ } } }, - "/yaniv/previousgames": { + "/uno/previousgames": { "get": { "tags": [ - "Yaniv" + "Uno" ], "responses": { "200": { @@ -4887,7 +4875,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Yaniv.YanivGame" + "$ref": "#/components/schemas/Uno.UnoGame" } } }, @@ -4895,7 +4883,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Yaniv.YanivGame" + "$ref": "#/components/schemas/Uno.UnoGame" } } }, @@ -4903,7 +4891,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Yaniv.YanivGame" + "$ref": "#/components/schemas/Uno.UnoGame" } } } @@ -4912,10 +4900,10 @@ } } }, - "/yaniv/previousgames/{id}": { + "/uno/previousgames/{id}": { "get": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -4934,17 +4922,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/Data.HistoricYanivGame" + "$ref": "#/components/schemas/Data.HistoricUnoGame" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricYanivGame" + "$ref": "#/components/schemas/Data.HistoricUnoGame" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricYanivGame" + "$ref": "#/components/schemas/Data.HistoricUnoGame" } } } @@ -4952,10 +4940,10 @@ } } }, - "/yaniv/previousgames/{id}/{version}": { + "/uno/previousgames/{id}/{version}": { "get": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -4983,17 +4971,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/Data.HistoricYanivGame" + "$ref": "#/components/schemas/Data.HistoricUnoGame" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricYanivGame" + "$ref": "#/components/schemas/Data.HistoricUnoGame" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/Data.HistoricYanivGame" + "$ref": "#/components/schemas/Data.HistoricUnoGame" } } } @@ -5001,10 +4989,10 @@ } } }, - "/yaniv/create/{name}": { + "/uno/create/{name}": { "post": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -5060,10 +5048,10 @@ } } }, - "/yaniv/create": { + "/uno/create": { "post": { "tags": [ - "Yaniv" + "Uno" ], "responses": { "200": { @@ -5109,10 +5097,10 @@ } } }, - "/yaniv/games/{name}/start": { + "/uno/games/{name}/start": { "post": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -5168,10 +5156,10 @@ } } }, - "/yaniv/join/{gameName}": { + "/uno/join/{gameName}": { "get": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -5190,10 +5178,10 @@ } } }, - "/yaniv/join/{connectionId}/finish": { + "/uno/join/{connectionId}/finish": { "get": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -5213,10 +5201,10 @@ } } }, - "/yaniv/spectate/{gameName}": { + "/uno/spectate/{gameName}": { "get": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -5235,10 +5223,10 @@ } } }, - "/yaniv/spectate/{connectionId}/finish": { + "/uno/spectate/{connectionId}/finish": { "get": { "tags": [ - "Yaniv" + "Uno" ], "parameters": [ { @@ -5257,61 +5245,1499 @@ } } } - } - }, - "components": { - "schemas": { - "Bullshit.BullshitBroadcastNotification": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterNotification" - }, - { - "required": [ - "actualCard", - "claimedToBeCard", - "playerId", - "punishmentCardCount" - ], - "type": "object", - "properties": { - "playerId": { - "type": "string", - "format": "uuid" - }, - "claimedToBeCard": { - "$ref": "#/components/schemas/Common.Card" + }, + "/me": { + "get": { + "tags": [ + "User" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/yaniv/description": { + "get": { + "tags": [ + "Yaniv" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/yaniv/metadata": { + "get": { + "tags": [ + "Yaniv" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Meta.GameMeta" + } }, - "actualCard": { - "$ref": "#/components/schemas/Common.Card" + "application/json": { + "schema": { + "$ref": "#/components/schemas/Meta.GameMeta" + } }, - "punishmentCardCount": { - "type": "integer", - "format": "int32" + "text/json": { + "schema": { + "$ref": "#/components/schemas/Meta.GameMeta" + } } - }, - "additionalProperties": false + } } - ] - }, - "Bullshit.BullshitGame": { - "allOf": [ - { - "$ref": "#/components/schemas/Games.GameObject" - }, - { - "required": [ - "cardsDrawn", - "currentPlayer", - "currentPlayerIndex", - "deck", - "discardPile", - "donePlayers", - "players", - "stockPile" - ], + } + } + }, + "/yaniv": { + "get": { + "tags": [ + "Yaniv" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameOverviewVm" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameOverviewVm" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameOverviewVm" + } + } + } + } + } + } + }, + "/yaniv/games": { + "get": { + "tags": [ + "Yaniv" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + } + } + } + } + } + } + }, + "/yaniv/games/{name}": { + "get": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + } + } + } + } + } + }, + "/yaniv/games/{name}/bot": { + "post": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + } + } + } + } + } + }, + "/yaniv/previousgames": { + "get": { + "tags": [ + "Yaniv" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Yaniv.YanivGame" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Yaniv.YanivGame" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Yaniv.YanivGame" + } + } + } + } + } + } + } + }, + "/yaniv/previousgames/{id}": { + "get": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Data.HistoricYanivGame" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Data.HistoricYanivGame" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Data.HistoricYanivGame" + } + } + } + } + } + } + }, + "/yaniv/previousgames/{id}/{version}": { + "get": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Data.HistoricYanivGame" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Data.HistoricYanivGame" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Data.HistoricYanivGame" + } + } + } + } + } + } + }, + "/yaniv/create/{name}": { + "post": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + } + } + } + } + } + }, + "/yaniv/create": { + "post": { + "tags": [ + "Yaniv" + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + } + } + } + } + } + }, + "/yaniv/games/{name}/start": { + "post": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Core.GameInfo" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/Controllers.ResponseMessage" + } + } + } + } + } + } + }, + "/yaniv/join/{gameName}": { + "get": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "gameName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/yaniv/join/{connectionId}/finish": { + "get": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "connectionId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/yaniv/spectate/{gameName}": { + "get": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "gameName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/yaniv/spectate/{connectionId}/finish": { + "get": { + "tags": [ + "Yaniv" + ], + "parameters": [ + { + "name": "connectionId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "Bullshit.BullshitBroadcastNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "actualCard", + "claimedToBeCard", + "playerId", + "punishmentCardCount" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "claimedToBeCard": { + "$ref": "#/components/schemas/Common.Card" + }, + "actualCard": { + "$ref": "#/components/schemas/Common.Card" + }, + "punishmentCardCount": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.BullshitGame": { + "allOf": [ + { + "$ref": "#/components/schemas/Games.GameObject" + }, + { + "required": [ + "cardsDrawn", + "currentPlayer", + "currentPlayerIndex", + "deck", + "discardPile", + "donePlayers", + "players", + "stockPile" + ], + "type": "object", + "properties": { + "deck": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "stockPile": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "discardPile": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "players": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bullshit.BullshitPlayer" + } + }, + "donePlayers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bullshit.BullshitPlayer" + } + }, + "currentPlayerIndex": { + "type": "integer", + "format": "int32" + }, + "claimedTopOfPile": { + "$ref": "#/components/schemas/Common.Card" + }, + "actualTopOfPile": { + "$ref": "#/components/schemas/Common.Card" + }, + "cardsDrawn": { + "type": "integer", + "format": "int32" + }, + "potentialBullshit": { + "$ref": "#/components/schemas/Bullshit.PotentialBullshit" + }, + "currentPlayer": { + "$ref": "#/components/schemas/Bullshit.BullshitPlayer" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.BullshitPlayer": { + "required": [ + "cards", + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + } + }, + "additionalProperties": false + }, + "Bullshit.BullshitPlayerNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "calledByPlayerId", + "card", + "punishmentCards" + ], + "type": "object", + "properties": { + "calledByPlayerId": { + "type": "string", + "format": "uuid" + }, + "card": { + "$ref": "#/components/schemas/Common.Card" + }, + "punishmentCards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.BullshitRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterRequest" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Bullshit.BullshitResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "required": [ + "punishmentCards" + ], + "type": "object", + "properties": { + "punishmentCards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.CardResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "required": [ + "card" + ], + "type": "object", + "properties": { + "card": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.DiscardPileShuffledNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Bullshit.DrawCardRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterRequest" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Bullshit.FalseBullshitCallNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "accusedPlayerId", + "playerId", + "punishmentCardCount" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "accusedPlayerId": { + "type": "string", + "format": "uuid" + }, + "punishmentCardCount": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.GameEndedNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "loserId", + "loserName", + "players" + ], + "type": "object", + "properties": { + "players": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.PlayerData" + } + }, + "loserId": { + "type": "string", + "format": "uuid" + }, + "loserName": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.GameStartedNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "gameId", + "playerViewOfGame" + ], + "type": "object", + "properties": { + "gameId": { + "type": "string", + "format": "uuid" + }, + "playerViewOfGame": { + "$ref": "#/components/schemas/Bullshit.PlayerViewOfGame" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.ItsPlayersTurnNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "playerId" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.ItsYourTurnNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Bullshit.OtherBullshitPlayer": { + "required": [ + "name", + "numberOfCards", + "playerId" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "numberOfCards": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "Bullshit.PassRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterRequest" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Bullshit.PlayerDrewCardNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "playerId" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.PlayerIsDoneNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "playerId" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.PlayerPassedNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "playerId" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.PlayerPutCardNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "claimedToBeCard", + "playerId" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "claimedToBeCard": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "additionalProperties": false + } + ] + }, + "Bullshit.PlayerViewOfGame": { + "required": [ + "cards", + "discardPileCount", + "otherPlayers", + "stockPileCount" + ], + "type": "object", + "properties": { + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "claimedTopOfPile": { + "$ref": "#/components/schemas/Common.Card" + }, + "stockPileCount": { + "type": "integer", + "format": "int32" + }, + "discardPileCount": { + "type": "integer", + "format": "int32" + }, + "otherPlayers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Bullshit.OtherBullshitPlayer" + } + } + }, + "additionalProperties": false + }, + "Bullshit.PotentialBullshit": { + "required": [ + "claimedToBeCard", + "playerId" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "claimedToBeCard": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "additionalProperties": false + }, + "Bullshit.PutCardRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterRequest" + }, + { + "required": [ + "actualCard", + "claimedToBeCard" + ], + "type": "object", + "properties": { + "actualCard": { + "$ref": "#/components/schemas/Common.Card" + }, + "claimedToBeCard": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "additionalProperties": false + } + ] + }, + "ChatRoom.ChatNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "required": [ + "message", + "sender" + ], + "type": "object", + "properties": { + "sender": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "ChatRoom.ChatResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "ChatRoom.ChatRoom": { + "allOf": [ + { + "$ref": "#/components/schemas/Games.GameObject" + }, + { + "required": [ + "transcript" + ], + "type": "object", + "properties": { + "transcript": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatRoom.SendChatRequest" + } + } + }, + "additionalProperties": false + } + ] + }, + "ChatRoom.SendChatRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterRequest" + }, + { + "required": [ + "message" + ], + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "Common.Card": { + "required": [ + "rank", + "suit" + ], + "type": "object", + "properties": { + "rank": { + "type": "integer", + "format": "int32" + }, + "suit": { + "$ref": "#/components/schemas/Common.Suit" + } + }, + "additionalProperties": false + }, + "Common.EmptyResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Common.PlayerData": { + "required": [ + "cardsInHand", + "id", + "info", + "name", + "points" + ], + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "points": { + "type": "number", + "format": "double" + }, + "cardsInHand": { + "type": "integer", + "format": "int32" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "info": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "Common.Suit": { + "enum": [ + "Clubs", + "Diamonds", + "Hearts", + "Spades" + ], + "type": "string" + }, + "Controllers.GameOverviewVm": { + "required": [ + "games", + "gameType" + ], + "type": "object", + "properties": { + "gameType": { + "type": "string" + }, + "games": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Controllers.GameVm" + } + } + }, + "additionalProperties": false + }, + "Controllers.GameVm": { + "required": [ + "gameType", + "name", + "players", + "state" + ], + "type": "object", + "properties": { + "gameType": { + "type": "string" + }, + "name": { + "type": "string" + }, + "state": { + "$ref": "#/components/schemas/Games.GameState" + }, + "players": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.PlayerData" + } + } + }, + "additionalProperties": false + }, + "Controllers.LoginModel": { + "type": "object", + "properties": { + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Controllers.ResponseMessage": { + "type": "object", + "properties": { + "message": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Core.GameInfo": { + "required": [ + "id" + ], + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "CrazyEights.CardResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterResponse" + }, + { + "required": [ + "card" + ], + "type": "object", + "properties": { + "card": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "additionalProperties": false + } + ] + }, + "CrazyEights.CrazyEightsGame": { + "allOf": [ + { + "$ref": "#/components/schemas/Games.GameObject" + }, + { + "required": [ + "cardsDrawn", + "currentPlayer", + "currentPlayerIndex", + "currentSuit", + "deck", + "discardPile", + "donePlayers", + "initialCardsPerPlayer", + "players", + "spectators", + "stockPile", + "topOfPile" + ], "type": "object", "properties": { + "initialCardsPerPlayer": { + "type": "integer", + "format": "int32" + }, + "currentPlayerIndex": { + "type": "integer", + "format": "int32" + }, + "cardsDrawn": { + "type": "integer", + "format": "int32" + }, + "donePlayers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CrazyEights.CrazyEightsPlayer" + } + }, "deck": { "type": "array", "items": { @@ -5333,41 +6759,33 @@ "players": { "type": "array", "items": { - "$ref": "#/components/schemas/Bullshit.BullshitPlayer" + "$ref": "#/components/schemas/CrazyEights.CrazyEightsPlayer" } }, - "donePlayers": { + "spectators": { "type": "array", "items": { - "$ref": "#/components/schemas/Bullshit.BullshitPlayer" + "$ref": "#/components/schemas/CrazyEights.CrazyEightsSpectator" } }, - "currentPlayerIndex": { - "type": "integer", - "format": "int32" - }, - "claimedTopOfPile": { - "$ref": "#/components/schemas/Common.Card" + "newSuit": { + "$ref": "#/components/schemas/Common.Suit" }, - "actualTopOfPile": { + "topOfPile": { "$ref": "#/components/schemas/Common.Card" }, - "cardsDrawn": { - "type": "integer", - "format": "int32" - }, - "potentialBullshit": { - "$ref": "#/components/schemas/Bullshit.PotentialBullshit" + "currentSuit": { + "$ref": "#/components/schemas/Common.Suit" }, "currentPlayer": { - "$ref": "#/components/schemas/Bullshit.BullshitPlayer" + "$ref": "#/components/schemas/CrazyEights.CrazyEightsPlayer" } }, "additionalProperties": false } ] }, - "Bullshit.BullshitPlayer": { + "CrazyEights.CrazyEightsPlayer": { "required": [ "cards", "id", @@ -5391,90 +6809,24 @@ }, "additionalProperties": false }, - "Bullshit.BullshitPlayerNotification": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterNotification" - }, - { - "required": [ - "calledByPlayerId", - "card", - "punishmentCards" - ], - "type": "object", - "properties": { - "calledByPlayerId": { - "type": "string", - "format": "uuid" - }, - "card": { - "$ref": "#/components/schemas/Common.Card" - }, - "punishmentCards": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.Card" - } - } - }, - "additionalProperties": false - } - ] - }, - "Bullshit.BullshitRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterRequest" - }, - { - "type": "object", - "additionalProperties": false - } - ] - }, - "Bullshit.BullshitResponse": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterResponse" - }, - { - "required": [ - "punishmentCards" - ], - "type": "object", - "properties": { - "punishmentCards": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.Card" - } - } - }, - "additionalProperties": false - } - ] - }, - "Bullshit.CardResponse": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterResponse" + "CrazyEights.CrazyEightsSpectator": { + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "required": [ - "card" - ], - "type": "object", - "properties": { - "card": { - "$ref": "#/components/schemas/Common.Card" - } - }, - "additionalProperties": false + "name": { + "type": "string" } - ] + }, + "additionalProperties": false }, - "Bullshit.DiscardPileShuffledNotification": { + "CrazyEights.DiscardPileShuffledNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" @@ -5485,7 +6837,7 @@ } ] }, - "Bullshit.DrawCardRequest": { + "CrazyEights.DrawCardRequest": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterRequest" @@ -5496,37 +6848,7 @@ } ] }, - "Bullshit.FalseBullshitCallNotification": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterNotification" - }, - { - "required": [ - "accusedPlayerId", - "playerId", - "punishmentCardCount" - ], - "type": "object", - "properties": { - "playerId": { - "type": "string", - "format": "uuid" - }, - "accusedPlayerId": { - "type": "string", - "format": "uuid" - }, - "punishmentCardCount": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - } - ] - }, - "Bullshit.GameEndedNotification": { + "CrazyEights.GameEndedNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" @@ -5557,7 +6879,7 @@ } ] }, - "Bullshit.GameStartedNotification": { + "CrazyEights.GameStartedNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" @@ -5574,14 +6896,14 @@ "format": "uuid" }, "playerViewOfGame": { - "$ref": "#/components/schemas/Bullshit.PlayerViewOfGame" + "$ref": "#/components/schemas/CrazyEights.PlayerViewOfGame" } }, "additionalProperties": false } ] }, - "Bullshit.ItsPlayersTurnNotification": { + "CrazyEights.ItsPlayersTurnNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" @@ -5601,18 +6923,26 @@ } ] }, - "Bullshit.ItsYourTurnNotification": { + "CrazyEights.ItsYourTurnNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { + "required": [ + "playerViewOfGame" + ], "type": "object", + "properties": { + "playerViewOfGame": { + "$ref": "#/components/schemas/CrazyEights.PlayerViewOfGame" + } + }, "additionalProperties": false } ] }, - "Bullshit.OtherBullshitPlayer": { + "CrazyEights.OtherCrazyEightsPlayer": { "required": [ "name", "numberOfCards", @@ -5634,7 +6964,7 @@ }, "additionalProperties": false }, - "Bullshit.PassRequest": { + "CrazyEights.PassRequest": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterRequest" @@ -5645,7 +6975,7 @@ } ] }, - "Bullshit.PlayerDrewCardNotification": { + "CrazyEights.PlayerDrewCardNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" @@ -5665,7 +6995,7 @@ } ] }, - "Bullshit.PlayerIsDoneNotification": { + "CrazyEights.PlayerIsDoneNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" @@ -5685,7 +7015,7 @@ } ] }, - "Bullshit.PlayerPassedNotification": { + "CrazyEights.PlayerPassedNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" @@ -5705,14 +7035,14 @@ } ] }, - "Bullshit.PlayerPutCardNotification": { + "CrazyEights.PlayerPutCardNotification": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "claimedToBeCard", + "card", "playerId" ], "type": "object", @@ -5721,7 +7051,7 @@ "type": "string", "format": "uuid" }, - "claimedToBeCard": { + "card": { "$ref": "#/components/schemas/Common.Card" } }, @@ -5729,314 +7059,264 @@ } ] }, - "Bullshit.PlayerViewOfGame": { - "required": [ - "cards", - "discardPileCount", - "otherPlayers", - "stockPileCount" - ], - "type": "object", - "properties": { - "cards": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.Card" - } - }, - "claimedTopOfPile": { - "$ref": "#/components/schemas/Common.Card" - }, - "stockPileCount": { - "type": "integer", - "format": "int32" - }, - "discardPileCount": { - "type": "integer", - "format": "int32" - }, - "otherPlayers": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Bullshit.OtherBullshitPlayer" - } - } - }, - "additionalProperties": false - }, - "Bullshit.PotentialBullshit": { - "required": [ - "claimedToBeCard", - "playerId" - ], - "type": "object", - "properties": { - "playerId": { - "type": "string", - "format": "uuid" - }, - "claimedToBeCard": { - "$ref": "#/components/schemas/Common.Card" - } - }, - "additionalProperties": false - }, - "Bullshit.PutCardRequest": { + "CrazyEights.PlayerPutEightNotification": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterRequest" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "actualCard", - "claimedToBeCard" + "card", + "newSuit", + "playerId" ], "type": "object", "properties": { - "actualCard": { - "$ref": "#/components/schemas/Common.Card" + "playerId": { + "type": "string", + "format": "uuid" }, - "claimedToBeCard": { + "card": { "$ref": "#/components/schemas/Common.Card" + }, + "newSuit": { + "$ref": "#/components/schemas/Common.Suit" } }, "additionalProperties": false } ] }, - "ChatRoom.ChatNotification": { + "CrazyEights.PlayerViewOfGame": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "$ref": "#/components/schemas/Protocol.DecksterResponse" }, { "required": [ - "message", - "sender" + "cards", + "currentSuit", + "discardPileCount", + "otherPlayers", + "stockPileCount", + "topOfPile" ], "type": "object", "properties": { - "sender": { - "type": "string" + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } }, - "message": { - "type": "string" + "topOfPile": { + "$ref": "#/components/schemas/Common.Card" + }, + "currentSuit": { + "$ref": "#/components/schemas/Common.Suit" + }, + "stockPileCount": { + "type": "integer", + "format": "int32" + }, + "discardPileCount": { + "type": "integer", + "format": "int32" + }, + "otherPlayers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CrazyEights.OtherCrazyEightsPlayer" + } } }, "additionalProperties": false } ] }, - "ChatRoom.ChatResponse": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterResponse" - }, - { - "type": "object", - "additionalProperties": false - } - ] - }, - "ChatRoom.ChatRoom": { + "CrazyEights.PutCardRequest": { "allOf": [ { - "$ref": "#/components/schemas/Games.GameObject" + "$ref": "#/components/schemas/Protocol.DecksterRequest" }, { "required": [ - "transcript" + "card" ], "type": "object", "properties": { - "transcript": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ChatRoom.SendChatRequest" - } + "card": { + "$ref": "#/components/schemas/Common.Card" } }, "additionalProperties": false } ] }, - "ChatRoom.SendChatRequest": { + "CrazyEights.PutEightRequest": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterRequest" }, { "required": [ - "message" + "card", + "newSuit" ], "type": "object", "properties": { - "message": { - "type": "string" + "card": { + "$ref": "#/components/schemas/Common.Card" + }, + "newSuit": { + "$ref": "#/components/schemas/Common.Suit" } }, "additionalProperties": false } ] }, - "Common.Card": { + "Data.DatabaseObject": { "required": [ - "rank", - "suit" + "id", + "type" ], "type": "object", "properties": { - "rank": { - "type": "integer", - "format": "int32" + "type": { + "type": "string", + "readOnly": true }, - "suit": { - "$ref": "#/components/schemas/Common.Suit" + "id": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "type", + "mapping": { + "Games.GameObject": "#/components/schemas/Games.GameObject", + "Yaniv.YanivGame": "#/components/schemas/Yaniv.YanivGame", + "Uno.UnoGame": "#/components/schemas/Uno.UnoGame", + "TexasHoldEm.TexasHoldEmGame": "#/components/schemas/TexasHoldEm.TexasHoldEmGame", + "Idiot.IdiotGame": "#/components/schemas/Idiot.IdiotGame", + "Hearts.HeartsGame": "#/components/schemas/Hearts.HeartsGame", + "Gabong.GabongGame": "#/components/schemas/Gabong.GabongGame", + "CrazyEights.CrazyEightsGame": "#/components/schemas/CrazyEights.CrazyEightsGame", + "ChatRoom.ChatRoom": "#/components/schemas/ChatRoom.ChatRoom", + "Bullshit.BullshitGame": "#/components/schemas/Bullshit.BullshitGame" + } + } + }, + "Data.HistoricBullshitGame": { + "type": "object", + "properties": { + "game": { + "$ref": "#/components/schemas/Bullshit.BullshitGame" } }, "additionalProperties": false }, - "Common.EmptyResponse": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterResponse" - }, - { - "type": "object", - "additionalProperties": false + "Data.HistoricChatRoom": { + "type": "object", + "properties": { + "game": { + "$ref": "#/components/schemas/ChatRoom.ChatRoom" } - ] + }, + "additionalProperties": false }, - "Common.PlayerData": { - "required": [ - "cardsInHand", - "id", - "info", - "name", - "points" - ], + "Data.HistoricCrazyEightsGame": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "points": { - "type": "number", - "format": "double" - }, - "cardsInHand": { - "type": "integer", - "format": "int32" - }, - "id": { - "type": "string", - "format": "uuid" - }, - "info": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "game": { + "$ref": "#/components/schemas/CrazyEights.CrazyEightsGame" } }, "additionalProperties": false }, - "Common.Suit": { - "enum": [ - "Clubs", - "Diamonds", - "Hearts", - "Spades" - ], - "type": "string" + "Data.HistoricGabongGame": { + "type": "object", + "properties": { + "game": { + "$ref": "#/components/schemas/Gabong.GabongGame" + } + }, + "additionalProperties": false }, - "Controllers.GameOverviewVm": { - "required": [ - "games", - "gameType" - ], + "Data.HistoricHeartsGame": { "type": "object", "properties": { - "gameType": { - "type": "string" - }, - "games": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Controllers.GameVm" - } + "game": { + "$ref": "#/components/schemas/Hearts.HeartsGame" } }, "additionalProperties": false }, - "Controllers.GameVm": { - "required": [ - "gameType", - "name", - "players", - "state" - ], + "Data.HistoricIdiotGame": { "type": "object", "properties": { - "gameType": { - "type": "string" - }, - "name": { - "type": "string" - }, - "state": { - "$ref": "#/components/schemas/Games.GameState" - }, - "players": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.PlayerData" - } + "game": { + "$ref": "#/components/schemas/Idiot.IdiotGame" } }, "additionalProperties": false }, - "Controllers.LoginModel": { + "Data.HistoricTexasHoldEmGame": { "type": "object", "properties": { - "username": { - "type": "string", - "nullable": true - }, - "password": { - "type": "string", - "nullable": true + "game": { + "$ref": "#/components/schemas/TexasHoldEm.TexasHoldEmGame" } }, "additionalProperties": false }, - "Controllers.ResponseMessage": { + "Data.HistoricUnoGame": { "type": "object", "properties": { - "message": { - "type": "string", - "nullable": true + "game": { + "$ref": "#/components/schemas/Uno.UnoGame" } }, "additionalProperties": false }, - "Core.GameInfo": { - "required": [ - "id" - ], + "Data.HistoricYanivGame": { "type": "object", "properties": { - "id": { - "type": "string" + "game": { + "$ref": "#/components/schemas/Yaniv.YanivGame" } }, "additionalProperties": false }, - "CrazyEights.CardResponse": { + "Gabong.ActionResponse": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterResponse" }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Gabong.DrawCardRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/Gabong.GabongRequest" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Gabong.GabongCardResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/Gabong.GabongResponse" + }, { "required": [ "card" @@ -6051,7 +7331,7 @@ } ] }, - "CrazyEights.CrazyEightsGame": { + "Gabong.GabongGame": { "allOf": [ { "$ref": "#/components/schemas/Games.GameObject" @@ -6059,25 +7339,26 @@ { "required": [ "cardsDrawn", + "cardsToDraw", "currentPlayer", - "currentPlayerIndex", "currentSuit", "deck", "discardPile", - "donePlayers", - "initialCardsPerPlayer", + "gabongMasterId", + "gameDirection", + "isBetweenRounds", + "lastPlayMadeByPlayerIndex", "players", - "spectators", "stockPile", "topOfPile" ], "type": "object", "properties": { - "initialCardsPerPlayer": { + "lastPlayMadeByPlayerIndex": { "type": "integer", "format": "int32" }, - "currentPlayerIndex": { + "cardsToDraw": { "type": "integer", "format": "int32" }, @@ -6085,11 +7366,16 @@ "type": "integer", "format": "int32" }, - "donePlayers": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CrazyEights.CrazyEightsPlayer" - } + "gameDirection": { + "type": "integer", + "format": "int32" + }, + "gabongMasterId": { + "type": "string", + "format": "uuid" + }, + "isBetweenRounds": { + "type": "boolean" }, "deck": { "type": "array", @@ -6112,13 +7398,7 @@ "players": { "type": "array", "items": { - "$ref": "#/components/schemas/CrazyEights.CrazyEightsPlayer" - } - }, - "spectators": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CrazyEights.CrazyEightsSpectator" + "$ref": "#/components/schemas/Gabong.GabongPlayer" } }, "newSuit": { @@ -6131,18 +7411,62 @@ "$ref": "#/components/schemas/Common.Suit" }, "currentPlayer": { - "$ref": "#/components/schemas/CrazyEights.CrazyEightsPlayer" + "$ref": "#/components/schemas/Gabong.GabongPlayer" } }, "additionalProperties": false } ] }, - "CrazyEights.CrazyEightsPlayer": { + "Gabong.GabongGameNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterNotification" + }, + { + "type": "object", + "additionalProperties": false, + "discriminator": { + "propertyName": "type", + "mapping": { + "Gabong.GabongPlayerNotification": "#/components/schemas/Gabong.GabongPlayerNotification", + "Gabong.PlayerPutCardNotification": "#/components/schemas/Gabong.PlayerPutCardNotification", + "Gabong.PlayerDrewCardNotification": "#/components/schemas/Gabong.PlayerDrewCardNotification", + "Gabong.PlayerDrewPenaltyCardNotification": "#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification", + "Gabong.GameStartedNotification": "#/components/schemas/Gabong.GameStartedNotification", + "Gabong.GameEndedNotification": "#/components/schemas/Gabong.GameEndedNotification", + "Gabong.RoundStartedNotification": "#/components/schemas/Gabong.RoundStartedNotification", + "Gabong.RoundEndedNotification": "#/components/schemas/Gabong.RoundEndedNotification", + "Gabong.PlayerLostTheirTurnNotification": "#/components/schemas/Gabong.PlayerLostTheirTurnNotification" + } + } + } + ] + }, + "Gabong.GabongPlay": { + "enum": [ + "CardPlayed", + "TurnLost", + "RoundStarted" + ], + "type": "string" + }, + "Gabong.GabongPlayer": { "required": [ + "bongas", "cards", + "cardsPlayed", + "debtDrawn", + "gabongs", + "hasWon", "id", - "name" + "name", + "passes", + "penalties", + "roundsWon", + "score", + "shots", + "turnsLost" ], "type": "object", "properties": { @@ -6157,109 +7481,60 @@ "type": "array", "items": { "$ref": "#/components/schemas/Common.Card" - } - } - }, - "additionalProperties": false - }, - "CrazyEights.CrazyEightsSpectator": { - "required": [ - "id", - "name" - ], - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" + }, + "readOnly": true }, - "name": { - "type": "string" - } - }, - "additionalProperties": false - }, - "CrazyEights.DiscardPileShuffledNotification": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "score": { + "type": "integer", + "format": "int32" }, - { - "type": "object", - "additionalProperties": false - } - ] - }, - "CrazyEights.DrawCardRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterRequest" + "hasWon": { + "type": "boolean", + "readOnly": true }, - { - "type": "object", - "additionalProperties": false - } - ] - }, - "CrazyEights.GameEndedNotification": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "penalties": { + "type": "integer", + "format": "int32" + }, + "gabongs": { + "type": "integer", + "format": "int32" + }, + "bongas": { + "type": "integer", + "format": "int32" + }, + "shots": { + "type": "integer", + "format": "int32" + }, + "cardsPlayed": { + "type": "integer", + "format": "int32" + }, + "debtDrawn": { + "type": "integer", + "format": "int32" + }, + "passes": { + "type": "integer", + "format": "int32" }, - { - "required": [ - "loserId", - "loserName", - "players" - ], - "type": "object", - "properties": { - "players": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.PlayerData" - } - }, - "loserId": { - "type": "string", - "format": "uuid" - }, - "loserName": { - "type": "string" - } - }, - "additionalProperties": false - } - ] - }, - "CrazyEights.GameStartedNotification": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "turnsLost": { + "type": "integer", + "format": "int32" }, - { - "required": [ - "gameId", - "playerViewOfGame" - ], - "type": "object", - "properties": { - "gameId": { - "type": "string", - "format": "uuid" - }, - "playerViewOfGame": { - "$ref": "#/components/schemas/CrazyEights.PlayerViewOfGame" - } - }, - "additionalProperties": false + "roundsWon": { + "type": "integer", + "format": "int32" } - ] + }, + "additionalProperties": false }, - "CrazyEights.ItsPlayersTurnNotification": { + "Gabong.GabongPlayerNotification": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "$ref": "#/components/schemas/Gabong.GabongGameNotification" }, { "required": [ @@ -6272,114 +7547,103 @@ "format": "uuid" } }, - "additionalProperties": false - } - ] - }, - "CrazyEights.ItsYourTurnNotification": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterNotification" - }, - { - "required": [ - "playerViewOfGame" - ], - "type": "object", - "properties": { - "playerViewOfGame": { - "$ref": "#/components/schemas/CrazyEights.PlayerViewOfGame" + "additionalProperties": false, + "discriminator": { + "propertyName": "type", + "mapping": { + "Gabong.PlayerPutCardNotification": "#/components/schemas/Gabong.PlayerPutCardNotification", + "Gabong.PlayerDrewCardNotification": "#/components/schemas/Gabong.PlayerDrewCardNotification", + "Gabong.PlayerDrewPenaltyCardNotification": "#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification", + "Gabong.PlayerLostTheirTurnNotification": "#/components/schemas/Gabong.PlayerLostTheirTurnNotification" } - }, - "additionalProperties": false + } } ] }, - "CrazyEights.OtherCrazyEightsPlayer": { - "required": [ - "name", - "numberOfCards", - "playerId" - ], - "type": "object", - "properties": { - "playerId": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "numberOfCards": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "CrazyEights.PassRequest": { + "Gabong.GabongRequest": { "allOf": [ { "$ref": "#/components/schemas/Protocol.DecksterRequest" }, { "type": "object", - "additionalProperties": false + "additionalProperties": false, + "discriminator": { + "propertyName": "type", + "mapping": { + "Gabong.PutCardRequest": "#/components/schemas/Gabong.PutCardRequest", + "Gabong.DrawCardRequest": "#/components/schemas/Gabong.DrawCardRequest", + "Gabong.PassRequest": "#/components/schemas/Gabong.PassRequest", + "Gabong.PlayGabongRequest": "#/components/schemas/Gabong.PlayGabongRequest", + "Gabong.PlayBongaRequest": "#/components/schemas/Gabong.PlayBongaRequest" + } + } } ] }, - "CrazyEights.PlayerDrewCardNotification": { + "Gabong.GabongResponse": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "$ref": "#/components/schemas/Protocol.DecksterResponse" }, { "required": [ - "playerId" + "cardsAdded" ], "type": "object", "properties": { - "playerId": { - "type": "string", - "format": "uuid" + "cardsAdded": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } } }, - "additionalProperties": false + "additionalProperties": false, + "discriminator": { + "propertyName": "type", + "mapping": { + "Gabong.GabongCardResponse": "#/components/schemas/Gabong.GabongCardResponse", + "Gabong.PlayerViewOfGame": "#/components/schemas/Gabong.PlayerViewOfGame" + } + } } ] }, - "CrazyEights.PlayerIsDoneNotification": { + "Gabong.GameEndedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "$ref": "#/components/schemas/Gabong.GabongGameNotification" }, { "required": [ - "playerId" + "players" ], "type": "object", "properties": { - "playerId": { - "type": "string", - "format": "uuid" + "players": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.PlayerData" + } } }, "additionalProperties": false } ] }, - "CrazyEights.PlayerPassedNotification": { + "Gabong.GameStartedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "$ref": "#/components/schemas/Gabong.GabongGameNotification" }, { "required": [ - "playerId" + "gameId" ], "type": "object", "properties": { - "playerId": { + "gameId": { "type": "string", "format": "uuid" } @@ -6388,277 +7652,135 @@ } ] }, - "CrazyEights.PlayerPutCardNotification": { + "Gabong.PassRequest": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "$ref": "#/components/schemas/Gabong.GabongRequest" }, { - "required": [ - "card", - "playerId" - ], "type": "object", - "properties": { - "playerId": { - "type": "string", - "format": "uuid" - }, - "card": { - "$ref": "#/components/schemas/Common.Card" - } - }, "additionalProperties": false } ] }, - "CrazyEights.PlayerPutEightNotification": { + "Gabong.PenalizePlayerForTakingTooLongRequest": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "$ref": "#/components/schemas/Protocol.DecksterRequest" }, { - "required": [ - "card", - "newSuit", - "playerId" - ], "type": "object", - "properties": { - "playerId": { - "type": "string", - "format": "uuid" - }, - "card": { - "$ref": "#/components/schemas/Common.Card" - }, - "newSuit": { - "$ref": "#/components/schemas/Common.Suit" - } - }, "additionalProperties": false } ] }, - "CrazyEights.PlayerViewOfGame": { + "Gabong.PenalizePlayerForTooManyCardsRequest": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterResponse" + "$ref": "#/components/schemas/Protocol.DecksterRequest" }, { - "required": [ - "cards", - "currentSuit", - "discardPileCount", - "otherPlayers", - "stockPileCount", - "topOfPile" - ], "type": "object", - "properties": { - "cards": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.Card" - } - }, - "topOfPile": { - "$ref": "#/components/schemas/Common.Card" - }, - "currentSuit": { - "$ref": "#/components/schemas/Common.Suit" - }, - "stockPileCount": { - "type": "integer", - "format": "int32" - }, - "discardPileCount": { - "type": "integer", - "format": "int32" - }, - "otherPlayers": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CrazyEights.OtherCrazyEightsPlayer" - } - } - }, "additionalProperties": false } ] }, - "CrazyEights.PutCardRequest": { + "Gabong.PenaltyReason": { + "enum": [ + "PlayOutOfTurn", + "TookTooLong", + "WrongPlay", + "WrongGabong", + "WrongBonga", + "UnpaidDebt", + "PassWithoutDrawing" + ], + "type": "string" + }, + "Gabong.PlayBongaRequest": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterRequest" + "$ref": "#/components/schemas/Gabong.GabongRequest" }, { - "required": [ - "card" - ], "type": "object", - "properties": { - "card": { - "$ref": "#/components/schemas/Common.Card" - } - }, "additionalProperties": false } ] }, - "CrazyEights.PutEightRequest": { + "Gabong.PlayGabongRequest": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterRequest" + "$ref": "#/components/schemas/Gabong.GabongRequest" }, { - "required": [ - "card", - "newSuit" - ], "type": "object", - "properties": { - "card": { - "$ref": "#/components/schemas/Common.Card" - }, - "newSuit": { - "$ref": "#/components/schemas/Common.Suit" - } - }, "additionalProperties": false } ] }, - "Data.DatabaseObject": { - "required": [ - "id", - "type" - ], - "type": "object", - "properties": { - "type": { - "type": "string", - "readOnly": true + "Gabong.PlayerDrewCardNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Gabong.GabongPlayerNotification" }, - "id": { - "type": "string", - "format": "uuid" - } - }, - "additionalProperties": false, - "discriminator": { - "propertyName": "type", - "mapping": { - "Games.GameObject": "#/components/schemas/Games.GameObject", - "Yaniv.YanivGame": "#/components/schemas/Yaniv.YanivGame", - "Uno.UnoGame": "#/components/schemas/Uno.UnoGame", - "TexasHoldEm.TexasHoldEmGame": "#/components/schemas/TexasHoldEm.TexasHoldEmGame", - "Idiot.IdiotGame": "#/components/schemas/Idiot.IdiotGame", - "Gabong.GabongGame": "#/components/schemas/Gabong.GabongGame", - "CrazyEights.CrazyEightsGame": "#/components/schemas/CrazyEights.CrazyEightsGame", - "ChatRoom.ChatRoom": "#/components/schemas/ChatRoom.ChatRoom", - "Bullshit.BullshitGame": "#/components/schemas/Bullshit.BullshitGame" - } - } - }, - "Data.HistoricBullshitGame": { - "type": "object", - "properties": { - "game": { - "$ref": "#/components/schemas/Bullshit.BullshitGame" - } - }, - "additionalProperties": false - }, - "Data.HistoricChatRoom": { - "type": "object", - "properties": { - "game": { - "$ref": "#/components/schemas/ChatRoom.ChatRoom" - } - }, - "additionalProperties": false - }, - "Data.HistoricCrazyEightsGame": { - "type": "object", - "properties": { - "game": { - "$ref": "#/components/schemas/CrazyEights.CrazyEightsGame" - } - }, - "additionalProperties": false - }, - "Data.HistoricGabongGame": { - "type": "object", - "properties": { - "game": { - "$ref": "#/components/schemas/Gabong.GabongGame" - } - }, - "additionalProperties": false - }, - "Data.HistoricIdiotGame": { - "type": "object", - "properties": { - "game": { - "$ref": "#/components/schemas/Idiot.IdiotGame" - } - }, - "additionalProperties": false - }, - "Data.HistoricTexasHoldEmGame": { - "type": "object", - "properties": { - "game": { - "$ref": "#/components/schemas/TexasHoldEm.TexasHoldEmGame" - } - }, - "additionalProperties": false - }, - "Data.HistoricUnoGame": { - "type": "object", - "properties": { - "game": { - "$ref": "#/components/schemas/Uno.UnoGame" - } - }, - "additionalProperties": false - }, - "Data.HistoricYanivGame": { - "type": "object", - "properties": { - "game": { - "$ref": "#/components/schemas/Yaniv.YanivGame" + { + "type": "object", + "additionalProperties": false } - }, - "additionalProperties": false + ] }, - "Gabong.ActionResponse": { + "Gabong.PlayerDrewPenaltyCardNotification": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterResponse" + "$ref": "#/components/schemas/Gabong.GabongPlayerNotification" }, { + "required": [ + "penaltyReason" + ], "type": "object", + "properties": { + "penaltyReason": { + "$ref": "#/components/schemas/Gabong.PenaltyReason" + } + }, "additionalProperties": false } ] }, - "Gabong.DrawCardRequest": { + "Gabong.PlayerLostTheirTurnNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongRequest" + "$ref": "#/components/schemas/Gabong.GabongPlayerNotification" }, { + "required": [ + "lostTurnReason" + ], "type": "object", + "properties": { + "lostTurnReason": { + "$ref": "#/components/schemas/Gabong.PlayerLostTurnReason" + } + }, "additionalProperties": false } ] }, - "Gabong.GabongCardResponse": { + "Gabong.PlayerLostTurnReason": { + "enum": [ + "Passed", + "WrongPlay", + "TookTooLong", + "FinishedDrawingCardDebt" + ], + "type": "string" + }, + "Gabong.PlayerPutCardNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongResponse" + "$ref": "#/components/schemas/Gabong.GabongPlayerNotification" }, { "required": [ @@ -6668,148 +7790,161 @@ "properties": { "card": { "$ref": "#/components/schemas/Common.Card" + }, + "newSuit": { + "$ref": "#/components/schemas/Common.Suit" } }, "additionalProperties": false } ] }, - "Gabong.GabongGame": { + "Gabong.PlayerViewOfGame": { "allOf": [ { - "$ref": "#/components/schemas/Games.GameObject" + "$ref": "#/components/schemas/Gabong.GabongResponse" }, { "required": [ - "cardsDrawn", - "cardsToDraw", - "currentPlayer", + "cardDebtToDraw", + "cards", "currentSuit", - "deck", - "discardPile", - "gabongMasterId", - "gameDirection", - "isBetweenRounds", - "lastPlayMadeByPlayerIndex", + "discardPileCount", + "lastPlay", + "lastPlayMadeByPlayerId", "players", - "stockPile", + "playersOrder", + "roundStarted", + "stockPileCount", "topOfPile" ], "type": "object", "properties": { - "lastPlayMadeByPlayerIndex": { - "type": "integer", - "format": "int32" + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } }, - "cardsToDraw": { - "type": "integer", - "format": "int32" + "topOfPile": { + "$ref": "#/components/schemas/Common.Card" }, - "cardsDrawn": { + "currentSuit": { + "$ref": "#/components/schemas/Common.Suit" + }, + "stockPileCount": { "type": "integer", "format": "int32" }, - "gameDirection": { + "discardPileCount": { "type": "integer", "format": "int32" }, - "gabongMasterId": { + "roundStarted": { + "type": "boolean" + }, + "lastPlayMadeByPlayerId": { "type": "string", "format": "uuid" }, - "isBetweenRounds": { - "type": "boolean" + "lastPlay": { + "$ref": "#/components/schemas/Gabong.GabongPlay" }, - "deck": { + "players": { "type": "array", "items": { - "$ref": "#/components/schemas/Common.Card" + "$ref": "#/components/schemas/Gabong.SlimGabongPlayer" } }, - "stockPile": { + "playersOrder": { "type": "array", "items": { - "$ref": "#/components/schemas/Common.Card" + "type": "string", + "format": "uuid" } }, - "discardPile": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.Card" - } + "cardDebtToDraw": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + ] + }, + "Gabong.PutCardRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/Gabong.GabongRequest" + }, + { + "required": [ + "card" + ], + "type": "object", + "properties": { + "card": { + "$ref": "#/components/schemas/Common.Card" }, + "newSuit": { + "$ref": "#/components/schemas/Common.Suit" + } + }, + "additionalProperties": false + } + ] + }, + "Gabong.RoundEndedNotification": { + "allOf": [ + { + "$ref": "#/components/schemas/Gabong.GabongGameNotification" + }, + { + "required": [ + "players" + ], + "type": "object", + "properties": { "players": { "type": "array", "items": { - "$ref": "#/components/schemas/Gabong.GabongPlayer" + "$ref": "#/components/schemas/Common.PlayerData" } - }, - "newSuit": { - "$ref": "#/components/schemas/Common.Suit" - }, - "topOfPile": { - "$ref": "#/components/schemas/Common.Card" - }, - "currentSuit": { - "$ref": "#/components/schemas/Common.Suit" - }, - "currentPlayer": { - "$ref": "#/components/schemas/Gabong.GabongPlayer" } }, "additionalProperties": false } ] }, - "Gabong.GabongGameNotification": { + "Gabong.RoundStartedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterNotification" + "$ref": "#/components/schemas/Gabong.GabongGameNotification" }, { + "required": [ + "playerViewOfGame", + "startingPlayerId" + ], "type": "object", - "additionalProperties": false, - "discriminator": { - "propertyName": "type", - "mapping": { - "Gabong.GabongPlayerNotification": "#/components/schemas/Gabong.GabongPlayerNotification", - "Gabong.PlayerPutCardNotification": "#/components/schemas/Gabong.PlayerPutCardNotification", - "Gabong.PlayerDrewCardNotification": "#/components/schemas/Gabong.PlayerDrewCardNotification", - "Gabong.PlayerDrewPenaltyCardNotification": "#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification", - "Gabong.GameStartedNotification": "#/components/schemas/Gabong.GameStartedNotification", - "Gabong.GameEndedNotification": "#/components/schemas/Gabong.GameEndedNotification", - "Gabong.RoundStartedNotification": "#/components/schemas/Gabong.RoundStartedNotification", - "Gabong.RoundEndedNotification": "#/components/schemas/Gabong.RoundEndedNotification", - "Gabong.PlayerLostTheirTurnNotification": "#/components/schemas/Gabong.PlayerLostTheirTurnNotification" + "properties": { + "playerViewOfGame": { + "$ref": "#/components/schemas/Gabong.PlayerViewOfGame" + }, + "startingPlayerId": { + "type": "string", + "format": "uuid" } - } + }, + "additionalProperties": false } ] }, - "Gabong.GabongPlay": { - "enum": [ - "CardPlayed", - "TurnLost", - "RoundStarted" - ], - "type": "string" - }, - "Gabong.GabongPlayer": { + "Gabong.SlimGabongPlayer": { "required": [ - "bongas", - "cards", - "cardsPlayed", - "debtDrawn", - "gabongs", - "hasWon", "id", "name", - "passes", - "penalties", - "roundsWon", - "score", - "shots", - "turnsLost" + "numberOfCards" ], "type": "object", "properties": { @@ -6820,93 +7955,97 @@ "name": { "type": "string" }, - "cards": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.Card" - }, - "readOnly": true - }, - "score": { - "type": "integer", - "format": "int32" - }, - "hasWon": { - "type": "boolean", - "readOnly": true - }, - "penalties": { - "type": "integer", - "format": "int32" - }, - "gabongs": { - "type": "integer", - "format": "int32" - }, - "bongas": { - "type": "integer", - "format": "int32" - }, - "shots": { - "type": "integer", - "format": "int32" - }, - "cardsPlayed": { - "type": "integer", - "format": "int32" - }, - "debtDrawn": { - "type": "integer", - "format": "int32" - }, - "passes": { - "type": "integer", - "format": "int32" - }, - "turnsLost": { - "type": "integer", - "format": "int32" - }, - "roundsWon": { + "numberOfCards": { "type": "integer", "format": "int32" } }, "additionalProperties": false }, - "Gabong.GabongPlayerNotification": { + "Games.GameObject": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongGameNotification" + "$ref": "#/components/schemas/Data.DatabaseObject" }, { "required": [ - "playerId" + "name", + "seed", + "startedTime", + "state", + "version" ], "type": "object", "properties": { - "playerId": { + "name": { + "type": "string" + }, + "startedTime": { "type": "string", - "format": "uuid" + "format": "date-time" + }, + "state": { + "$ref": "#/components/schemas/Games.GameState" + }, + "version": { + "type": "integer", + "format": "int32" + }, + "seed": { + "type": "integer", + "format": "int32" } }, "additionalProperties": false, "discriminator": { "propertyName": "type", "mapping": { - "Gabong.PlayerPutCardNotification": "#/components/schemas/Gabong.PlayerPutCardNotification", - "Gabong.PlayerDrewCardNotification": "#/components/schemas/Gabong.PlayerDrewCardNotification", - "Gabong.PlayerDrewPenaltyCardNotification": "#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification", - "Gabong.PlayerLostTheirTurnNotification": "#/components/schemas/Gabong.PlayerLostTheirTurnNotification" + "Yaniv.YanivGame": "#/components/schemas/Yaniv.YanivGame", + "Uno.UnoGame": "#/components/schemas/Uno.UnoGame", + "TexasHoldEm.TexasHoldEmGame": "#/components/schemas/TexasHoldEm.TexasHoldEmGame", + "Idiot.IdiotGame": "#/components/schemas/Idiot.IdiotGame", + "Hearts.HeartsGame": "#/components/schemas/Hearts.HeartsGame", + "Gabong.GabongGame": "#/components/schemas/Gabong.GabongGame", + "CrazyEights.CrazyEightsGame": "#/components/schemas/CrazyEights.CrazyEightsGame", + "ChatRoom.ChatRoom": "#/components/schemas/ChatRoom.ChatRoom", + "Bullshit.BullshitGame": "#/components/schemas/Bullshit.BullshitGame" } } } ] }, - "Gabong.GabongRequest": { + "Games.GameState": { + "enum": [ + "Waiting", + "Running", + "Finished", + "RoundFinished" + ], + "type": "string" + }, + "Handshake.ConnectFailureMessage": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterRequest" + "$ref": "#/components/schemas/Handshake.ConnectMessage" + }, + { + "required": [ + "errorMessage" + ], + "type": "object", + "properties": { + "errorMessage": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "Handshake.ConnectMessage": { + "allOf": [ + { + "$ref": "#/components/schemas/Protocol.DecksterMessage" }, { "type": "object", @@ -6914,102 +8053,158 @@ "discriminator": { "propertyName": "type", "mapping": { - "Gabong.PutCardRequest": "#/components/schemas/Gabong.PutCardRequest", - "Gabong.DrawCardRequest": "#/components/schemas/Gabong.DrawCardRequest", - "Gabong.PassRequest": "#/components/schemas/Gabong.PassRequest", - "Gabong.PlayGabongRequest": "#/components/schemas/Gabong.PlayGabongRequest", - "Gabong.PlayBongaRequest": "#/components/schemas/Gabong.PlayBongaRequest" + "Handshake.HelloSuccessMessage": "#/components/schemas/Handshake.HelloSuccessMessage", + "Handshake.ConnectSuccessMessage": "#/components/schemas/Handshake.ConnectSuccessMessage", + "Handshake.ConnectFailureMessage": "#/components/schemas/Handshake.ConnectFailureMessage" + } + } + } + ] + }, + "Handshake.ConnectSuccessMessage": { + "allOf": [ + { + "$ref": "#/components/schemas/Handshake.ConnectMessage" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "Handshake.HelloSuccessMessage": { + "allOf": [ + { + "$ref": "#/components/schemas/Handshake.ConnectMessage" + }, + { + "required": [ + "connectionId", + "player" + ], + "type": "object", + "properties": { + "player": { + "$ref": "#/components/schemas/Common.PlayerData" + }, + "connectionId": { + "type": "string", + "format": "uuid" } - } + }, + "additionalProperties": false } ] }, - "Gabong.GabongResponse": { + "Hearts.AllPlayersPassedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterResponse" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "cardsAdded" + "receivedCards" ], "type": "object", "properties": { - "cardsAdded": { + "receivedCards": { "type": "array", "items": { "$ref": "#/components/schemas/Common.Card" } } }, - "additionalProperties": false, - "discriminator": { - "propertyName": "type", - "mapping": { - "Gabong.GabongCardResponse": "#/components/schemas/Gabong.GabongCardResponse", - "Gabong.PlayerViewOfGame": "#/components/schemas/Gabong.PlayerViewOfGame" - } - } + "additionalProperties": false } ] }, - "Gabong.GameEndedNotification": { + "Hearts.CardPlay": { + "required": [ + "card", + "playerId", + "playerName" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "playerName": { + "type": "string" + }, + "card": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "additionalProperties": false + }, + "Hearts.GameEndedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongGameNotification" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "players" + "finalScores", + "winnerId", + "winnerName" ], "type": "object", "properties": { - "players": { + "finalScores": { "type": "array", "items": { - "$ref": "#/components/schemas/Common.PlayerData" + "$ref": "#/components/schemas/Hearts.PlayerScore" } + }, + "winnerId": { + "type": "string", + "format": "uuid" + }, + "winnerName": { + "type": "string" } }, "additionalProperties": false } ] }, - "Gabong.GameStartedNotification": { + "Hearts.GamePhase": { + "enum": [ + "Passing", + "Playing" + ], + "type": "string" + }, + "Hearts.GameStartedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongGameNotification" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "gameId" + "gameId", + "playerViewOfGame" ], "type": "object", "properties": { "gameId": { "type": "string", "format": "uuid" + }, + "playerViewOfGame": { + "$ref": "#/components/schemas/Hearts.PlayerViewOfGame" } }, "additionalProperties": false } ] }, - "Gabong.PassRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/Gabong.GabongRequest" - }, - { - "type": "object", - "additionalProperties": false - } - ] - }, - "Gabong.PenalizePlayerForTakingTooLongRequest": { + "Hearts.HeartsAreBrokenNotification": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterRequest" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "type": "object", @@ -7017,208 +8212,271 @@ } ] }, - "Gabong.PenalizePlayerForTooManyCardsRequest": { + "Hearts.HeartsGame": { "allOf": [ { - "$ref": "#/components/schemas/Protocol.DecksterRequest" + "$ref": "#/components/schemas/Games.GameObject" }, { + "required": [ + "currentPassDirection", + "currentPlayer", + "currentPlayerIndex", + "currentTrick", + "deck", + "heartsAreBroken", + "isFirstTrick", + "phase", + "players", + "roundNumber" + ], "type": "object", + "properties": { + "deck": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "players": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.HeartsPlayer" + } + }, + "currentPlayerIndex": { + "type": "integer", + "format": "int32" + }, + "roundNumber": { + "type": "integer", + "format": "int32" + }, + "heartsAreBroken": { + "type": "boolean" + }, + "currentTrick": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.CardPlay" + } + }, + "leadSuit": { + "$ref": "#/components/schemas/Common.Suit" + }, + "isFirstTrick": { + "type": "boolean" + }, + "phase": { + "$ref": "#/components/schemas/Hearts.GamePhase" + }, + "currentPlayer": { + "$ref": "#/components/schemas/Hearts.HeartsPlayer" + }, + "currentPassDirection": { + "$ref": "#/components/schemas/Hearts.PassDirection" + } + }, "additionalProperties": false } ] }, - "Gabong.PenaltyReason": { - "enum": [ - "PlayOutOfTurn", - "TookTooLong", - "WrongPlay", - "WrongGabong", - "WrongBonga", - "UnpaidDebt", - "PassWithoutDrawing" + "Hearts.HeartsPlayer": { + "required": [ + "cards", + "cardsToPass", + "hasPassed", + "id", + "name", + "roundScore", + "totalScore" ], - "type": "string" - }, - "Gabong.PlayBongaRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/Gabong.GabongRequest" + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - { - "type": "object", - "additionalProperties": false - } - ] - }, - "Gabong.PlayGabongRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/Gabong.GabongRequest" + "name": { + "type": "string" }, - { - "type": "object", - "additionalProperties": false + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "cardsToPass": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "hasPassed": { + "type": "boolean" + }, + "roundScore": { + "type": "integer", + "format": "int32" + }, + "totalScore": { + "type": "integer", + "format": "int32" + }, + "playedCard": { + "$ref": "#/components/schemas/Common.Card" } - ] + }, + "additionalProperties": false }, - "Gabong.PlayerDrewCardNotification": { + "Hearts.ItsPlayersTurnNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongPlayerNotification" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { + "required": [ + "playerId" + ], "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + } + }, "additionalProperties": false } ] }, - "Gabong.PlayerDrewPenaltyCardNotification": { + "Hearts.ItsYourTurnNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongPlayerNotification" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "penaltyReason" + "playerViewOfGame" ], "type": "object", "properties": { - "penaltyReason": { - "$ref": "#/components/schemas/Gabong.PenaltyReason" + "playerViewOfGame": { + "$ref": "#/components/schemas/Hearts.PlayerViewOfGame" } }, "additionalProperties": false } ] }, - "Gabong.PlayerLostTheirTurnNotification": { + "Hearts.OtherHeartsPlayer": { + "required": [ + "name", + "numberOfCards", + "playerId", + "roundScore", + "totalScore" + ], + "type": "object", + "properties": { + "playerId": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "numberOfCards": { + "type": "integer", + "format": "int32" + }, + "totalScore": { + "type": "integer", + "format": "int32" + }, + "roundScore": { + "type": "integer", + "format": "int32" + }, + "playedCard": { + "$ref": "#/components/schemas/Common.Card" + } + }, + "additionalProperties": false + }, + "Hearts.PassCardsRequest": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongPlayerNotification" + "$ref": "#/components/schemas/Protocol.DecksterRequest" }, { "required": [ - "lostTurnReason" + "cards" ], "type": "object", "properties": { - "lostTurnReason": { - "$ref": "#/components/schemas/Gabong.PlayerLostTurnReason" + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } } }, "additionalProperties": false } ] }, - "Gabong.PlayerLostTurnReason": { - "enum": [ - "Passed", - "WrongPlay", - "TookTooLong", - "FinishedDrawingCardDebt" - ], - "type": "string" - }, - "Gabong.PlayerPutCardNotification": { + "Hearts.PassCardsResponse": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongPlayerNotification" + "$ref": "#/components/schemas/Protocol.DecksterResponse" }, { - "required": [ - "card" - ], "type": "object", "properties": { - "card": { - "$ref": "#/components/schemas/Common.Card" - }, - "newSuit": { - "$ref": "#/components/schemas/Common.Suit" + "receivedCards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + }, + "nullable": true } }, "additionalProperties": false } ] }, - "Gabong.PlayerViewOfGame": { + "Hearts.PassDirection": { + "enum": [ + "None", + "Left", + "Right", + "Across" + ], + "type": "string" + }, + "Hearts.PassingPhaseStartedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongResponse" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "cardDebtToDraw", - "cards", - "currentSuit", - "discardPileCount", - "lastPlay", - "lastPlayMadeByPlayerId", - "players", - "playersOrder", - "roundStarted", - "stockPileCount", - "topOfPile" + "passDirection" ], "type": "object", "properties": { - "cards": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.Card" - } - }, - "topOfPile": { - "$ref": "#/components/schemas/Common.Card" - }, - "currentSuit": { - "$ref": "#/components/schemas/Common.Suit" - }, - "stockPileCount": { - "type": "integer", - "format": "int32" - }, - "discardPileCount": { - "type": "integer", - "format": "int32" - }, - "roundStarted": { - "type": "boolean" - }, - "lastPlayMadeByPlayerId": { - "type": "string", - "format": "uuid" - }, - "lastPlay": { - "$ref": "#/components/schemas/Gabong.GabongPlay" - }, - "players": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Gabong.SlimGabongPlayer" - } - }, - "playersOrder": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - } - }, - "cardDebtToDraw": { - "type": "integer", - "format": "int32" + "passDirection": { + "$ref": "#/components/schemas/Hearts.PassDirection" } }, "additionalProperties": false } ] }, - "Gabong.PutCardRequest": { + "Hearts.PlayCardRequest": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongRequest" + "$ref": "#/components/schemas/Protocol.DecksterRequest" }, { "required": [ @@ -7228,210 +8486,211 @@ "properties": { "card": { "$ref": "#/components/schemas/Common.Card" - }, - "newSuit": { - "$ref": "#/components/schemas/Common.Suit" } }, "additionalProperties": false } ] }, - "Gabong.RoundEndedNotification": { + "Hearts.PlayerPassedCardsNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongGameNotification" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "players" + "playerId" ], "type": "object", "properties": { - "players": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Common.PlayerData" - } + "playerId": { + "type": "string", + "format": "uuid" } }, "additionalProperties": false } ] }, - "Gabong.RoundStartedNotification": { + "Hearts.PlayerPlayedCardNotification": { "allOf": [ { - "$ref": "#/components/schemas/Gabong.GabongGameNotification" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "playerViewOfGame", - "startingPlayerId" + "card", + "playerId" ], "type": "object", "properties": { - "playerViewOfGame": { - "$ref": "#/components/schemas/Gabong.PlayerViewOfGame" - }, - "startingPlayerId": { + "playerId": { "type": "string", "format": "uuid" + }, + "card": { + "$ref": "#/components/schemas/Common.Card" } }, "additionalProperties": false } ] }, - "Gabong.SlimGabongPlayer": { + "Hearts.PlayerScore": { "required": [ - "id", - "name", - "numberOfCards" + "playerId", + "playerName", + "roundScore", + "totalScore" ], "type": "object", "properties": { - "id": { + "playerId": { "type": "string", "format": "uuid" }, - "name": { + "playerName": { "type": "string" }, - "numberOfCards": { + "roundScore": { + "type": "integer", + "format": "int32" + }, + "totalScore": { "type": "integer", "format": "int32" } }, "additionalProperties": false }, - "Games.GameObject": { + "Hearts.PlayerViewOfGame": { "allOf": [ { - "$ref": "#/components/schemas/Data.DatabaseObject" + "$ref": "#/components/schemas/Protocol.DecksterResponse" }, { "required": [ - "name", - "seed", - "startedTime", - "state", - "version" + "cards", + "currentTrick", + "hasPassed", + "heartsAreBroken", + "isMyTurn", + "otherPlayers", + "passDirection", + "roundNumber", + "roundScore", + "totalScore" ], "type": "object", "properties": { - "name": { - "type": "string" + "cards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Common.Card" + } }, - "startedTime": { - "type": "string", - "format": "date-time" + "otherPlayers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.OtherHeartsPlayer" + } }, - "state": { - "$ref": "#/components/schemas/Games.GameState" + "roundNumber": { + "type": "integer", + "format": "int32" }, - "version": { + "passDirection": { + "$ref": "#/components/schemas/Hearts.PassDirection" + }, + "hasPassed": { + "type": "boolean" + }, + "currentTrick": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.CardPlay" + } + }, + "totalScore": { "type": "integer", "format": "int32" }, - "seed": { + "roundScore": { "type": "integer", "format": "int32" + }, + "heartsAreBroken": { + "type": "boolean" + }, + "isMyTurn": { + "type": "boolean" } }, - "additionalProperties": false, - "discriminator": { - "propertyName": "type", - "mapping": { - "Yaniv.YanivGame": "#/components/schemas/Yaniv.YanivGame", - "Uno.UnoGame": "#/components/schemas/Uno.UnoGame", - "TexasHoldEm.TexasHoldEmGame": "#/components/schemas/TexasHoldEm.TexasHoldEmGame", - "Idiot.IdiotGame": "#/components/schemas/Idiot.IdiotGame", - "Gabong.GabongGame": "#/components/schemas/Gabong.GabongGame", - "CrazyEights.CrazyEightsGame": "#/components/schemas/CrazyEights.CrazyEightsGame", - "ChatRoom.ChatRoom": "#/components/schemas/ChatRoom.ChatRoom", - "Bullshit.BullshitGame": "#/components/schemas/Bullshit.BullshitGame" - } - } + "additionalProperties": false } ] }, - "Games.GameState": { - "enum": [ - "Waiting", - "Running", - "Finished", - "RoundFinished" - ], - "type": "string" - }, - "Handshake.ConnectFailureMessage": { + "Hearts.RoundEndedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Handshake.ConnectMessage" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "errorMessage" + "scores" ], "type": "object", "properties": { - "errorMessage": { - "type": "string" + "scores": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.PlayerScore" + } + }, + "moonShooterId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "moonShooterName": { + "type": "string", + "nullable": true } }, "additionalProperties": false } ] }, - "Handshake.ConnectMessage": { - "allOf": [ - { - "$ref": "#/components/schemas/Protocol.DecksterMessage" - }, - { - "type": "object", - "additionalProperties": false, - "discriminator": { - "propertyName": "type", - "mapping": { - "Handshake.HelloSuccessMessage": "#/components/schemas/Handshake.HelloSuccessMessage", - "Handshake.ConnectSuccessMessage": "#/components/schemas/Handshake.ConnectSuccessMessage", - "Handshake.ConnectFailureMessage": "#/components/schemas/Handshake.ConnectFailureMessage" - } - } - } - ] - }, - "Handshake.ConnectSuccessMessage": { - "allOf": [ - { - "$ref": "#/components/schemas/Handshake.ConnectMessage" - }, - { - "type": "object", - "additionalProperties": false - } - ] - }, - "Handshake.HelloSuccessMessage": { + "Hearts.TrickCompletedNotification": { "allOf": [ { - "$ref": "#/components/schemas/Handshake.ConnectMessage" + "$ref": "#/components/schemas/Protocol.DecksterNotification" }, { "required": [ - "connectionId", - "player" + "points", + "trickCards", + "winnerId", + "winnerName" ], "type": "object", "properties": { - "player": { - "$ref": "#/components/schemas/Common.PlayerData" - }, - "connectionId": { + "winnerId": { "type": "string", "format": "uuid" + }, + "winnerName": { + "type": "string" + }, + "trickCards": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Hearts.CardPlay" + } + }, + "points": { + "type": "integer", + "format": "int32" } }, "additionalProperties": false @@ -8301,6 +9560,21 @@ "Idiot.GameStartedNotification": "#/components/schemas/Idiot.GameStartedNotification", "Idiot.GameEndedNotification": "#/components/schemas/Idiot.GameEndedNotification", "Idiot.ItsTimeToSwapCardsNotification": "#/components/schemas/Idiot.ItsTimeToSwapCardsNotification", + "Hearts.PassCardsRequest": "#/components/schemas/Hearts.PassCardsRequest", + "Hearts.PlayCardRequest": "#/components/schemas/Hearts.PlayCardRequest", + "Hearts.PassCardsResponse": "#/components/schemas/Hearts.PassCardsResponse", + "Hearts.GameStartedNotification": "#/components/schemas/Hearts.GameStartedNotification", + "Hearts.PassingPhaseStartedNotification": "#/components/schemas/Hearts.PassingPhaseStartedNotification", + "Hearts.AllPlayersPassedNotification": "#/components/schemas/Hearts.AllPlayersPassedNotification", + "Hearts.PlayerPassedCardsNotification": "#/components/schemas/Hearts.PlayerPassedCardsNotification", + "Hearts.ItsYourTurnNotification": "#/components/schemas/Hearts.ItsYourTurnNotification", + "Hearts.ItsPlayersTurnNotification": "#/components/schemas/Hearts.ItsPlayersTurnNotification", + "Hearts.PlayerPlayedCardNotification": "#/components/schemas/Hearts.PlayerPlayedCardNotification", + "Hearts.TrickCompletedNotification": "#/components/schemas/Hearts.TrickCompletedNotification", + "Hearts.RoundEndedNotification": "#/components/schemas/Hearts.RoundEndedNotification", + "Hearts.GameEndedNotification": "#/components/schemas/Hearts.GameEndedNotification", + "Hearts.HeartsAreBrokenNotification": "#/components/schemas/Hearts.HeartsAreBrokenNotification", + "Hearts.PlayerViewOfGame": "#/components/schemas/Hearts.PlayerViewOfGame", "Gabong.GabongGameNotification": "#/components/schemas/Gabong.GabongGameNotification", "Gabong.GabongPlayerNotification": "#/components/schemas/Gabong.GabongPlayerNotification", "Gabong.PlayerPutCardNotification": "#/components/schemas/Gabong.PlayerPutCardNotification", @@ -8418,6 +9692,17 @@ "Idiot.GameStartedNotification": "#/components/schemas/Idiot.GameStartedNotification", "Idiot.GameEndedNotification": "#/components/schemas/Idiot.GameEndedNotification", "Idiot.ItsTimeToSwapCardsNotification": "#/components/schemas/Idiot.ItsTimeToSwapCardsNotification", + "Hearts.GameStartedNotification": "#/components/schemas/Hearts.GameStartedNotification", + "Hearts.PassingPhaseStartedNotification": "#/components/schemas/Hearts.PassingPhaseStartedNotification", + "Hearts.AllPlayersPassedNotification": "#/components/schemas/Hearts.AllPlayersPassedNotification", + "Hearts.PlayerPassedCardsNotification": "#/components/schemas/Hearts.PlayerPassedCardsNotification", + "Hearts.ItsYourTurnNotification": "#/components/schemas/Hearts.ItsYourTurnNotification", + "Hearts.ItsPlayersTurnNotification": "#/components/schemas/Hearts.ItsPlayersTurnNotification", + "Hearts.PlayerPlayedCardNotification": "#/components/schemas/Hearts.PlayerPlayedCardNotification", + "Hearts.TrickCompletedNotification": "#/components/schemas/Hearts.TrickCompletedNotification", + "Hearts.RoundEndedNotification": "#/components/schemas/Hearts.RoundEndedNotification", + "Hearts.GameEndedNotification": "#/components/schemas/Hearts.GameEndedNotification", + "Hearts.HeartsAreBrokenNotification": "#/components/schemas/Hearts.HeartsAreBrokenNotification", "Gabong.GabongGameNotification": "#/components/schemas/Gabong.GabongGameNotification", "Gabong.GabongPlayerNotification": "#/components/schemas/Gabong.GabongPlayerNotification", "Gabong.PlayerPutCardNotification": "#/components/schemas/Gabong.PlayerPutCardNotification", @@ -8494,6 +9779,8 @@ "Idiot.DrawCardsRequest": "#/components/schemas/Idiot.DrawCardsRequest", "Idiot.PullInDiscardPileRequest": "#/components/schemas/Idiot.PullInDiscardPileRequest", "Idiot.PutChanceCardRequest": "#/components/schemas/Idiot.PutChanceCardRequest", + "Hearts.PassCardsRequest": "#/components/schemas/Hearts.PassCardsRequest", + "Hearts.PlayCardRequest": "#/components/schemas/Hearts.PlayCardRequest", "Gabong.PenalizePlayerForTakingTooLongRequest": "#/components/schemas/Gabong.PenalizePlayerForTakingTooLongRequest", "Gabong.PenalizePlayerForTooManyCardsRequest": "#/components/schemas/Gabong.PenalizePlayerForTooManyCardsRequest", "Gabong.GabongRequest": "#/components/schemas/Gabong.GabongRequest", @@ -8548,6 +9835,8 @@ "Idiot.PullInResponse": "#/components/schemas/Idiot.PullInResponse", "Idiot.DrawCardsResponse": "#/components/schemas/Idiot.DrawCardsResponse", "Idiot.PutBlindCardResponse": "#/components/schemas/Idiot.PutBlindCardResponse", + "Hearts.PassCardsResponse": "#/components/schemas/Hearts.PassCardsResponse", + "Hearts.PlayerViewOfGame": "#/components/schemas/Hearts.PlayerViewOfGame", "Gabong.GabongResponse": "#/components/schemas/Gabong.GabongResponse", "Gabong.GabongCardResponse": "#/components/schemas/Gabong.GabongCardResponse", "Gabong.ActionResponse": "#/components/schemas/Gabong.ActionResponse", diff --git a/generated/shebang.opeanpi.yaml b/generated/shebang.opeanpi.yaml index 45a55671..14d6d4c6 100644 --- a/generated/shebang.opeanpi.yaml +++ b/generated/shebang.opeanpi.yaml @@ -1,4 +1,4 @@ -openapi: 3.0.1 +openapi: 3.0.4 info: title: Deckster.Server version: '1.0' @@ -1547,48 +1547,17 @@ paths: responses: '200': description: OK - /: - get: - tags: - - Home - responses: - '200': - description: OK - /login: - get: - tags: - - Home - responses: - '200': - description: OK - post: - tags: - - Home - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/Controllers.LoginModel' - text/json: - schema: - $ref: '#/components/schemas/Controllers.LoginModel' - application/*+json: - schema: - $ref: '#/components/schemas/Controllers.LoginModel' - responses: - '200': - description: OK - /idiot/description: + /hearts/description: get: tags: - - Idiot + - Hearts responses: '200': description: OK - /idiot/metadata: + /hearts/metadata: get: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1602,10 +1571,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Meta.GameMeta' - /idiot: + /hearts: get: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1619,10 +1588,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.GameOverviewVm' - /idiot/games: + /hearts/games: get: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1642,10 +1611,10 @@ paths: type: array items: $ref: '#/components/schemas/Controllers.GameVm' - '/idiot/games/{name}': + '/hearts/games/{name}': get: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1679,7 +1648,7 @@ paths: $ref: '#/components/schemas/Controllers.ResponseMessage' delete: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1711,10 +1680,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/idiot/games/{name}/bot': + '/hearts/games/{name}/bot': post: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1734,10 +1703,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /idiot/previousgames: + /hearts/previousgames: get: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1746,21 +1715,21 @@ paths: schema: type: array items: - $ref: '#/components/schemas/Idiot.IdiotGame' + $ref: '#/components/schemas/Hearts.HeartsGame' application/json: schema: type: array items: - $ref: '#/components/schemas/Idiot.IdiotGame' + $ref: '#/components/schemas/Hearts.HeartsGame' text/json: schema: type: array items: - $ref: '#/components/schemas/Idiot.IdiotGame' - '/idiot/previousgames/{id}': + $ref: '#/components/schemas/Hearts.HeartsGame' + '/hearts/previousgames/{id}': get: tags: - - Idiot + - Hearts parameters: - name: id in: path @@ -1774,17 +1743,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' + $ref: '#/components/schemas/Data.HistoricHeartsGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' + $ref: '#/components/schemas/Data.HistoricHeartsGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' - '/idiot/previousgames/{id}/{version}': + $ref: '#/components/schemas/Data.HistoricHeartsGame' + '/hearts/previousgames/{id}/{version}': get: tags: - - Idiot + - Hearts parameters: - name: id in: path @@ -1804,17 +1773,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' + $ref: '#/components/schemas/Data.HistoricHeartsGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' + $ref: '#/components/schemas/Data.HistoricHeartsGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricIdiotGame' - '/idiot/create/{name}': + $ref: '#/components/schemas/Data.HistoricHeartsGame' + '/hearts/create/{name}': post: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1846,10 +1815,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /idiot/create: + /hearts/create: post: tags: - - Idiot + - Hearts responses: '200': description: OK @@ -1875,10 +1844,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/idiot/games/{name}/start': + '/hearts/games/{name}/start': post: tags: - - Idiot + - Hearts parameters: - name: name in: path @@ -1910,10 +1879,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/idiot/join/{gameName}': + '/hearts/join/{gameName}': get: tags: - - Idiot + - Hearts parameters: - name: gameName in: path @@ -1923,10 +1892,10 @@ paths: responses: '200': description: OK - '/idiot/join/{connectionId}/finish': + '/hearts/join/{connectionId}/finish': get: tags: - - Idiot + - Hearts parameters: - name: connectionId in: path @@ -1937,10 +1906,10 @@ paths: responses: '200': description: OK - '/idiot/spectate/{gameName}': + '/hearts/spectate/{gameName}': get: tags: - - Idiot + - Hearts parameters: - name: gameName in: path @@ -1950,10 +1919,10 @@ paths: responses: '200': description: OK - '/idiot/spectate/{connectionId}/finish': + '/hearts/spectate/{connectionId}/finish': get: tags: - - Idiot + - Hearts parameters: - name: connectionId in: path @@ -1964,24 +1933,48 @@ paths: responses: '200': description: OK - /meta/messages: + /: get: tags: - - Meta + - Home responses: '200': description: OK - /texasholdem/description: + /login: get: tags: - - TexasHoldEm + - Home responses: '200': description: OK - /texasholdem/metadata: + post: + tags: + - Home + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Controllers.LoginModel' + text/json: + schema: + $ref: '#/components/schemas/Controllers.LoginModel' + application/*+json: + schema: + $ref: '#/components/schemas/Controllers.LoginModel' + responses: + '200': + description: OK + /idiot/description: get: tags: - - TexasHoldEm + - Idiot + responses: + '200': + description: OK + /idiot/metadata: + get: + tags: + - Idiot responses: '200': description: OK @@ -1995,10 +1988,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Meta.GameMeta' - /texasholdem: + /idiot: get: tags: - - TexasHoldEm + - Idiot responses: '200': description: OK @@ -2012,10 +2005,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.GameOverviewVm' - /texasholdem/games: + /idiot/games: get: tags: - - TexasHoldEm + - Idiot responses: '200': description: OK @@ -2035,10 +2028,10 @@ paths: type: array items: $ref: '#/components/schemas/Controllers.GameVm' - '/texasholdem/games/{name}': + '/idiot/games/{name}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2072,7 +2065,7 @@ paths: $ref: '#/components/schemas/Controllers.ResponseMessage' delete: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2104,10 +2097,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/texasholdem/games/{name}/bot': + '/idiot/games/{name}/bot': post: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2127,10 +2120,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /texasholdem/previousgames: + /idiot/previousgames: get: tags: - - TexasHoldEm + - Idiot responses: '200': description: OK @@ -2139,21 +2132,21 @@ paths: schema: type: array items: - $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + $ref: '#/components/schemas/Idiot.IdiotGame' application/json: schema: type: array items: - $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + $ref: '#/components/schemas/Idiot.IdiotGame' text/json: schema: type: array items: - $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' - '/texasholdem/previousgames/{id}': + $ref: '#/components/schemas/Idiot.IdiotGame' + '/idiot/previousgames/{id}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: id in: path @@ -2167,17 +2160,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + $ref: '#/components/schemas/Data.HistoricIdiotGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + $ref: '#/components/schemas/Data.HistoricIdiotGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' - '/texasholdem/previousgames/{id}/{version}': + $ref: '#/components/schemas/Data.HistoricIdiotGame' + '/idiot/previousgames/{id}/{version}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: id in: path @@ -2197,17 +2190,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + $ref: '#/components/schemas/Data.HistoricIdiotGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + $ref: '#/components/schemas/Data.HistoricIdiotGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' - '/texasholdem/create/{name}': + $ref: '#/components/schemas/Data.HistoricIdiotGame' + '/idiot/create/{name}': post: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2239,10 +2232,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /texasholdem/create: + /idiot/create: post: tags: - - TexasHoldEm + - Idiot responses: '200': description: OK @@ -2268,10 +2261,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/texasholdem/games/{name}/start': + '/idiot/games/{name}/start': post: tags: - - TexasHoldEm + - Idiot parameters: - name: name in: path @@ -2303,10 +2296,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/texasholdem/join/{gameName}': + '/idiot/join/{gameName}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: gameName in: path @@ -2316,10 +2309,10 @@ paths: responses: '200': description: OK - '/texasholdem/join/{connectionId}/finish': + '/idiot/join/{connectionId}/finish': get: tags: - - TexasHoldEm + - Idiot parameters: - name: connectionId in: path @@ -2330,10 +2323,10 @@ paths: responses: '200': description: OK - '/texasholdem/spectate/{gameName}': + '/idiot/spectate/{gameName}': get: tags: - - TexasHoldEm + - Idiot parameters: - name: gameName in: path @@ -2343,10 +2336,10 @@ paths: responses: '200': description: OK - '/texasholdem/spectate/{connectionId}/finish': + '/idiot/spectate/{connectionId}/finish': get: tags: - - TexasHoldEm + - Idiot parameters: - name: connectionId in: path @@ -2357,17 +2350,24 @@ paths: responses: '200': description: OK - /uno/description: + /meta/messages: get: tags: - - Uno + - Meta responses: '200': description: OK - /uno/metadata: + /texasholdem/description: get: tags: - - Uno + - TexasHoldEm + responses: + '200': + description: OK + /texasholdem/metadata: + get: + tags: + - TexasHoldEm responses: '200': description: OK @@ -2381,10 +2381,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Meta.GameMeta' - /uno: + /texasholdem: get: tags: - - Uno + - TexasHoldEm responses: '200': description: OK @@ -2398,10 +2398,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.GameOverviewVm' - /uno/games: + /texasholdem/games: get: tags: - - Uno + - TexasHoldEm responses: '200': description: OK @@ -2421,10 +2421,10 @@ paths: type: array items: $ref: '#/components/schemas/Controllers.GameVm' - '/uno/games/{name}': + '/texasholdem/games/{name}': get: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2458,7 +2458,7 @@ paths: $ref: '#/components/schemas/Controllers.ResponseMessage' delete: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2490,10 +2490,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/uno/games/{name}/bot': + '/texasholdem/games/{name}/bot': post: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2513,10 +2513,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /uno/previousgames: + /texasholdem/previousgames: get: tags: - - Uno + - TexasHoldEm responses: '200': description: OK @@ -2525,21 +2525,21 @@ paths: schema: type: array items: - $ref: '#/components/schemas/Uno.UnoGame' + $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' application/json: schema: type: array items: - $ref: '#/components/schemas/Uno.UnoGame' + $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' text/json: schema: type: array items: - $ref: '#/components/schemas/Uno.UnoGame' - '/uno/previousgames/{id}': + $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + '/texasholdem/previousgames/{id}': get: tags: - - Uno + - TexasHoldEm parameters: - name: id in: path @@ -2553,17 +2553,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' - '/uno/previousgames/{id}/{version}': - get: + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + '/texasholdem/previousgames/{id}/{version}': + get: tags: - - Uno + - TexasHoldEm parameters: - name: id in: path @@ -2583,17 +2583,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricUnoGame' - '/uno/create/{name}': + $ref: '#/components/schemas/Data.HistoricTexasHoldEmGame' + '/texasholdem/create/{name}': post: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2625,10 +2625,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /uno/create: + /texasholdem/create: post: tags: - - Uno + - TexasHoldEm responses: '200': description: OK @@ -2654,10 +2654,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/uno/games/{name}/start': + '/texasholdem/games/{name}/start': post: tags: - - Uno + - TexasHoldEm parameters: - name: name in: path @@ -2689,10 +2689,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/uno/join/{gameName}': + '/texasholdem/join/{gameName}': get: tags: - - Uno + - TexasHoldEm parameters: - name: gameName in: path @@ -2702,10 +2702,10 @@ paths: responses: '200': description: OK - '/uno/join/{connectionId}/finish': + '/texasholdem/join/{connectionId}/finish': get: tags: - - Uno + - TexasHoldEm parameters: - name: connectionId in: path @@ -2716,10 +2716,10 @@ paths: responses: '200': description: OK - '/uno/spectate/{gameName}': + '/texasholdem/spectate/{gameName}': get: tags: - - Uno + - TexasHoldEm parameters: - name: gameName in: path @@ -2729,10 +2729,10 @@ paths: responses: '200': description: OK - '/uno/spectate/{connectionId}/finish': + '/texasholdem/spectate/{connectionId}/finish': get: tags: - - Uno + - TexasHoldEm parameters: - name: connectionId in: path @@ -2743,24 +2743,17 @@ paths: responses: '200': description: OK - /me: - get: - tags: - - User - responses: - '200': - description: OK - /yaniv/description: + /uno/description: get: tags: - - Yaniv + - Uno responses: '200': description: OK - /yaniv/metadata: + /uno/metadata: get: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -2774,10 +2767,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Meta.GameMeta' - /yaniv: + /uno: get: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -2791,10 +2784,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.GameOverviewVm' - /yaniv/games: + /uno/games: get: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -2814,10 +2807,10 @@ paths: type: array items: $ref: '#/components/schemas/Controllers.GameVm' - '/yaniv/games/{name}': + '/uno/games/{name}': get: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -2851,7 +2844,7 @@ paths: $ref: '#/components/schemas/Controllers.ResponseMessage' delete: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -2883,10 +2876,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/yaniv/games/{name}/bot': + '/uno/games/{name}/bot': post: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -2906,10 +2899,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /yaniv/previousgames: + /uno/previousgames: get: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -2918,21 +2911,21 @@ paths: schema: type: array items: - $ref: '#/components/schemas/Yaniv.YanivGame' + $ref: '#/components/schemas/Uno.UnoGame' application/json: schema: type: array items: - $ref: '#/components/schemas/Yaniv.YanivGame' + $ref: '#/components/schemas/Uno.UnoGame' text/json: schema: type: array items: - $ref: '#/components/schemas/Yaniv.YanivGame' - '/yaniv/previousgames/{id}': + $ref: '#/components/schemas/Uno.UnoGame' + '/uno/previousgames/{id}': get: tags: - - Yaniv + - Uno parameters: - name: id in: path @@ -2946,17 +2939,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' + $ref: '#/components/schemas/Data.HistoricUnoGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' + $ref: '#/components/schemas/Data.HistoricUnoGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' - '/yaniv/previousgames/{id}/{version}': + $ref: '#/components/schemas/Data.HistoricUnoGame' + '/uno/previousgames/{id}/{version}': get: tags: - - Yaniv + - Uno parameters: - name: id in: path @@ -2976,17 +2969,17 @@ paths: content: text/plain: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' + $ref: '#/components/schemas/Data.HistoricUnoGame' application/json: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' + $ref: '#/components/schemas/Data.HistoricUnoGame' text/json: schema: - $ref: '#/components/schemas/Data.HistoricYanivGame' - '/yaniv/create/{name}': + $ref: '#/components/schemas/Data.HistoricUnoGame' + '/uno/create/{name}': post: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -3018,10 +3011,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - /yaniv/create: + /uno/create: post: tags: - - Yaniv + - Uno responses: '200': description: OK @@ -3047,10 +3040,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/yaniv/games/{name}/start': + '/uno/games/{name}/start': post: tags: - - Yaniv + - Uno parameters: - name: name in: path @@ -3082,10 +3075,10 @@ paths: text/json: schema: $ref: '#/components/schemas/Controllers.ResponseMessage' - '/yaniv/join/{gameName}': + '/uno/join/{gameName}': get: tags: - - Yaniv + - Uno parameters: - name: gameName in: path @@ -3095,10 +3088,10 @@ paths: responses: '200': description: OK - '/yaniv/join/{connectionId}/finish': + '/uno/join/{connectionId}/finish': get: tags: - - Yaniv + - Uno parameters: - name: connectionId in: path @@ -3109,10 +3102,10 @@ paths: responses: '200': description: OK - '/yaniv/spectate/{gameName}': + '/uno/spectate/{gameName}': get: tags: - - Yaniv + - Uno parameters: - name: gameName in: path @@ -3122,10 +3115,10 @@ paths: responses: '200': description: OK - '/yaniv/spectate/{connectionId}/finish': + '/uno/spectate/{connectionId}/finish': get: tags: - - Yaniv + - Uno parameters: - name: connectionId in: path @@ -3136,132 +3129,877 @@ paths: responses: '200': description: OK -components: - schemas: - Bullshit.BullshitBroadcastNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - actualCard - - claimedToBeCard - - playerId - - punishmentCardCount - type: object - properties: - playerId: - type: string - format: uuid - claimedToBeCard: - $ref: '#/components/schemas/Common.Card' - actualCard: - $ref: '#/components/schemas/Common.Card' - punishmentCardCount: - type: integer - format: int32 - additionalProperties: false - Bullshit.BullshitGame: - allOf: - - $ref: '#/components/schemas/Games.GameObject' - - required: - - cardsDrawn - - currentPlayer - - currentPlayerIndex - - deck - - discardPile - - donePlayers - - players - - stockPile - type: object - properties: - deck: - type: array - items: - $ref: '#/components/schemas/Common.Card' - stockPile: - type: array - items: - $ref: '#/components/schemas/Common.Card' - discardPile: - type: array - items: - $ref: '#/components/schemas/Common.Card' - players: - type: array - items: - $ref: '#/components/schemas/Bullshit.BullshitPlayer' - donePlayers: - type: array - items: - $ref: '#/components/schemas/Bullshit.BullshitPlayer' - currentPlayerIndex: - type: integer - format: int32 - claimedTopOfPile: - $ref: '#/components/schemas/Common.Card' - actualTopOfPile: - $ref: '#/components/schemas/Common.Card' - cardsDrawn: - type: integer - format: int32 - potentialBullshit: - $ref: '#/components/schemas/Bullshit.PotentialBullshit' - currentPlayer: - $ref: '#/components/schemas/Bullshit.BullshitPlayer' - additionalProperties: false - Bullshit.BullshitPlayer: - required: - - cards - - id - - name - type: object - properties: - id: - type: string - format: uuid - name: - type: string - cards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Bullshit.BullshitPlayerNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - calledByPlayerId - - card - - punishmentCards - type: object - properties: - calledByPlayerId: - type: string - format: uuid - card: - $ref: '#/components/schemas/Common.Card' - punishmentCards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Bullshit.BullshitRequest: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' - - type: object - additionalProperties: false - Bullshit.BullshitResponse: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' - - required: - - punishmentCards - type: object - properties: - punishmentCards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Bullshit.CardResponse: + /me: + get: + tags: + - User + responses: + '200': + description: OK + /yaniv/description: + get: + tags: + - Yaniv + responses: + '200': + description: OK + /yaniv/metadata: + get: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Meta.GameMeta' + application/json: + schema: + $ref: '#/components/schemas/Meta.GameMeta' + text/json: + schema: + $ref: '#/components/schemas/Meta.GameMeta' + /yaniv: + get: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.GameOverviewVm' + application/json: + schema: + $ref: '#/components/schemas/Controllers.GameOverviewVm' + text/json: + schema: + $ref: '#/components/schemas/Controllers.GameOverviewVm' + /yaniv/games: + get: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + type: array + items: + $ref: '#/components/schemas/Controllers.GameVm' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Controllers.GameVm' + text/json: + schema: + type: array + items: + $ref: '#/components/schemas/Controllers.GameVm' + '/yaniv/games/{name}': + get: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + application/json: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + text/json: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + '404': + description: Not Found + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + delete: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + application/json: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + text/json: + schema: + $ref: '#/components/schemas/Controllers.GameVm' + '404': + description: Not Found + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + '/yaniv/games/{name}/bot': + post: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + /yaniv/previousgames: + get: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + type: array + items: + $ref: '#/components/schemas/Yaniv.YanivGame' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Yaniv.YanivGame' + text/json: + schema: + type: array + items: + $ref: '#/components/schemas/Yaniv.YanivGame' + '/yaniv/previousgames/{id}': + get: + tags: + - Yaniv + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + application/json: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + text/json: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + '/yaniv/previousgames/{id}/{version}': + get: + tags: + - Yaniv + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: version + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + application/json: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + text/json: + schema: + $ref: '#/components/schemas/Data.HistoricYanivGame' + '/yaniv/create/{name}': + post: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Core.GameInfo' + application/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + text/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + '400': + description: Bad Request + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + /yaniv/create: + post: + tags: + - Yaniv + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Core.GameInfo' + application/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + text/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + '400': + description: Bad Request + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + '/yaniv/games/{name}/start': + post: + tags: + - Yaniv + parameters: + - name: name + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/Core.GameInfo' + application/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + text/json: + schema: + $ref: '#/components/schemas/Core.GameInfo' + '404': + description: Not Found + content: + text/plain: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + application/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + text/json: + schema: + $ref: '#/components/schemas/Controllers.ResponseMessage' + '/yaniv/join/{gameName}': + get: + tags: + - Yaniv + parameters: + - name: gameName + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '/yaniv/join/{connectionId}/finish': + get: + tags: + - Yaniv + parameters: + - name: connectionId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: OK + '/yaniv/spectate/{gameName}': + get: + tags: + - Yaniv + parameters: + - name: gameName + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '/yaniv/spectate/{connectionId}/finish': + get: + tags: + - Yaniv + parameters: + - name: connectionId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: OK +components: + schemas: + Bullshit.BullshitBroadcastNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - actualCard + - claimedToBeCard + - playerId + - punishmentCardCount + type: object + properties: + playerId: + type: string + format: uuid + claimedToBeCard: + $ref: '#/components/schemas/Common.Card' + actualCard: + $ref: '#/components/schemas/Common.Card' + punishmentCardCount: + type: integer + format: int32 + additionalProperties: false + Bullshit.BullshitGame: + allOf: + - $ref: '#/components/schemas/Games.GameObject' + - required: + - cardsDrawn + - currentPlayer + - currentPlayerIndex + - deck + - discardPile + - donePlayers + - players + - stockPile + type: object + properties: + deck: + type: array + items: + $ref: '#/components/schemas/Common.Card' + stockPile: + type: array + items: + $ref: '#/components/schemas/Common.Card' + discardPile: + type: array + items: + $ref: '#/components/schemas/Common.Card' + players: + type: array + items: + $ref: '#/components/schemas/Bullshit.BullshitPlayer' + donePlayers: + type: array + items: + $ref: '#/components/schemas/Bullshit.BullshitPlayer' + currentPlayerIndex: + type: integer + format: int32 + claimedTopOfPile: + $ref: '#/components/schemas/Common.Card' + actualTopOfPile: + $ref: '#/components/schemas/Common.Card' + cardsDrawn: + type: integer + format: int32 + potentialBullshit: + $ref: '#/components/schemas/Bullshit.PotentialBullshit' + currentPlayer: + $ref: '#/components/schemas/Bullshit.BullshitPlayer' + additionalProperties: false + Bullshit.BullshitPlayer: + required: + - cards + - id + - name + type: object + properties: + id: + type: string + format: uuid + name: + type: string + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.BullshitPlayerNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - calledByPlayerId + - card + - punishmentCards + type: object + properties: + calledByPlayerId: + type: string + format: uuid + card: + $ref: '#/components/schemas/Common.Card' + punishmentCards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.BullshitRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object + additionalProperties: false + Bullshit.BullshitResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - required: + - punishmentCards + type: object + properties: + punishmentCards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.CardResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - required: + - card + type: object + properties: + card: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.DiscardPileShuffledNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + additionalProperties: false + Bullshit.DrawCardRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object + additionalProperties: false + Bullshit.FalseBullshitCallNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - accusedPlayerId + - playerId + - punishmentCardCount + type: object + properties: + playerId: + type: string + format: uuid + accusedPlayerId: + type: string + format: uuid + punishmentCardCount: + type: integer + format: int32 + additionalProperties: false + Bullshit.GameEndedNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - loserId + - loserName + - players + type: object + properties: + players: + type: array + items: + $ref: '#/components/schemas/Common.PlayerData' + loserId: + type: string + format: uuid + loserName: + type: string + additionalProperties: false + Bullshit.GameStartedNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - gameId + - playerViewOfGame + type: object + properties: + gameId: + type: string + format: uuid + playerViewOfGame: + $ref: '#/components/schemas/Bullshit.PlayerViewOfGame' + additionalProperties: false + Bullshit.ItsPlayersTurnNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid + additionalProperties: false + Bullshit.ItsYourTurnNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + additionalProperties: false + Bullshit.OtherBullshitPlayer: + required: + - name + - numberOfCards + - playerId + type: object + properties: + playerId: + type: string + format: uuid + name: + type: string + numberOfCards: + type: integer + format: int32 + additionalProperties: false + Bullshit.PassRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object + additionalProperties: false + Bullshit.PlayerDrewCardNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid + additionalProperties: false + Bullshit.PlayerIsDoneNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid + additionalProperties: false + Bullshit.PlayerPassedNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid + additionalProperties: false + Bullshit.PlayerPutCardNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - claimedToBeCard + - playerId + type: object + properties: + playerId: + type: string + format: uuid + claimedToBeCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.PlayerViewOfGame: + required: + - cards + - discardPileCount + - otherPlayers + - stockPileCount + type: object + properties: + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + claimedTopOfPile: + $ref: '#/components/schemas/Common.Card' + stockPileCount: + type: integer + format: int32 + discardPileCount: + type: integer + format: int32 + otherPlayers: + type: array + items: + $ref: '#/components/schemas/Bullshit.OtherBullshitPlayer' + additionalProperties: false + Bullshit.PotentialBullshit: + required: + - claimedToBeCard + - playerId + type: object + properties: + playerId: + type: string + format: uuid + claimedToBeCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Bullshit.PutCardRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - required: + - actualCard + - claimedToBeCard + type: object + properties: + actualCard: + $ref: '#/components/schemas/Common.Card' + claimedToBeCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + ChatRoom.ChatNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - message + - sender + type: object + properties: + sender: + type: string + message: + type: string + additionalProperties: false + ChatRoom.ChatResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + additionalProperties: false + ChatRoom.ChatRoom: + allOf: + - $ref: '#/components/schemas/Games.GameObject' + - required: + - transcript + type: object + properties: + transcript: + type: array + items: + $ref: '#/components/schemas/ChatRoom.SendChatRequest' + additionalProperties: false + ChatRoom.SendChatRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - required: + - message + type: object + properties: + message: + type: string + additionalProperties: false + Common.Card: + required: + - rank + - suit + type: object + properties: + rank: + type: integer + format: int32 + suit: + $ref: '#/components/schemas/Common.Suit' + additionalProperties: false + Common.EmptyResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + additionalProperties: false + Common.PlayerData: + required: + - cardsInHand + - id + - info + - name + - points + type: object + properties: + name: + type: string + points: + type: number + format: double + cardsInHand: + type: integer + format: int32 + id: + type: string + format: uuid + info: + type: object + additionalProperties: + type: string + additionalProperties: false + Common.Suit: + enum: + - Clubs + - Diamonds + - Hearts + - Spades + type: string + Controllers.GameOverviewVm: + required: + - games + - gameType + type: object + properties: + gameType: + type: string + games: + type: array + items: + $ref: '#/components/schemas/Controllers.GameVm' + additionalProperties: false + Controllers.GameVm: + required: + - gameType + - name + - players + - state + type: object + properties: + gameType: + type: string + name: + type: string + state: + $ref: '#/components/schemas/Games.GameState' + players: + type: array + items: + $ref: '#/components/schemas/Common.PlayerData' + additionalProperties: false + Controllers.LoginModel: + type: object + properties: + username: + type: string + nullable: true + password: + type: string + nullable: true + additionalProperties: false + Controllers.ResponseMessage: + type: object + properties: + message: + type: string + nullable: true + additionalProperties: false + Core.GameInfo: + required: + - id + type: object + properties: + id: + type: string + additionalProperties: false + CrazyEights.CardResponse: allOf: - $ref: '#/components/schemas/Protocol.DecksterResponse' - required: @@ -3271,36 +4009,106 @@ components: card: $ref: '#/components/schemas/Common.Card' additionalProperties: false - Bullshit.DiscardPileShuffledNotification: + CrazyEights.CrazyEightsGame: + allOf: + - $ref: '#/components/schemas/Games.GameObject' + - required: + - cardsDrawn + - currentPlayer + - currentPlayerIndex + - currentSuit + - deck + - discardPile + - donePlayers + - initialCardsPerPlayer + - players + - spectators + - stockPile + - topOfPile + type: object + properties: + initialCardsPerPlayer: + type: integer + format: int32 + currentPlayerIndex: + type: integer + format: int32 + cardsDrawn: + type: integer + format: int32 + donePlayers: + type: array + items: + $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + deck: + type: array + items: + $ref: '#/components/schemas/Common.Card' + stockPile: + type: array + items: + $ref: '#/components/schemas/Common.Card' + discardPile: + type: array + items: + $ref: '#/components/schemas/Common.Card' + players: + type: array + items: + $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + spectators: + type: array + items: + $ref: '#/components/schemas/CrazyEights.CrazyEightsSpectator' + newSuit: + $ref: '#/components/schemas/Common.Suit' + topOfPile: + $ref: '#/components/schemas/Common.Card' + currentSuit: + $ref: '#/components/schemas/Common.Suit' + currentPlayer: + $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + additionalProperties: false + CrazyEights.CrazyEightsPlayer: + required: + - cards + - id + - name + type: object + properties: + id: + type: string + format: uuid + name: + type: string + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + CrazyEights.CrazyEightsSpectator: + required: + - id + - name + type: object + properties: + id: + type: string + format: uuid + name: + type: string + additionalProperties: false + CrazyEights.DiscardPileShuffledNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - type: object additionalProperties: false - Bullshit.DrawCardRequest: + CrazyEights.DrawCardRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - type: object additionalProperties: false - Bullshit.FalseBullshitCallNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - accusedPlayerId - - playerId - - punishmentCardCount - type: object - properties: - playerId: - type: string - format: uuid - accusedPlayerId: - type: string - format: uuid - punishmentCardCount: - type: integer - format: int32 - additionalProperties: false - Bullshit.GameEndedNotification: + CrazyEights.GameEndedNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: @@ -3319,7 +4127,7 @@ components: loserName: type: string additionalProperties: false - Bullshit.GameStartedNotification: + CrazyEights.GameStartedNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: @@ -3331,9 +4139,9 @@ components: type: string format: uuid playerViewOfGame: - $ref: '#/components/schemas/Bullshit.PlayerViewOfGame' + $ref: '#/components/schemas/CrazyEights.PlayerViewOfGame' additionalProperties: false - Bullshit.ItsPlayersTurnNotification: + CrazyEights.ItsPlayersTurnNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: @@ -3344,12 +4152,17 @@ components: type: string format: uuid additionalProperties: false - Bullshit.ItsYourTurnNotification: + CrazyEights.ItsYourTurnNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - - type: object + - required: + - playerViewOfGame + type: object + properties: + playerViewOfGame: + $ref: '#/components/schemas/CrazyEights.PlayerViewOfGame' additionalProperties: false - Bullshit.OtherBullshitPlayer: + CrazyEights.OtherCrazyEightsPlayer: required: - name - numberOfCards @@ -3365,257 +4178,222 @@ components: type: integer format: int32 additionalProperties: false - Bullshit.PassRequest: + CrazyEights.PassRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - type: object additionalProperties: false - Bullshit.PlayerDrewCardNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid - additionalProperties: false - Bullshit.PlayerIsDoneNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid - additionalProperties: false - Bullshit.PlayerPassedNotification: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid - additionalProperties: false - Bullshit.PlayerPutCardNotification: + CrazyEights.PlayerDrewCardNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - claimedToBeCard - playerId type: object properties: playerId: type: string format: uuid - claimedToBeCard: - $ref: '#/components/schemas/Common.Card' additionalProperties: false - Bullshit.PlayerViewOfGame: - required: - - cards - - discardPileCount - - otherPlayers - - stockPileCount - type: object - properties: - cards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - claimedTopOfPile: - $ref: '#/components/schemas/Common.Card' - stockPileCount: - type: integer - format: int32 - discardPileCount: - type: integer - format: int32 - otherPlayers: - type: array - items: - $ref: '#/components/schemas/Bullshit.OtherBullshitPlayer' - additionalProperties: false - Bullshit.PotentialBullshit: - required: - - claimedToBeCard - - playerId - type: object - properties: - playerId: - type: string - format: uuid - claimedToBeCard: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Bullshit.PutCardRequest: + CrazyEights.PlayerIsDoneNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - actualCard - - claimedToBeCard + - playerId type: object properties: - actualCard: - $ref: '#/components/schemas/Common.Card' - claimedToBeCard: - $ref: '#/components/schemas/Common.Card' + playerId: + type: string + format: uuid additionalProperties: false - ChatRoom.ChatNotification: + CrazyEights.PlayerPassedNotification: allOf: - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - message - - sender + - playerId type: object properties: - sender: + playerId: type: string - message: + format: uuid + additionalProperties: false + CrazyEights.PlayerPutCardNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - card + - playerId + type: object + properties: + playerId: type: string + format: uuid + card: + $ref: '#/components/schemas/Common.Card' additionalProperties: false - ChatRoom.ChatResponse: + CrazyEights.PlayerPutEightNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' - - type: object + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - card + - newSuit + - playerId + type: object + properties: + playerId: + type: string + format: uuid + card: + $ref: '#/components/schemas/Common.Card' + newSuit: + $ref: '#/components/schemas/Common.Suit' additionalProperties: false - ChatRoom.ChatRoom: + CrazyEights.PlayerViewOfGame: allOf: - - $ref: '#/components/schemas/Games.GameObject' + - $ref: '#/components/schemas/Protocol.DecksterResponse' - required: - - transcript + - cards + - currentSuit + - discardPileCount + - otherPlayers + - stockPileCount + - topOfPile type: object properties: - transcript: + cards: type: array items: - $ref: '#/components/schemas/ChatRoom.SendChatRequest' + $ref: '#/components/schemas/Common.Card' + topOfPile: + $ref: '#/components/schemas/Common.Card' + currentSuit: + $ref: '#/components/schemas/Common.Suit' + stockPileCount: + type: integer + format: int32 + discardPileCount: + type: integer + format: int32 + otherPlayers: + type: array + items: + $ref: '#/components/schemas/CrazyEights.OtherCrazyEightsPlayer' additionalProperties: false - ChatRoom.SendChatRequest: + CrazyEights.PutCardRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - required: - - message + - card type: object properties: - message: - type: string + card: + $ref: '#/components/schemas/Common.Card' additionalProperties: false - Common.Card: - required: - - rank - - suit - type: object - properties: - rank: - type: integer - format: int32 - suit: - $ref: '#/components/schemas/Common.Suit' - additionalProperties: false - Common.EmptyResponse: + CrazyEights.PutEightRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' - - type: object + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - required: + - card + - newSuit + type: object + properties: + card: + $ref: '#/components/schemas/Common.Card' + newSuit: + $ref: '#/components/schemas/Common.Suit' additionalProperties: false - Common.PlayerData: + Data.DatabaseObject: required: - - cardsInHand - id - - info - - name - - points + - type type: object properties: - name: + type: type: string - points: - type: number - format: double - cardsInHand: - type: integer - format: int32 + readOnly: true id: type: string format: uuid - info: - type: object - additionalProperties: - type: string additionalProperties: false - Common.Suit: - enum: - - Clubs - - Diamonds - - Hearts - - Spades - type: string - Controllers.GameOverviewVm: - required: - - games - - gameType + discriminator: + propertyName: type + mapping: + Games.GameObject: '#/components/schemas/Games.GameObject' + Yaniv.YanivGame: '#/components/schemas/Yaniv.YanivGame' + Uno.UnoGame: '#/components/schemas/Uno.UnoGame' + TexasHoldEm.TexasHoldEmGame: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + Idiot.IdiotGame: '#/components/schemas/Idiot.IdiotGame' + Hearts.HeartsGame: '#/components/schemas/Hearts.HeartsGame' + Gabong.GabongGame: '#/components/schemas/Gabong.GabongGame' + CrazyEights.CrazyEightsGame: '#/components/schemas/CrazyEights.CrazyEightsGame' + ChatRoom.ChatRoom: '#/components/schemas/ChatRoom.ChatRoom' + Bullshit.BullshitGame: '#/components/schemas/Bullshit.BullshitGame' + Data.HistoricBullshitGame: type: object properties: - gameType: - type: string - games: - type: array - items: - $ref: '#/components/schemas/Controllers.GameVm' + game: + $ref: '#/components/schemas/Bullshit.BullshitGame' additionalProperties: false - Controllers.GameVm: - required: - - gameType - - name - - players - - state + Data.HistoricChatRoom: type: object properties: - gameType: - type: string - name: - type: string - state: - $ref: '#/components/schemas/Games.GameState' - players: - type: array - items: - $ref: '#/components/schemas/Common.PlayerData' + game: + $ref: '#/components/schemas/ChatRoom.ChatRoom' additionalProperties: false - Controllers.LoginModel: + Data.HistoricCrazyEightsGame: type: object properties: - username: - type: string - nullable: true - password: - type: string - nullable: true + game: + $ref: '#/components/schemas/CrazyEights.CrazyEightsGame' additionalProperties: false - Controllers.ResponseMessage: + Data.HistoricGabongGame: type: object properties: - message: - type: string - nullable: true + game: + $ref: '#/components/schemas/Gabong.GabongGame' additionalProperties: false - Core.GameInfo: - required: - - id + Data.HistoricHeartsGame: type: object properties: - id: - type: string + game: + $ref: '#/components/schemas/Hearts.HeartsGame' additionalProperties: false - CrazyEights.CardResponse: + Data.HistoricIdiotGame: + type: object + properties: + game: + $ref: '#/components/schemas/Idiot.IdiotGame' + additionalProperties: false + Data.HistoricTexasHoldEmGame: + type: object + properties: + game: + $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + additionalProperties: false + Data.HistoricUnoGame: + type: object + properties: + game: + $ref: '#/components/schemas/Uno.UnoGame' + additionalProperties: false + Data.HistoricYanivGame: + type: object + properties: + game: + $ref: '#/components/schemas/Yaniv.YanivGame' + additionalProperties: false + Gabong.ActionResponse: allOf: - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + additionalProperties: false + Gabong.DrawCardRequest: + allOf: + - $ref: '#/components/schemas/Gabong.GabongRequest' + - type: object + additionalProperties: false + Gabong.GabongCardResponse: + allOf: + - $ref: '#/components/schemas/Gabong.GabongResponse' - required: - card type: object @@ -3623,37 +4401,42 @@ components: card: $ref: '#/components/schemas/Common.Card' additionalProperties: false - CrazyEights.CrazyEightsGame: + Gabong.GabongGame: allOf: - $ref: '#/components/schemas/Games.GameObject' - required: - cardsDrawn + - cardsToDraw - currentPlayer - - currentPlayerIndex - currentSuit - deck - discardPile - - donePlayers - - initialCardsPerPlayer + - gabongMasterId + - gameDirection + - isBetweenRounds + - lastPlayMadeByPlayerIndex - players - - spectators - stockPile - topOfPile type: object properties: - initialCardsPerPlayer: + lastPlayMadeByPlayerIndex: type: integer format: int32 - currentPlayerIndex: + cardsToDraw: type: integer format: int32 cardsDrawn: type: integer format: int32 - donePlayers: - type: array - items: - $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + gameDirection: + type: integer + format: int32 + gabongMasterId: + type: string + format: uuid + isBetweenRounds: + type: boolean deck: type: array items: @@ -3669,11 +4452,7 @@ components: players: type: array items: - $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' - spectators: - type: array - items: - $ref: '#/components/schemas/CrazyEights.CrazyEightsSpectator' + $ref: '#/components/schemas/Gabong.GabongPlayer' newSuit: $ref: '#/components/schemas/Common.Suit' topOfPile: @@ -3681,13 +4460,47 @@ components: currentSuit: $ref: '#/components/schemas/Common.Suit' currentPlayer: - $ref: '#/components/schemas/CrazyEights.CrazyEightsPlayer' + $ref: '#/components/schemas/Gabong.GabongPlayer' additionalProperties: false - CrazyEights.CrazyEightsPlayer: + Gabong.GabongGameNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - type: object + additionalProperties: false + discriminator: + propertyName: type + mapping: + Gabong.GabongPlayerNotification: '#/components/schemas/Gabong.GabongPlayerNotification' + Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' + Gabong.PlayerDrewCardNotification: '#/components/schemas/Gabong.PlayerDrewCardNotification' + Gabong.PlayerDrewPenaltyCardNotification: '#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification' + Gabong.GameStartedNotification: '#/components/schemas/Gabong.GameStartedNotification' + Gabong.GameEndedNotification: '#/components/schemas/Gabong.GameEndedNotification' + Gabong.RoundStartedNotification: '#/components/schemas/Gabong.RoundStartedNotification' + Gabong.RoundEndedNotification: '#/components/schemas/Gabong.RoundEndedNotification' + Gabong.PlayerLostTheirTurnNotification: '#/components/schemas/Gabong.PlayerLostTheirTurnNotification' + Gabong.GabongPlay: + enum: + - CardPlayed + - TurnLost + - RoundStarted + type: string + Gabong.GabongPlayer: required: + - bongas - cards + - cardsPlayed + - debtDrawn + - gabongs + - hasWon - id - name + - passes + - penalties + - roundsWon + - score + - shots + - turnsLost type: object properties: id: @@ -3699,35 +4512,93 @@ components: type: array items: $ref: '#/components/schemas/Common.Card' + readOnly: true + score: + type: integer + format: int32 + hasWon: + type: boolean + readOnly: true + penalties: + type: integer + format: int32 + gabongs: + type: integer + format: int32 + bongas: + type: integer + format: int32 + shots: + type: integer + format: int32 + cardsPlayed: + type: integer + format: int32 + debtDrawn: + type: integer + format: int32 + passes: + type: integer + format: int32 + turnsLost: + type: integer + format: int32 + roundsWon: + type: integer + format: int32 additionalProperties: false - CrazyEights.CrazyEightsSpectator: - required: - - id - - name - type: object - properties: - id: - type: string - format: uuid - name: - type: string - additionalProperties: false - CrazyEights.DiscardPileShuffledNotification: + Gabong.GabongPlayerNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - type: object + - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - required: + - playerId + type: object + properties: + playerId: + type: string + format: uuid additionalProperties: false - CrazyEights.DrawCardRequest: + discriminator: + propertyName: type + mapping: + Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' + Gabong.PlayerDrewCardNotification: '#/components/schemas/Gabong.PlayerDrewCardNotification' + Gabong.PlayerDrewPenaltyCardNotification: '#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification' + Gabong.PlayerLostTheirTurnNotification: '#/components/schemas/Gabong.PlayerLostTheirTurnNotification' + Gabong.GabongRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - type: object additionalProperties: false - CrazyEights.GameEndedNotification: + discriminator: + propertyName: type + mapping: + Gabong.PutCardRequest: '#/components/schemas/Gabong.PutCardRequest' + Gabong.DrawCardRequest: '#/components/schemas/Gabong.DrawCardRequest' + Gabong.PassRequest: '#/components/schemas/Gabong.PassRequest' + Gabong.PlayGabongRequest: '#/components/schemas/Gabong.PlayGabongRequest' + Gabong.PlayBongaRequest: '#/components/schemas/Gabong.PlayBongaRequest' + Gabong.GabongResponse: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - required: + - cardsAdded + type: object + properties: + cardsAdded: + type: array + items: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + discriminator: + propertyName: type + mapping: + Gabong.GabongCardResponse: '#/components/schemas/Gabong.GabongCardResponse' + Gabong.PlayerViewOfGame: '#/components/schemas/Gabong.PlayerViewOfGame' + Gabong.GameEndedNotification: + allOf: + - $ref: '#/components/schemas/Gabong.GabongGameNotification' - required: - - loserId - - loserName - players type: object properties: @@ -3735,140 +4606,110 @@ components: type: array items: $ref: '#/components/schemas/Common.PlayerData' - loserId: - type: string - format: uuid - loserName: - type: string additionalProperties: false - CrazyEights.GameStartedNotification: + Gabong.GameStartedNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Gabong.GabongGameNotification' - required: - gameId - - playerViewOfGame type: object properties: gameId: type: string format: uuid - playerViewOfGame: - $ref: '#/components/schemas/CrazyEights.PlayerViewOfGame' additionalProperties: false - CrazyEights.ItsPlayersTurnNotification: + Gabong.PassRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid + - $ref: '#/components/schemas/Gabong.GabongRequest' + - type: object additionalProperties: false - CrazyEights.ItsYourTurnNotification: + Gabong.PenalizePlayerForTakingTooLongRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerViewOfGame - type: object - properties: - playerViewOfGame: - $ref: '#/components/schemas/CrazyEights.PlayerViewOfGame' + - $ref: '#/components/schemas/Protocol.DecksterRequest' + - type: object additionalProperties: false - CrazyEights.OtherCrazyEightsPlayer: - required: - - name - - numberOfCards - - playerId - type: object - properties: - playerId: - type: string - format: uuid - name: - type: string - numberOfCards: - type: integer - format: int32 - additionalProperties: false - CrazyEights.PassRequest: + Gabong.PenalizePlayerForTooManyCardsRequest: allOf: - $ref: '#/components/schemas/Protocol.DecksterRequest' - type: object additionalProperties: false - CrazyEights.PlayerDrewCardNotification: + Gabong.PenaltyReason: + enum: + - PlayOutOfTurn + - TookTooLong + - WrongPlay + - WrongGabong + - WrongBonga + - UnpaidDebt + - PassWithoutDrawing + type: string + Gabong.PlayBongaRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid + - $ref: '#/components/schemas/Gabong.GabongRequest' + - type: object additionalProperties: false - CrazyEights.PlayerIsDoneNotification: + Gabong.PlayGabongRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - required: - - playerId - type: object - properties: - playerId: - type: string - format: uuid + - $ref: '#/components/schemas/Gabong.GabongRequest' + - type: object additionalProperties: false - CrazyEights.PlayerPassedNotification: + Gabong.PlayerDrewCardNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - type: object + additionalProperties: false + Gabong.PlayerDrewPenaltyCardNotification: + allOf: + - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' - required: - - playerId + - penaltyReason type: object properties: - playerId: - type: string - format: uuid + penaltyReason: + $ref: '#/components/schemas/Gabong.PenaltyReason' additionalProperties: false - CrazyEights.PlayerPutCardNotification: + Gabong.PlayerLostTheirTurnNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' - required: - - card - - playerId + - lostTurnReason type: object properties: - playerId: - type: string - format: uuid - card: - $ref: '#/components/schemas/Common.Card' + lostTurnReason: + $ref: '#/components/schemas/Gabong.PlayerLostTurnReason' additionalProperties: false - CrazyEights.PlayerPutEightNotification: + Gabong.PlayerLostTurnReason: + enum: + - Passed + - WrongPlay + - TookTooLong + - FinishedDrawingCardDebt + type: string + Gabong.PlayerPutCardNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' + - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' - required: - card - - newSuit - - playerId type: object properties: - playerId: - type: string - format: uuid card: $ref: '#/components/schemas/Common.Card' newSuit: $ref: '#/components/schemas/Common.Suit' additionalProperties: false - CrazyEights.PlayerViewOfGame: + Gabong.PlayerViewOfGame: allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' + - $ref: '#/components/schemas/Gabong.GabongResponse' - required: + - cardDebtToDraw - cards - currentSuit - discardPileCount - - otherPlayers + - lastPlay + - lastPlayMadeByPlayerId + - players + - playersOrder + - roundStarted - stockPileCount - topOfPile type: object @@ -3887,27 +4728,31 @@ components: discardPileCount: type: integer format: int32 - otherPlayers: + roundStarted: + type: boolean + lastPlayMadeByPlayerId: + type: string + format: uuid + lastPlay: + $ref: '#/components/schemas/Gabong.GabongPlay' + players: type: array items: - $ref: '#/components/schemas/CrazyEights.OtherCrazyEightsPlayer' - additionalProperties: false - CrazyEights.PutCardRequest: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' - - required: - - card - type: object - properties: - card: - $ref: '#/components/schemas/Common.Card' + $ref: '#/components/schemas/Gabong.SlimGabongPlayer' + playersOrder: + type: array + items: + type: string + format: uuid + cardDebtToDraw: + type: integer + format: int32 additionalProperties: false - CrazyEights.PutEightRequest: + Gabong.PutCardRequest: allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' + - $ref: '#/components/schemas/Gabong.GabongRequest' - required: - card - - newSuit type: object properties: card: @@ -3915,199 +4760,37 @@ components: newSuit: $ref: '#/components/schemas/Common.Suit' additionalProperties: false - Data.DatabaseObject: - required: - - id - - type - type: object - properties: - type: - type: string - readOnly: true - id: - type: string - format: uuid - additionalProperties: false - discriminator: - propertyName: type - mapping: - Games.GameObject: '#/components/schemas/Games.GameObject' - Yaniv.YanivGame: '#/components/schemas/Yaniv.YanivGame' - Uno.UnoGame: '#/components/schemas/Uno.UnoGame' - TexasHoldEm.TexasHoldEmGame: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' - Idiot.IdiotGame: '#/components/schemas/Idiot.IdiotGame' - Gabong.GabongGame: '#/components/schemas/Gabong.GabongGame' - CrazyEights.CrazyEightsGame: '#/components/schemas/CrazyEights.CrazyEightsGame' - ChatRoom.ChatRoom: '#/components/schemas/ChatRoom.ChatRoom' - Bullshit.BullshitGame: '#/components/schemas/Bullshit.BullshitGame' - Data.HistoricBullshitGame: - type: object - properties: - game: - $ref: '#/components/schemas/Bullshit.BullshitGame' - additionalProperties: false - Data.HistoricChatRoom: - type: object - properties: - game: - $ref: '#/components/schemas/ChatRoom.ChatRoom' - additionalProperties: false - Data.HistoricCrazyEightsGame: - type: object - properties: - game: - $ref: '#/components/schemas/CrazyEights.CrazyEightsGame' - additionalProperties: false - Data.HistoricGabongGame: - type: object - properties: - game: - $ref: '#/components/schemas/Gabong.GabongGame' - additionalProperties: false - Data.HistoricIdiotGame: - type: object - properties: - game: - $ref: '#/components/schemas/Idiot.IdiotGame' - additionalProperties: false - Data.HistoricTexasHoldEmGame: - type: object - properties: - game: - $ref: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' - additionalProperties: false - Data.HistoricUnoGame: - type: object - properties: - game: - $ref: '#/components/schemas/Uno.UnoGame' - additionalProperties: false - Data.HistoricYanivGame: - type: object - properties: - game: - $ref: '#/components/schemas/Yaniv.YanivGame' - additionalProperties: false - Gabong.ActionResponse: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' - - type: object - additionalProperties: false - Gabong.DrawCardRequest: - allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' - - type: object - additionalProperties: false - Gabong.GabongCardResponse: - allOf: - - $ref: '#/components/schemas/Gabong.GabongResponse' - - required: - - card - type: object - properties: - card: - $ref: '#/components/schemas/Common.Card' - additionalProperties: false - Gabong.GabongGame: + Gabong.RoundEndedNotification: allOf: - - $ref: '#/components/schemas/Games.GameObject' + - $ref: '#/components/schemas/Gabong.GabongGameNotification' - required: - - cardsDrawn - - cardsToDraw - - currentPlayer - - currentSuit - - deck - - discardPile - - gabongMasterId - - gameDirection - - isBetweenRounds - - lastPlayMadeByPlayerIndex - players - - stockPile - - topOfPile type: object properties: - lastPlayMadeByPlayerIndex: - type: integer - format: int32 - cardsToDraw: - type: integer - format: int32 - cardsDrawn: - type: integer - format: int32 - gameDirection: - type: integer - format: int32 - gabongMasterId: - type: string - format: uuid - isBetweenRounds: - type: boolean - deck: - type: array - items: - $ref: '#/components/schemas/Common.Card' - stockPile: - type: array - items: - $ref: '#/components/schemas/Common.Card' - discardPile: - type: array - items: - $ref: '#/components/schemas/Common.Card' players: type: array items: - $ref: '#/components/schemas/Gabong.GabongPlayer' - newSuit: - $ref: '#/components/schemas/Common.Suit' - topOfPile: - $ref: '#/components/schemas/Common.Card' - currentSuit: - $ref: '#/components/schemas/Common.Suit' - currentPlayer: - $ref: '#/components/schemas/Gabong.GabongPlayer' + $ref: '#/components/schemas/Common.PlayerData' additionalProperties: false - Gabong.GabongGameNotification: + Gabong.RoundStartedNotification: allOf: - - $ref: '#/components/schemas/Protocol.DecksterNotification' - - type: object - additionalProperties: false - discriminator: - propertyName: type - mapping: - Gabong.GabongPlayerNotification: '#/components/schemas/Gabong.GabongPlayerNotification' - Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' - Gabong.PlayerDrewCardNotification: '#/components/schemas/Gabong.PlayerDrewCardNotification' - Gabong.PlayerDrewPenaltyCardNotification: '#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification' - Gabong.GameStartedNotification: '#/components/schemas/Gabong.GameStartedNotification' - Gabong.GameEndedNotification: '#/components/schemas/Gabong.GameEndedNotification' - Gabong.RoundStartedNotification: '#/components/schemas/Gabong.RoundStartedNotification' - Gabong.RoundEndedNotification: '#/components/schemas/Gabong.RoundEndedNotification' - Gabong.PlayerLostTheirTurnNotification: '#/components/schemas/Gabong.PlayerLostTheirTurnNotification' - Gabong.GabongPlay: - enum: - - CardPlayed - - TurnLost - - RoundStarted - type: string - Gabong.GabongPlayer: + - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - required: + - playerViewOfGame + - startingPlayerId + type: object + properties: + playerViewOfGame: + $ref: '#/components/schemas/Gabong.PlayerViewOfGame' + startingPlayerId: + type: string + format: uuid + additionalProperties: false + Gabong.SlimGabongPlayer: required: - - bongas - - cards - - cardsPlayed - - debtDrawn - - gabongs - - hasWon - id - name - - passes - - penalties - - roundsWon - - score - - shots - - turnsLost + - numberOfCards type: object properties: id: @@ -4115,382 +4798,475 @@ components: format: uuid name: type: string - cards: - type: array - items: - $ref: '#/components/schemas/Common.Card' - readOnly: true - score: - type: integer - format: int32 - hasWon: - type: boolean - readOnly: true - penalties: - type: integer - format: int32 - gabongs: - type: integer - format: int32 - bongas: - type: integer - format: int32 - shots: - type: integer - format: int32 - cardsPlayed: - type: integer - format: int32 - debtDrawn: - type: integer - format: int32 - passes: - type: integer - format: int32 - turnsLost: - type: integer - format: int32 - roundsWon: + numberOfCards: type: integer format: int32 additionalProperties: false - Gabong.GabongPlayerNotification: + Games.GameObject: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Data.DatabaseObject' - required: - - playerId + - name + - seed + - startedTime + - state + - version type: object properties: - playerId: + name: type: string - format: uuid + startedTime: + type: string + format: date-time + state: + $ref: '#/components/schemas/Games.GameState' + version: + type: integer + format: int32 + seed: + type: integer + format: int32 additionalProperties: false discriminator: propertyName: type mapping: - Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' - Gabong.PlayerDrewCardNotification: '#/components/schemas/Gabong.PlayerDrewCardNotification' - Gabong.PlayerDrewPenaltyCardNotification: '#/components/schemas/Gabong.PlayerDrewPenaltyCardNotification' - Gabong.PlayerLostTheirTurnNotification: '#/components/schemas/Gabong.PlayerLostTheirTurnNotification' - Gabong.GabongRequest: + Yaniv.YanivGame: '#/components/schemas/Yaniv.YanivGame' + Uno.UnoGame: '#/components/schemas/Uno.UnoGame' + TexasHoldEm.TexasHoldEmGame: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' + Idiot.IdiotGame: '#/components/schemas/Idiot.IdiotGame' + Hearts.HeartsGame: '#/components/schemas/Hearts.HeartsGame' + Gabong.GabongGame: '#/components/schemas/Gabong.GabongGame' + CrazyEights.CrazyEightsGame: '#/components/schemas/CrazyEights.CrazyEightsGame' + ChatRoom.ChatRoom: '#/components/schemas/ChatRoom.ChatRoom' + Bullshit.BullshitGame: '#/components/schemas/Bullshit.BullshitGame' + Games.GameState: + enum: + - Waiting + - Running + - Finished + - RoundFinished + type: string + Handshake.ConnectFailureMessage: allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' + - $ref: '#/components/schemas/Handshake.ConnectMessage' + - required: + - errorMessage + type: object + properties: + errorMessage: + type: string + additionalProperties: false + Handshake.ConnectMessage: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterMessage' - type: object additionalProperties: false discriminator: propertyName: type mapping: - Gabong.PutCardRequest: '#/components/schemas/Gabong.PutCardRequest' - Gabong.DrawCardRequest: '#/components/schemas/Gabong.DrawCardRequest' - Gabong.PassRequest: '#/components/schemas/Gabong.PassRequest' - Gabong.PlayGabongRequest: '#/components/schemas/Gabong.PlayGabongRequest' - Gabong.PlayBongaRequest: '#/components/schemas/Gabong.PlayBongaRequest' - Gabong.GabongResponse: + Handshake.HelloSuccessMessage: '#/components/schemas/Handshake.HelloSuccessMessage' + Handshake.ConnectSuccessMessage: '#/components/schemas/Handshake.ConnectSuccessMessage' + Handshake.ConnectFailureMessage: '#/components/schemas/Handshake.ConnectFailureMessage' + Handshake.ConnectSuccessMessage: allOf: - - $ref: '#/components/schemas/Protocol.DecksterResponse' + - $ref: '#/components/schemas/Handshake.ConnectMessage' + - type: object + additionalProperties: false + Handshake.HelloSuccessMessage: + allOf: + - $ref: '#/components/schemas/Handshake.ConnectMessage' - required: - - cardsAdded + - connectionId + - player type: object properties: - cardsAdded: + player: + $ref: '#/components/schemas/Common.PlayerData' + connectionId: + type: string + format: uuid + additionalProperties: false + Hearts.AllPlayersPassedNotification: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - receivedCards + type: object + properties: + receivedCards: type: array items: $ref: '#/components/schemas/Common.Card' additionalProperties: false - discriminator: - propertyName: type - mapping: - Gabong.GabongCardResponse: '#/components/schemas/Gabong.GabongCardResponse' - Gabong.PlayerViewOfGame: '#/components/schemas/Gabong.PlayerViewOfGame' - Gabong.GameEndedNotification: + Hearts.CardPlay: + required: + - card + - playerId + - playerName + type: object + properties: + playerId: + type: string + format: uuid + playerName: + type: string + card: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Hearts.GameEndedNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - players + - finalScores + - winnerId + - winnerName type: object properties: - players: + finalScores: type: array items: - $ref: '#/components/schemas/Common.PlayerData' + $ref: '#/components/schemas/Hearts.PlayerScore' + winnerId: + type: string + format: uuid + winnerName: + type: string additionalProperties: false - Gabong.GameStartedNotification: + Hearts.GamePhase: + enum: + - Passing + - Playing + type: string + Hearts.GameStartedNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - gameId + - playerViewOfGame type: object properties: gameId: type: string format: uuid + playerViewOfGame: + $ref: '#/components/schemas/Hearts.PlayerViewOfGame' additionalProperties: false - Gabong.PassRequest: - allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' - - type: object - additionalProperties: false - Gabong.PenalizePlayerForTakingTooLongRequest: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' - - type: object - additionalProperties: false - Gabong.PenalizePlayerForTooManyCardsRequest: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterRequest' - - type: object - additionalProperties: false - Gabong.PenaltyReason: - enum: - - PlayOutOfTurn - - TookTooLong - - WrongPlay - - WrongGabong - - WrongBonga - - UnpaidDebt - - PassWithoutDrawing - type: string - Gabong.PlayBongaRequest: - allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' - - type: object - additionalProperties: false - Gabong.PlayGabongRequest: - allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' - - type: object - additionalProperties: false - Gabong.PlayerDrewCardNotification: + Hearts.HeartsAreBrokenNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - type: object additionalProperties: false - Gabong.PlayerDrewPenaltyCardNotification: + Hearts.HeartsGame: allOf: - - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - $ref: '#/components/schemas/Games.GameObject' - required: - - penaltyReason + - currentPassDirection + - currentPlayer + - currentPlayerIndex + - currentTrick + - deck + - heartsAreBroken + - isFirstTrick + - phase + - players + - roundNumber type: object properties: - penaltyReason: - $ref: '#/components/schemas/Gabong.PenaltyReason' + deck: + type: array + items: + $ref: '#/components/schemas/Common.Card' + players: + type: array + items: + $ref: '#/components/schemas/Hearts.HeartsPlayer' + currentPlayerIndex: + type: integer + format: int32 + roundNumber: + type: integer + format: int32 + heartsAreBroken: + type: boolean + currentTrick: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + leadSuit: + $ref: '#/components/schemas/Common.Suit' + isFirstTrick: + type: boolean + phase: + $ref: '#/components/schemas/Hearts.GamePhase' + currentPlayer: + $ref: '#/components/schemas/Hearts.HeartsPlayer' + currentPassDirection: + $ref: '#/components/schemas/Hearts.PassDirection' additionalProperties: false - Gabong.PlayerLostTheirTurnNotification: + Hearts.HeartsPlayer: + required: + - cards + - cardsToPass + - hasPassed + - id + - name + - roundScore + - totalScore + type: object + properties: + id: + type: string + format: uuid + name: + type: string + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + cardsToPass: + type: array + items: + $ref: '#/components/schemas/Common.Card' + hasPassed: + type: boolean + roundScore: + type: integer + format: int32 + totalScore: + type: integer + format: int32 + playedCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Hearts.ItsPlayersTurnNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - lostTurnReason + - playerId type: object properties: - lostTurnReason: - $ref: '#/components/schemas/Gabong.PlayerLostTurnReason' + playerId: + type: string + format: uuid additionalProperties: false - Gabong.PlayerLostTurnReason: - enum: - - Passed - - WrongPlay - - TookTooLong - - FinishedDrawingCardDebt - type: string - Gabong.PlayerPutCardNotification: + Hearts.ItsYourTurnNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongPlayerNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - card + - playerViewOfGame type: object properties: - card: - $ref: '#/components/schemas/Common.Card' - newSuit: - $ref: '#/components/schemas/Common.Suit' + playerViewOfGame: + $ref: '#/components/schemas/Hearts.PlayerViewOfGame' additionalProperties: false - Gabong.PlayerViewOfGame: + Hearts.OtherHeartsPlayer: + required: + - name + - numberOfCards + - playerId + - roundScore + - totalScore + type: object + properties: + playerId: + type: string + format: uuid + name: + type: string + numberOfCards: + type: integer + format: int32 + totalScore: + type: integer + format: int32 + roundScore: + type: integer + format: int32 + playedCard: + $ref: '#/components/schemas/Common.Card' + additionalProperties: false + Hearts.PassCardsRequest: allOf: - - $ref: '#/components/schemas/Gabong.GabongResponse' + - $ref: '#/components/schemas/Protocol.DecksterRequest' - required: - - cardDebtToDraw - cards - - currentSuit - - discardPileCount - - lastPlay - - lastPlayMadeByPlayerId - - players - - playersOrder - - roundStarted - - stockPileCount - - topOfPile type: object properties: cards: type: array items: $ref: '#/components/schemas/Common.Card' - topOfPile: - $ref: '#/components/schemas/Common.Card' - currentSuit: - $ref: '#/components/schemas/Common.Suit' - stockPileCount: - type: integer - format: int32 - discardPileCount: - type: integer - format: int32 - roundStarted: - type: boolean - lastPlayMadeByPlayerId: - type: string - format: uuid - lastPlay: - $ref: '#/components/schemas/Gabong.GabongPlay' - players: - type: array - items: - $ref: '#/components/schemas/Gabong.SlimGabongPlayer' - playersOrder: + additionalProperties: false + Hearts.PassCardsResponse: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterResponse' + - type: object + properties: + receivedCards: type: array items: - type: string - format: uuid - cardDebtToDraw: - type: integer - format: int32 + $ref: '#/components/schemas/Common.Card' + nullable: true additionalProperties: false - Gabong.PutCardRequest: + Hearts.PassDirection: + enum: + - None + - Left + - Right + - Across + type: string + Hearts.PassingPhaseStartedNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongRequest' + - $ref: '#/components/schemas/Protocol.DecksterNotification' + - required: + - passDirection + type: object + properties: + passDirection: + $ref: '#/components/schemas/Hearts.PassDirection' + additionalProperties: false + Hearts.PlayCardRequest: + allOf: + - $ref: '#/components/schemas/Protocol.DecksterRequest' - required: - card type: object properties: card: $ref: '#/components/schemas/Common.Card' - newSuit: - $ref: '#/components/schemas/Common.Suit' additionalProperties: false - Gabong.RoundEndedNotification: + Hearts.PlayerPassedCardsNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - players + - playerId type: object properties: - players: - type: array - items: - $ref: '#/components/schemas/Common.PlayerData' + playerId: + type: string + format: uuid additionalProperties: false - Gabong.RoundStartedNotification: + Hearts.PlayerPlayedCardNotification: allOf: - - $ref: '#/components/schemas/Gabong.GabongGameNotification' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - playerViewOfGame - - startingPlayerId + - card + - playerId type: object properties: - playerViewOfGame: - $ref: '#/components/schemas/Gabong.PlayerViewOfGame' - startingPlayerId: + playerId: type: string format: uuid + card: + $ref: '#/components/schemas/Common.Card' additionalProperties: false - Gabong.SlimGabongPlayer: + Hearts.PlayerScore: required: - - id - - name - - numberOfCards + - playerId + - playerName + - roundScore + - totalScore type: object properties: - id: + playerId: type: string format: uuid - name: + playerName: type: string - numberOfCards: + roundScore: + type: integer + format: int32 + totalScore: type: integer format: int32 additionalProperties: false - Games.GameObject: + Hearts.PlayerViewOfGame: allOf: - - $ref: '#/components/schemas/Data.DatabaseObject' + - $ref: '#/components/schemas/Protocol.DecksterResponse' - required: - - name - - seed - - startedTime - - state - - version + - cards + - currentTrick + - hasPassed + - heartsAreBroken + - isMyTurn + - otherPlayers + - passDirection + - roundNumber + - roundScore + - totalScore type: object properties: - name: - type: string - startedTime: - type: string - format: date-time - state: - $ref: '#/components/schemas/Games.GameState' - version: + cards: + type: array + items: + $ref: '#/components/schemas/Common.Card' + otherPlayers: + type: array + items: + $ref: '#/components/schemas/Hearts.OtherHeartsPlayer' + roundNumber: type: integer format: int32 - seed: + passDirection: + $ref: '#/components/schemas/Hearts.PassDirection' + hasPassed: + type: boolean + currentTrick: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + totalScore: type: integer format: int32 + roundScore: + type: integer + format: int32 + heartsAreBroken: + type: boolean + isMyTurn: + type: boolean additionalProperties: false - discriminator: - propertyName: type - mapping: - Yaniv.YanivGame: '#/components/schemas/Yaniv.YanivGame' - Uno.UnoGame: '#/components/schemas/Uno.UnoGame' - TexasHoldEm.TexasHoldEmGame: '#/components/schemas/TexasHoldEm.TexasHoldEmGame' - Idiot.IdiotGame: '#/components/schemas/Idiot.IdiotGame' - Gabong.GabongGame: '#/components/schemas/Gabong.GabongGame' - CrazyEights.CrazyEightsGame: '#/components/schemas/CrazyEights.CrazyEightsGame' - ChatRoom.ChatRoom: '#/components/schemas/ChatRoom.ChatRoom' - Bullshit.BullshitGame: '#/components/schemas/Bullshit.BullshitGame' - Games.GameState: - enum: - - Waiting - - Running - - Finished - - RoundFinished - type: string - Handshake.ConnectFailureMessage: + Hearts.RoundEndedNotification: allOf: - - $ref: '#/components/schemas/Handshake.ConnectMessage' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - errorMessage + - scores type: object properties: - errorMessage: + scores: + type: array + items: + $ref: '#/components/schemas/Hearts.PlayerScore' + moonShooterId: type: string + format: uuid + nullable: true + moonShooterName: + type: string + nullable: true additionalProperties: false - Handshake.ConnectMessage: - allOf: - - $ref: '#/components/schemas/Protocol.DecksterMessage' - - type: object - additionalProperties: false - discriminator: - propertyName: type - mapping: - Handshake.HelloSuccessMessage: '#/components/schemas/Handshake.HelloSuccessMessage' - Handshake.ConnectSuccessMessage: '#/components/schemas/Handshake.ConnectSuccessMessage' - Handshake.ConnectFailureMessage: '#/components/schemas/Handshake.ConnectFailureMessage' - Handshake.ConnectSuccessMessage: - allOf: - - $ref: '#/components/schemas/Handshake.ConnectMessage' - - type: object - additionalProperties: false - Handshake.HelloSuccessMessage: + Hearts.TrickCompletedNotification: allOf: - - $ref: '#/components/schemas/Handshake.ConnectMessage' + - $ref: '#/components/schemas/Protocol.DecksterNotification' - required: - - connectionId - - player + - points + - trickCards + - winnerId + - winnerName type: object properties: - player: - $ref: '#/components/schemas/Common.PlayerData' - connectionId: + winnerId: type: string format: uuid + winnerName: + type: string + trickCards: + type: array + items: + $ref: '#/components/schemas/Hearts.CardPlay' + points: + type: integer + format: int32 additionalProperties: false Idiot.DiscardPileFlushedNotification: allOf: @@ -5047,6 +5823,21 @@ components: Idiot.GameStartedNotification: '#/components/schemas/Idiot.GameStartedNotification' Idiot.GameEndedNotification: '#/components/schemas/Idiot.GameEndedNotification' Idiot.ItsTimeToSwapCardsNotification: '#/components/schemas/Idiot.ItsTimeToSwapCardsNotification' + Hearts.PassCardsRequest: '#/components/schemas/Hearts.PassCardsRequest' + Hearts.PlayCardRequest: '#/components/schemas/Hearts.PlayCardRequest' + Hearts.PassCardsResponse: '#/components/schemas/Hearts.PassCardsResponse' + Hearts.GameStartedNotification: '#/components/schemas/Hearts.GameStartedNotification' + Hearts.PassingPhaseStartedNotification: '#/components/schemas/Hearts.PassingPhaseStartedNotification' + Hearts.AllPlayersPassedNotification: '#/components/schemas/Hearts.AllPlayersPassedNotification' + Hearts.PlayerPassedCardsNotification: '#/components/schemas/Hearts.PlayerPassedCardsNotification' + Hearts.ItsYourTurnNotification: '#/components/schemas/Hearts.ItsYourTurnNotification' + Hearts.ItsPlayersTurnNotification: '#/components/schemas/Hearts.ItsPlayersTurnNotification' + Hearts.PlayerPlayedCardNotification: '#/components/schemas/Hearts.PlayerPlayedCardNotification' + Hearts.TrickCompletedNotification: '#/components/schemas/Hearts.TrickCompletedNotification' + Hearts.RoundEndedNotification: '#/components/schemas/Hearts.RoundEndedNotification' + Hearts.GameEndedNotification: '#/components/schemas/Hearts.GameEndedNotification' + Hearts.HeartsAreBrokenNotification: '#/components/schemas/Hearts.HeartsAreBrokenNotification' + Hearts.PlayerViewOfGame: '#/components/schemas/Hearts.PlayerViewOfGame' Gabong.GabongGameNotification: '#/components/schemas/Gabong.GabongGameNotification' Gabong.GabongPlayerNotification: '#/components/schemas/Gabong.GabongPlayerNotification' Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' @@ -5158,6 +5949,17 @@ components: Idiot.GameStartedNotification: '#/components/schemas/Idiot.GameStartedNotification' Idiot.GameEndedNotification: '#/components/schemas/Idiot.GameEndedNotification' Idiot.ItsTimeToSwapCardsNotification: '#/components/schemas/Idiot.ItsTimeToSwapCardsNotification' + Hearts.GameStartedNotification: '#/components/schemas/Hearts.GameStartedNotification' + Hearts.PassingPhaseStartedNotification: '#/components/schemas/Hearts.PassingPhaseStartedNotification' + Hearts.AllPlayersPassedNotification: '#/components/schemas/Hearts.AllPlayersPassedNotification' + Hearts.PlayerPassedCardsNotification: '#/components/schemas/Hearts.PlayerPassedCardsNotification' + Hearts.ItsYourTurnNotification: '#/components/schemas/Hearts.ItsYourTurnNotification' + Hearts.ItsPlayersTurnNotification: '#/components/schemas/Hearts.ItsPlayersTurnNotification' + Hearts.PlayerPlayedCardNotification: '#/components/schemas/Hearts.PlayerPlayedCardNotification' + Hearts.TrickCompletedNotification: '#/components/schemas/Hearts.TrickCompletedNotification' + Hearts.RoundEndedNotification: '#/components/schemas/Hearts.RoundEndedNotification' + Hearts.GameEndedNotification: '#/components/schemas/Hearts.GameEndedNotification' + Hearts.HeartsAreBrokenNotification: '#/components/schemas/Hearts.HeartsAreBrokenNotification' Gabong.GabongGameNotification: '#/components/schemas/Gabong.GabongGameNotification' Gabong.GabongPlayerNotification: '#/components/schemas/Gabong.GabongPlayerNotification' Gabong.PlayerPutCardNotification: '#/components/schemas/Gabong.PlayerPutCardNotification' @@ -5223,6 +6025,8 @@ components: Idiot.DrawCardsRequest: '#/components/schemas/Idiot.DrawCardsRequest' Idiot.PullInDiscardPileRequest: '#/components/schemas/Idiot.PullInDiscardPileRequest' Idiot.PutChanceCardRequest: '#/components/schemas/Idiot.PutChanceCardRequest' + Hearts.PassCardsRequest: '#/components/schemas/Hearts.PassCardsRequest' + Hearts.PlayCardRequest: '#/components/schemas/Hearts.PlayCardRequest' Gabong.PenalizePlayerForTakingTooLongRequest: '#/components/schemas/Gabong.PenalizePlayerForTakingTooLongRequest' Gabong.PenalizePlayerForTooManyCardsRequest: '#/components/schemas/Gabong.PenalizePlayerForTooManyCardsRequest' Gabong.GabongRequest: '#/components/schemas/Gabong.GabongRequest' @@ -5265,6 +6069,8 @@ components: Idiot.PullInResponse: '#/components/schemas/Idiot.PullInResponse' Idiot.DrawCardsResponse: '#/components/schemas/Idiot.DrawCardsResponse' Idiot.PutBlindCardResponse: '#/components/schemas/Idiot.PutBlindCardResponse' + Hearts.PassCardsResponse: '#/components/schemas/Hearts.PassCardsResponse' + Hearts.PlayerViewOfGame: '#/components/schemas/Hearts.PlayerViewOfGame' Gabong.GabongResponse: '#/components/schemas/Gabong.GabongResponse' Gabong.GabongCardResponse: '#/components/schemas/Gabong.GabongCardResponse' Gabong.ActionResponse: '#/components/schemas/Gabong.ActionResponse' diff --git a/src/Deckster.Client/Games/Hearts/HeartsClient.g.cs b/src/Deckster.Client/Games/Hearts/HeartsClient.g.cs new file mode 100644 index 00000000..872fd95a --- /dev/null +++ b/src/Deckster.Client/Games/Hearts/HeartsClient.g.cs @@ -0,0 +1,136 @@ +#nullable enable + +using Deckster.Core.Games.Hearts; +using System.Collections.Generic; +using Deckster.Core.Games.Common; +using System.Diagnostics; +using Deckster.Core.Communication; +using Deckster.Core.Protocol; +using Deckster.Core.Extensions; + +namespace Deckster.Client.Games.Hearts; + +/** + * Autogenerated by really, really eager small hamsters. +*/ + +[DebuggerDisplay("HeartsClient {PlayerData}")] +public class HeartsClient(IClientChannel channel) : GameClient(channel) +{ + public event Action? GameStarted; + public event Action? PassingPhaseStarted; + public event Action? AllPlayersPassed; + public event Action? PlayerPassedCards; + public event Action? ItsYourTurn; + public event Action? ItsPlayersTurn; + public event Action? PlayerPlayedCard; + public event Action? TrickCompleted; + public event Action? RoundEnded; + public event Action? GameEnded; + public event Action? HeartsWereBroken; + + public Task PassCardsAsync(PassCardsRequest request, CancellationToken cancellationToken = default) + { + return SendAsync(request, false, cancellationToken); + } + + public Task PlayCardAsync(PlayCardRequest request, CancellationToken cancellationToken = default) + { + return SendAsync(request, false, cancellationToken); + } + + protected override void OnNotification(DecksterNotification notification) + { + try + { + switch (notification) + { + case GameStartedNotification m: + GameStarted?.Invoke(m); + return; + case PassingPhaseStartedNotification m: + PassingPhaseStarted?.Invoke(m); + return; + case AllPlayersPassedNotification m: + AllPlayersPassed?.Invoke(m); + return; + case PlayerPassedCardsNotification m: + PlayerPassedCards?.Invoke(m); + return; + case ItsYourTurnNotification m: + ItsYourTurn?.Invoke(m); + return; + case ItsPlayersTurnNotification m: + ItsPlayersTurn?.Invoke(m); + return; + case PlayerPlayedCardNotification m: + PlayerPlayedCard?.Invoke(m); + return; + case TrickCompletedNotification m: + TrickCompleted?.Invoke(m); + return; + case RoundEndedNotification m: + RoundEnded?.Invoke(m); + return; + case GameEndedNotification m: + GameEnded?.Invoke(m); + return; + case HeartsAreBrokenNotification m: + HeartsWereBroken?.Invoke(m); + return; + default: + return; + } + } + catch (Exception e) + { + Console.WriteLine(e); + } + } +} + +public static class HeartsClientConveniences +{ + /// + /// does not throw exception on error + /// + public static Task PassCardsAsync(this HeartsClient self, List cards, CancellationToken cancellationToken = default) + { + var request = new PassCardsRequest{ Cards = cards }; + return self.SendAsync(request, false, cancellationToken); + } + /// + /// throws exception on error + /// + public static async Task> PassCardsOrThrowAsync(this HeartsClient self, List cards, CancellationToken cancellationToken = default) + { + var request = new PassCardsRequest{ Cards = cards }; + var response = await self.SendAsync(request, true, cancellationToken); + return response.ReceivedCards; + } + /// + /// does not throw exception on error + /// + public static Task PlayCardAsync(this HeartsClient self, Card card, CancellationToken cancellationToken = default) + { + var request = new PlayCardRequest{ Card = card }; + return self.SendAsync(request, false, cancellationToken); + } + /// + /// throws exception on error + /// + public static async Task<(List cards, List otherPlayers, int roundNumber, PassDirection passDirection, bool hasPassed, List currentTrick, int totalScore, int roundScore, bool heartsAreBroken, bool isMyTurn)> PlayCardOrThrowAsync(this HeartsClient self, Card card, CancellationToken cancellationToken = default) + { + var request = new PlayCardRequest{ Card = card }; + var response = await self.SendAsync(request, true, cancellationToken); + return (response.Cards, response.OtherPlayers, response.RoundNumber, response.PassDirection, response.HasPassed, response.CurrentTrick, response.TotalScore, response.RoundScore, response.HeartsAreBroken, response.IsMyTurn); + } +} + +public static class HeartsClientDecksterClientExtensions +{ + public static GameApi Hearts(this DecksterClient client) + { + return new GameApi(client.BaseUri.Append("hearts"), client.Token, c => new HeartsClient(c)); + } +} diff --git a/src/Deckster.Client/Games/Uno/UnoClient.g.cs b/src/Deckster.Client/Games/Uno/UnoClient.g.cs index f7351dc7..f48f362d 100644 --- a/src/Deckster.Client/Games/Uno/UnoClient.g.cs +++ b/src/Deckster.Client/Games/Uno/UnoClient.g.cs @@ -23,8 +23,6 @@ public class UnoClient(IClientChannel channel) : GameClient(channel) public event Action? PlayerPassed; public event Action? GameEnded; public event Action? ItsYourTurn; - public event Action? RoundStarted; - public event Action? RoundEnded; public Task PutCardAsync(PutCardRequest request, CancellationToken cancellationToken = default) { @@ -73,12 +71,6 @@ protected override void OnNotification(DecksterNotification notification) case ItsYourTurnNotification m: ItsYourTurn?.Invoke(m); return; - case RoundStartedNotification m: - RoundStarted?.Invoke(m); - return; - case RoundEndedNotification m: - RoundEnded?.Invoke(m); - return; default: return; } diff --git a/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs b/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs index d41e1944..a105b9c1 100644 --- a/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs +++ b/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs @@ -141,7 +141,7 @@ public CsharpClientGenerator(CSharpGameMeta meta, string ns) "/// throws exception on error", "/// ", ]); - Source.AppendLine($"public static async Task<{extension.ReturnParameters[0].ParameterType.Name}> {extension.Name}OrThrowAsync(this {ClientName} self, {parameters})"); + Source.AppendLine($"public static async Task<{extension.ReturnParameters[0].ParameterType.ToDisplayString()}> {extension.Name}OrThrowAsync(this {ClientName} self, {parameters})"); break; default: var returnTuple = extension.ReturnParameters.Select(p => $"{p.ParameterType.ToDisplayString()} {p.Name}").StringJoined(", "); diff --git a/src/Deckster.Uno.SampleClient/UnoInteractive.cs b/src/Deckster.Uno.SampleClient/UnoInteractive.cs index ed00bf31..85cd828a 100644 --- a/src/Deckster.Uno.SampleClient/UnoInteractive.cs +++ b/src/Deckster.Uno.SampleClient/UnoInteractive.cs @@ -14,13 +14,13 @@ public UnoInteractive(UnoClient client) { _client = client; client.GameStarted += OnGameStarted; - client.RoundStarted += OnRoundStarted; + // client.RoundStarted += OnRoundStarted; client.ItsYourTurn += OnItsYourTurn; client.PlayerPutCard += OnPlayerPutCard; client.PlayerPutWild += OnPlayerPutWild; client.PlayerDrewCard += OnPlayerDrewCard; client.PlayerPassed += OnPlayerPassed; - client.RoundEnded += OnRoundEnded; + // client.RoundEnded += OnRoundEnded; client.GameEnded += OnGameEnded; } diff --git a/src/Deckster.Uno.SampleClient/UnoPoorAi.cs b/src/Deckster.Uno.SampleClient/UnoPoorAi.cs index b5fa45b7..b36fd938 100644 --- a/src/Deckster.Uno.SampleClient/UnoPoorAi.cs +++ b/src/Deckster.Uno.SampleClient/UnoPoorAi.cs @@ -20,13 +20,13 @@ public UnoPoorAi(UnoClient client) _client = client; _logger = Log.Factory.CreateLogger(client.PlayerData.Name); client.GameStarted += OnGameStarted; - client.RoundStarted += OnRoundStarted; + // client.RoundStarted += OnRoundStarted; client.ItsYourTurn += OnItsYourTurn; client.PlayerPutCard += OnPlayerPutCard; client.PlayerPutWild += OnPlayerPutWild; client.PlayerDrewCard += OnPlayerDrewCard; client.PlayerPassed += OnPlayerPassed; - client.RoundEnded += OnRoundEnded; + // client.RoundEnded += OnRoundEnded; client.GameEnded += OnGameEnded; } From 0b9c87f24161093238d890511d1fb37692912207 Mon Sep 17 00:00:00 2001 From: stho Date: Fri, 10 Oct 2025 13:03:36 +0200 Subject: [PATCH 04/26] add sample client by claude --- hearts.sh | 3 + .../Deckster.Hearts.SampleClient.csproj | 16 ++ .../HeartsPoorAi.cs | 228 ++++++++++++++++++ src/Deckster.Hearts.SampleClient/Program.cs | 56 +++++ src/Deckster.Server/Deckster.Server.csproj | 1 + src/Deckster.sln | 7 + 6 files changed, 311 insertions(+) create mode 100644 hearts.sh create mode 100644 src/Deckster.Hearts.SampleClient/Deckster.Hearts.SampleClient.csproj create mode 100644 src/Deckster.Hearts.SampleClient/HeartsPoorAi.cs create mode 100644 src/Deckster.Hearts.SampleClient/Program.cs diff --git a/hearts.sh b/hearts.sh new file mode 100644 index 00000000..74fb7629 --- /dev/null +++ b/hearts.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd src/Deckster.Hearts.SampleClient +dotnet run diff --git a/src/Deckster.Hearts.SampleClient/Deckster.Hearts.SampleClient.csproj b/src/Deckster.Hearts.SampleClient/Deckster.Hearts.SampleClient.csproj new file mode 100644 index 00000000..769b9f5e --- /dev/null +++ b/src/Deckster.Hearts.SampleClient/Deckster.Hearts.SampleClient.csproj @@ -0,0 +1,16 @@ + + + + Exe + net9.0 + enable + enable + default + + + + + + + + diff --git a/src/Deckster.Hearts.SampleClient/HeartsPoorAi.cs b/src/Deckster.Hearts.SampleClient/HeartsPoorAi.cs new file mode 100644 index 00000000..95e1da38 --- /dev/null +++ b/src/Deckster.Hearts.SampleClient/HeartsPoorAi.cs @@ -0,0 +1,228 @@ +using Deckster.Client.Games.Hearts; +using Deckster.Client.Logging; +using Deckster.Core.Games.Common; +using Deckster.Core.Games.Hearts; +using Microsoft.Extensions.Logging; + +namespace Deckster.Hearts.SampleClient; + +public class HeartsPoorAi +{ + private readonly ILogger _logger; + private PlayerViewOfGame _view = new(); + private readonly HeartsClient _client; + private readonly TaskCompletionSource _tcs = new(); + + public HeartsPoorAi(HeartsClient client) + { + _client = client; + _logger = Log.Factory.CreateLogger(client.PlayerData.Name); + + client.GameStarted += OnGameStarted; + client.PassingPhaseStarted += OnPassingPhaseStarted; + client.AllPlayersPassed += OnAllPlayersPassed; + client.PlayerPassedCards += OnPlayerPassedCards; + client.ItsYourTurn += OnItsYourTurn; + client.ItsPlayersTurn += OnItsPlayersTurn; + client.PlayerPlayedCard += OnPlayerPlayedCard; + client.TrickCompleted += OnTrickCompleted; + client.RoundEnded += OnRoundEnded; + client.GameEnded += OnGameEnded; + client.HeartsWereBroken += OnHeartsWereBroken; + } + + private void OnGameStarted(GameStartedNotification notification) + { + _logger.LogInformation("Game started. GameId: {id}", notification.GameId); + _view = notification.PlayerViewOfGame; + } + + private void OnPassingPhaseStarted(PassingPhaseStartedNotification notification) + { + _logger.LogInformation("Passing phase started. Direction: {direction}", notification.PassDirection); + } + + private void OnAllPlayersPassed(AllPlayersPassedNotification notification) + { + _logger.LogInformation("All players passed. Received cards: {cards}", string.Join(", ", notification.ReceivedCards)); + // Cards will be updated in the next ItsYourTurn notification + } + + private void OnPlayerPassedCards(PlayerPassedCardsNotification notification) + { + _logger.LogDebug("Player {playerId} passed cards", notification.PlayerId); + } + + private void OnItsPlayersTurn(ItsPlayersTurnNotification notification) + { + _logger.LogDebug("It's player {playerId}'s turn", notification.PlayerId); + } + + private void OnPlayerPlayedCard(PlayerPlayedCardNotification notification) + { + _logger.LogInformation("Player {playerId} played {card}", notification.PlayerId, notification.Card); + } + + private void OnTrickCompleted(TrickCompletedNotification notification) + { + _logger.LogInformation("Trick completed. Winner: {winner} ({points} points)", + notification.WinnerName, notification.Points); + } + + private void OnRoundEnded(RoundEndedNotification notification) + { + _logger.LogInformation("Round ended. Scores:"); + foreach (var score in notification.Scores) + { + _logger.LogInformation(" {name}: Round={round}, Total={total}", + score.PlayerName, score.RoundScore, score.TotalScore); + } + if (notification.MoonShooterId != null) + { + _logger.LogInformation("Moon shot by {shooter}!", notification.MoonShooterName); + } + } + + private void OnGameEnded(GameEndedNotification notification) + { + _logger.LogInformation("Game ended! Winner: {winner}", notification.WinnerName); + _logger.LogInformation("Final scores:"); + foreach (var score in notification.FinalScores) + { + _logger.LogInformation(" {name}: {total}", score.PlayerName, score.TotalScore); + } + _tcs.SetResult(); + } + + private void OnHeartsWereBroken(HeartsAreBrokenNotification notification) + { + _logger.LogInformation("Hearts are broken!"); + } + + private async void OnItsYourTurn(ItsYourTurnNotification notification) + { + try + { + _view = notification.PlayerViewOfGame; + + // Handle passing phase + if (_view.PassDirection != PassDirection.None && !_view.HasPassed) + { + var cardsToPass = ChooseCardsToPass(); + _logger.LogInformation("Passing cards: {cards}", string.Join(", ", cardsToPass)); + await _client.PassCardsAsync(cardsToPass); + return; + } + + // Handle playing phase + if (_view.IsMyTurn) + { + var cardToPlay = ChooseCardToPlay(); + _logger.LogInformation("Playing card: {card}", cardToPlay); + var result = await _client.PlayCardAsync(cardToPlay); + + if (result.HasError) + { + _logger.LogError("Error playing card: {error}", result.Error); + } + } + } + catch (Exception e) + { + _logger.LogError(e, "Error during turn"); + } + } + + private List ChooseCardsToPass() + { + // Simple strategy: pass highest cards, prioritizing high hearts and Queen of Spades + var cards = _view.Cards.ToList(); + var cardsToPass = new List(); + + // Pass Queen of Spades if we have it + var queenOfSpades = cards.FirstOrDefault(c => c.Suit == Suit.Spades && c.Rank == 12); + if (queenOfSpades != null) + { + cardsToPass.Add(queenOfSpades); + cards.Remove(queenOfSpades); + } + + // Pass highest hearts + var hearts = cards.Where(c => c.Suit == Suit.Hearts).OrderByDescending(c => c.Rank).ToList(); + foreach (var heart in hearts.Take(3 - cardsToPass.Count)) + { + cardsToPass.Add(heart); + cards.Remove(heart); + } + + // Fill with highest remaining cards + while (cardsToPass.Count < 3) + { + var highCard = cards.OrderByDescending(c => c.Rank).First(); + cardsToPass.Add(highCard); + cards.Remove(highCard); + } + + return cardsToPass; + } + + private Card ChooseCardToPlay() + { + var cards = _view.Cards.ToList(); + var currentTrick = _view.CurrentTrick; + + // If leading (first card in trick) + if (currentTrick.Count == 0) + { + // Must lead with 2 of clubs if we have it (first trick) + var twoOfClubs = cards.FirstOrDefault(c => c.Suit == Suit.Clubs && c.Rank == 2); + if (twoOfClubs != null) + { + return twoOfClubs; + } + + // Try to lead with a safe card (not hearts unless broken, low cards preferred) + var safeCards = cards.Where(c => c.Suit != Suit.Hearts || _view.HeartsAreBroken).ToList(); + if (safeCards.Any()) + { + // Lead with lowest safe card + return safeCards.OrderBy(c => c.Rank).First(); + } + + // If only hearts, lead with lowest heart + return cards.Where(c => c.Suit == Suit.Hearts).OrderBy(c => c.Rank).First(); + } + + // Following suit + var leadSuit = currentTrick[0].Card.Suit; + var sameSuitCards = cards.Where(c => c.Suit == leadSuit).ToList(); + + if (sameSuitCards.Any()) + { + // Play highest card of lead suit (try to avoid winning) + return sameSuitCards.OrderByDescending(c => c.Rank).First(); + } + + // Can't follow suit - try to dump Queen of Spades or high hearts + var queenOfSpades = cards.FirstOrDefault(c => c.Suit == Suit.Spades && c.Rank == 12); + if (queenOfSpades != null) + { + return queenOfSpades; + } + + var highHearts = cards.Where(c => c.Suit == Suit.Hearts).OrderByDescending(c => c.Rank).ToList(); + if (highHearts.Any()) + { + return highHearts.First(); + } + + // Otherwise, play highest card to get rid of it + return cards.OrderByDescending(c => c.Rank).First(); + } + + public Task PlayAsync(CancellationToken cancellationToken) + { + cancellationToken.Register(_tcs.SetCanceled); + return _tcs.Task; + } +} diff --git a/src/Deckster.Hearts.SampleClient/Program.cs b/src/Deckster.Hearts.SampleClient/Program.cs new file mode 100644 index 00000000..c569a403 --- /dev/null +++ b/src/Deckster.Hearts.SampleClient/Program.cs @@ -0,0 +1,56 @@ +using Deckster.Client; +using Deckster.Client.Games.Hearts; +using Deckster.Client.Logging; +using Microsoft.Extensions.Logging; + +namespace Deckster.Hearts.SampleClient; + +class Program +{ + public static async Task Main(string[] argz) + { + try + { + var logger = Log.Factory.CreateLogger("Hearts"); + const string gameName = "my-hearts-game"; + using var cts = new CancellationTokenSource(); + Console.CancelKeyPress += (s, e) => + { + if (cts.IsCancellationRequested) + { + return; + } + cts.Cancel(); + }; + + var deckster = await DecksterClient.LogInOrRegisterAsync("http://localhost:13992", "Hearts Player", "hest"); + var client = deckster.Hearts(); + logger.LogInformation("Creating game {name}", gameName); + var info = await client.CreateAsync(gameName, cts.Token); + logger.LogInformation("Adding bots"); + + // Hearts needs exactly 4 players, so add 3 bots + for (var ii = 0; ii < 3; ii++) + { + await client.AddBotAsync(gameName, cts.Token); + } + + logger.LogInformation("Joining game {name}", gameName); + await using var game = await client.JoinAsync(gameName, cts.Token); + + logger.LogInformation("Using ai"); + var ai = new HeartsPoorAi(game); + logger.LogInformation("Starting game"); + await client.StartGameAsync(gameName, cts.Token); + logger.LogInformation("Playing game"); + await ai.PlayAsync(cts.Token); + + return 0; + } + catch (Exception e) + { + Console.WriteLine(e); + return 1; + } + } +} diff --git a/src/Deckster.Server/Deckster.Server.csproj b/src/Deckster.Server/Deckster.Server.csproj index 3c362230..63647898 100644 --- a/src/Deckster.Server/Deckster.Server.csproj +++ b/src/Deckster.Server/Deckster.Server.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Deckster.sln b/src/Deckster.sln index f165adb3..69ade46b 100644 --- a/src/Deckster.sln +++ b/src/Deckster.sln @@ -43,6 +43,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deckster.TexasHoldEm.Sample EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deckster.Bullshit.SampleClient", "Deckster.Bullshit.SampleClient\Deckster.Bullshit.SampleClient.csproj", "{15FD6712-AFF7-42EC-BBAD-28E23B77107B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deckster.Hearts.SampleClient", "Deckster.Hearts.SampleClient\Deckster.Hearts.SampleClient.csproj", "{31419E3F-8EF3-4D76-AD38-F91CB0C67004}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -109,6 +111,10 @@ Global {15FD6712-AFF7-42EC-BBAD-28E23B77107B}.Debug|Any CPU.Build.0 = Debug|Any CPU {15FD6712-AFF7-42EC-BBAD-28E23B77107B}.Release|Any CPU.ActiveCfg = Release|Any CPU {15FD6712-AFF7-42EC-BBAD-28E23B77107B}.Release|Any CPU.Build.0 = Release|Any CPU + {31419E3F-8EF3-4D76-AD38-F91CB0C67004}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31419E3F-8EF3-4D76-AD38-F91CB0C67004}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31419E3F-8EF3-4D76-AD38-F91CB0C67004}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31419E3F-8EF3-4D76-AD38-F91CB0C67004}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -129,6 +135,7 @@ Global {38F22734-F7CB-4376-BC86-6623F98F45D0} = {E66EE07A-1B20-4842-A77D-5A71F8FD3E0B} {C69EE4FE-3BF2-41F7-A956-E3A270219DD9} = {E66EE07A-1B20-4842-A77D-5A71F8FD3E0B} {15FD6712-AFF7-42EC-BBAD-28E23B77107B} = {E66EE07A-1B20-4842-A77D-5A71F8FD3E0B} + {31419E3F-8EF3-4D76-AD38-F91CB0C67004} = {E66EE07A-1B20-4842-A77D-5A71F8FD3E0B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AE622423-92CC-4E60-ADDA-E76DEFF6CB96} From a27230e6d9552735efb6a63a2e6b26bfa3b7e0ba Mon Sep 17 00:00:00 2001 From: stho Date: Fri, 10 Oct 2025 13:53:37 +0200 Subject: [PATCH 05/26] WIP --- decksterapi.yml | 5 +++-- generated/shebang.opeanpi.json | 6 ++++-- generated/shebang.opeanpi.yaml | 5 +++-- src/Deckster.Core/Games/Common/Card.cs | 9 ++++++++- .../Games/Hearts/HeartsMessages.cs | 2 +- src/Deckster.Games/Hearts/HeartsGame.cs | 8 ++++++++ .../HeartsPoorAi.cs | 20 +++++++++---------- .../Games/Hearts/HeartsGameHost.cs | 19 ++++++++++++++++-- 8 files changed, 54 insertions(+), 20 deletions(-) diff --git a/decksterapi.yml b/decksterapi.yml index 14d6d4c6..f6c85ce4 100644 --- a/decksterapi.yml +++ b/decksterapi.yml @@ -5100,13 +5100,14 @@ components: Hearts.PassCardsResponse: allOf: - $ref: '#/components/schemas/Protocol.DecksterResponse' - - type: object + - required: + - receivedCards + type: object properties: receivedCards: type: array items: $ref: '#/components/schemas/Common.Card' - nullable: true additionalProperties: false Hearts.PassDirection: enum: diff --git a/generated/shebang.opeanpi.json b/generated/shebang.opeanpi.json index 4bbffa88..b7ed2a07 100644 --- a/generated/shebang.opeanpi.json +++ b/generated/shebang.opeanpi.json @@ -8431,14 +8431,16 @@ "$ref": "#/components/schemas/Protocol.DecksterResponse" }, { + "required": [ + "receivedCards" + ], "type": "object", "properties": { "receivedCards": { "type": "array", "items": { "$ref": "#/components/schemas/Common.Card" - }, - "nullable": true + } } }, "additionalProperties": false diff --git a/generated/shebang.opeanpi.yaml b/generated/shebang.opeanpi.yaml index 14d6d4c6..f6c85ce4 100644 --- a/generated/shebang.opeanpi.yaml +++ b/generated/shebang.opeanpi.yaml @@ -5100,13 +5100,14 @@ components: Hearts.PassCardsResponse: allOf: - $ref: '#/components/schemas/Protocol.DecksterResponse' - - type: object + - required: + - receivedCards + type: object properties: receivedCards: type: array items: $ref: '#/components/schemas/Common.Card' - nullable: true additionalProperties: false Hearts.PassDirection: enum: diff --git a/src/Deckster.Core/Games/Common/Card.cs b/src/Deckster.Core/Games/Common/Card.cs index f587ee71..f39f1bec 100644 --- a/src/Deckster.Core/Games/Common/Card.cs +++ b/src/Deckster.Core/Games/Common/Card.cs @@ -1,6 +1,6 @@ namespace Deckster.Core.Games.Common; -public readonly struct Card +public readonly struct Card : IComparable { public int Rank { get; init; } public Suit Suit { get; init; } @@ -45,6 +45,13 @@ public override int GetHashCode() return HashCode.Combine(Rank, (int) Suit); } + public int CompareTo(Card other) + { + // Sort by suit first, then by rank + var suitComparison = Suit.CompareTo(other.Suit); + return suitComparison != 0 ? suitComparison : Rank.CompareTo(other.Rank); + } + public override string ToString() { return Rank switch diff --git a/src/Deckster.Core/Games/Hearts/HeartsMessages.cs b/src/Deckster.Core/Games/Hearts/HeartsMessages.cs index b3801400..a07f4cc9 100644 --- a/src/Deckster.Core/Games/Hearts/HeartsMessages.cs +++ b/src/Deckster.Core/Games/Hearts/HeartsMessages.cs @@ -15,5 +15,5 @@ public class PlayCardRequest : DecksterRequest public class PassCardsResponse : DecksterResponse { - public List? ReceivedCards { get; init; } + public List ReceivedCards { get; init; } = []; } diff --git a/src/Deckster.Games/Hearts/HeartsGame.cs b/src/Deckster.Games/Hearts/HeartsGame.cs index fa0c6111..a1110c8d 100644 --- a/src/Deckster.Games/Hearts/HeartsGame.cs +++ b/src/Deckster.Games/Hearts/HeartsGame.cs @@ -549,6 +549,14 @@ public override async Task StartAsync() { PassDirection = CurrentPassDirection }); + + foreach (var player in Players) + { + await ItsYourTurn.InvokeOrDefault(player.Id, () => new ItsYourTurnNotification + { + PlayerViewOfGame = GetPlayerViewOfGame(player) + }); + } } } } diff --git a/src/Deckster.Hearts.SampleClient/HeartsPoorAi.cs b/src/Deckster.Hearts.SampleClient/HeartsPoorAi.cs index 95e1da38..446509ed 100644 --- a/src/Deckster.Hearts.SampleClient/HeartsPoorAi.cs +++ b/src/Deckster.Hearts.SampleClient/HeartsPoorAi.cs @@ -140,11 +140,11 @@ private List ChooseCardsToPass() var cardsToPass = new List(); // Pass Queen of Spades if we have it - var queenOfSpades = cards.FirstOrDefault(c => c.Suit == Suit.Spades && c.Rank == 12); - if (queenOfSpades != null) + var queenOfSpades = cards.Where(c => c.Suit == Suit.Spades && c.Rank == 12).ToList(); + if (queenOfSpades.Any()) { - cardsToPass.Add(queenOfSpades); - cards.Remove(queenOfSpades); + cardsToPass.Add(queenOfSpades.First()); + cards.Remove(queenOfSpades.First()); } // Pass highest hearts @@ -175,10 +175,10 @@ private Card ChooseCardToPlay() if (currentTrick.Count == 0) { // Must lead with 2 of clubs if we have it (first trick) - var twoOfClubs = cards.FirstOrDefault(c => c.Suit == Suit.Clubs && c.Rank == 2); - if (twoOfClubs != null) + var twoOfClubs = cards.Where(c => c.Suit == Suit.Clubs && c.Rank == 2).ToList(); + if (twoOfClubs.Any()) { - return twoOfClubs; + return twoOfClubs.First(); } // Try to lead with a safe card (not hearts unless broken, low cards preferred) @@ -204,10 +204,10 @@ private Card ChooseCardToPlay() } // Can't follow suit - try to dump Queen of Spades or high hearts - var queenOfSpades = cards.FirstOrDefault(c => c.Suit == Suit.Spades && c.Rank == 12); - if (queenOfSpades != null) + var queenOfSpades = cards.Where(c => c.Suit == Suit.Spades && c.Rank == 12).ToList(); + if (queenOfSpades.Any()) { - return queenOfSpades; + return queenOfSpades.First(); } var highHearts = cards.Where(c => c.Suit == Suit.Hearts).OrderByDescending(c => c.Rank).ToList(); diff --git a/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs b/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs index e40d1f9d..3c9e80b6 100644 --- a/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs +++ b/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs @@ -1,6 +1,10 @@ using System.Diagnostics.CodeAnalysis; +using Deckster.Client.Games.Hearts; +using Deckster.Core.Games.Common; using Deckster.Games.Hearts; +using Deckster.Hearts.SampleClient; using Deckster.Server.Data; +using Deckster.Server.Games.Common.Fakes; namespace Deckster.Server.Games.Hearts; @@ -8,13 +12,24 @@ public class HeartsGameHost : StandardGameHost { public override string GameType => "Hearts"; + private readonly List _bots = []; + public HeartsGameHost(IRepo repo, ILoggerFactory loggerFactory) : base(repo, loggerFactory, new HeartsProjection(), 4) { } public override bool TryAddBot([MaybeNullWhen(true)] out string error) { - error = "Bots are not yet supported for Hearts"; - return false; + var channel = new InMemoryChannel + { + Player = new PlayerData + { + Id = Guid.NewGuid(), + Name = TestUserNames.Random() + } + }; + var bot = new HeartsPoorAi(new HeartsClient(channel)); + _bots.Add(bot); + return TryAddPlayer(channel, out error); } } From 8725997e3e15c7dd73a5e6a05e9d671d6cef68f4 Mon Sep 17 00:00:00 2001 From: stho Date: Fri, 10 Oct 2025 14:51:43 +0200 Subject: [PATCH 06/26] wip --- src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs b/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs index a105b9c1..d41e1944 100644 --- a/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs +++ b/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs @@ -141,7 +141,7 @@ public CsharpClientGenerator(CSharpGameMeta meta, string ns) "/// throws exception on error", "/// ", ]); - Source.AppendLine($"public static async Task<{extension.ReturnParameters[0].ParameterType.ToDisplayString()}> {extension.Name}OrThrowAsync(this {ClientName} self, {parameters})"); + Source.AppendLine($"public static async Task<{extension.ReturnParameters[0].ParameterType.Name}> {extension.Name}OrThrowAsync(this {ClientName} self, {parameters})"); break; default: var returnTuple = extension.ReturnParameters.Select(p => $"{p.ParameterType.ToDisplayString()} {p.Name}").StringJoined(", "); From 63f9626b9397326a1e4ce96daf4a76336cf14c15 Mon Sep 17 00:00:00 2001 From: stho Date: Fri, 10 Oct 2025 16:17:30 +0200 Subject: [PATCH 07/26] web clients by claude --- .gitignore | 4 + .../typescript/bullshit/BullshitClient.ts | 364 ++ generated/typescript/bullshit/types.ts | 160 + .../typescript/chatroom/ChatRoomClient.ts | 79 + generated/typescript/chatroom/types.ts | 23 + .../crazyeights/CrazyEightsClient.ts | 326 ++ generated/typescript/crazyeights/types.ts | 144 + generated/typescript/gabong/GabongClient.ts | 312 ++ generated/typescript/gabong/types.ts | 160 + generated/typescript/hearts/HeartsClient.ts | 294 ++ generated/typescript/hearts/types.ts | 144 + generated/typescript/idiot/IdiotClient.ts | 439 ++ generated/typescript/idiot/types.ts | 173 + .../texasholdem/TexasHoldEmClient.ts | 344 ++ generated/typescript/texasholdem/types.ts | 146 + generated/typescript/types.ts | 11 + generated/typescript/uno/UnoClient.ts | 269 ++ generated/typescript/uno/types.ts | 147 + generated/typescript/yaniv/YanivClient.ts | 200 + generated/typescript/yaniv/types.ts | 104 + .../Generators/CsharpClientGenerator.cs | 2 +- .../Generators/TypeScriptClientGenerator.cs | 283 ++ .../Generators/TypeScriptTypeGenerator.cs | 273 ++ src/Deckster.CodeGenerator/Program.cs | 119 +- src/Deckster.Server/Startup.cs | 21 +- web-clients/hearts/README.md | 138 + .../hearts/dist/assets/index-w1daCLpV.js | 3844 +++++++++++++++++ web-clients/hearts/dist/index.html | 180 + web-clients/hearts/index.html | 180 + web-clients/hearts/package-lock.json | 1160 +++++ web-clients/hearts/package.json | 23 + web-clients/hearts/src/game/HeartsGame.ts | 384 ++ web-clients/hearts/src/graphics/Card3D.ts | 171 + web-clients/hearts/src/graphics/CardScene.ts | 279 ++ web-clients/hearts/src/main.ts | 83 + web-clients/hearts/src/ui/GameUI.ts | 94 + web-clients/hearts/tsconfig.json | 29 + web-clients/hearts/vite.config.ts | 14 + 38 files changed, 11109 insertions(+), 11 deletions(-) create mode 100644 generated/typescript/bullshit/BullshitClient.ts create mode 100644 generated/typescript/bullshit/types.ts create mode 100644 generated/typescript/chatroom/ChatRoomClient.ts create mode 100644 generated/typescript/chatroom/types.ts create mode 100644 generated/typescript/crazyeights/CrazyEightsClient.ts create mode 100644 generated/typescript/crazyeights/types.ts create mode 100644 generated/typescript/gabong/GabongClient.ts create mode 100644 generated/typescript/gabong/types.ts create mode 100644 generated/typescript/hearts/HeartsClient.ts create mode 100644 generated/typescript/hearts/types.ts create mode 100644 generated/typescript/idiot/IdiotClient.ts create mode 100644 generated/typescript/idiot/types.ts create mode 100644 generated/typescript/texasholdem/TexasHoldEmClient.ts create mode 100644 generated/typescript/texasholdem/types.ts create mode 100644 generated/typescript/types.ts create mode 100644 generated/typescript/uno/UnoClient.ts create mode 100644 generated/typescript/uno/types.ts create mode 100644 generated/typescript/yaniv/YanivClient.ts create mode 100644 generated/typescript/yaniv/types.ts create mode 100644 src/Deckster.CodeGenerator/Generators/TypeScriptClientGenerator.cs create mode 100644 src/Deckster.CodeGenerator/Generators/TypeScriptTypeGenerator.cs create mode 100644 web-clients/hearts/README.md create mode 100644 web-clients/hearts/dist/assets/index-w1daCLpV.js create mode 100644 web-clients/hearts/dist/index.html create mode 100644 web-clients/hearts/index.html create mode 100644 web-clients/hearts/package-lock.json create mode 100644 web-clients/hearts/package.json create mode 100644 web-clients/hearts/src/game/HeartsGame.ts create mode 100644 web-clients/hearts/src/graphics/Card3D.ts create mode 100644 web-clients/hearts/src/graphics/CardScene.ts create mode 100644 web-clients/hearts/src/main.ts create mode 100644 web-clients/hearts/src/ui/GameUI.ts create mode 100644 web-clients/hearts/tsconfig.json create mode 100644 web-clients/hearts/vite.config.ts diff --git a/.gitignore b/.gitignore index 6676cf31..5b8d2e49 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,7 @@ DerivedData/ .swiftpm/configuration/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc + + +# nodejs +node_modules \ No newline at end of file diff --git a/generated/typescript/bullshit/BullshitClient.ts b/generated/typescript/bullshit/BullshitClient.ts new file mode 100644 index 00000000..d2aa9796 --- /dev/null +++ b/generated/typescript/bullshit/BullshitClient.ts @@ -0,0 +1,364 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * Bullshit Game Client + * + * Notifications (events) for this game: + * - GameStarted: GameStartedNotification + * - PlayerDrewCard: PlayerDrewCardNotification + * - ItsYourTurn: ItsYourTurnNotification + * - ItsPlayersTurn: ItsPlayersTurnNotification + * - PlayerPassed: PlayerPassedNotification + * - PlayerPutCard: PlayerPutCardNotification + * - GameEnded: GameEndedNotification + * - PlayerIsDone: PlayerIsDoneNotification + * - DiscardPileShuffled: DiscardPileShuffledNotification + * - PlayersBullshitHasBeenCalled: BullshitBroadcastNotification + * - YourBullshitHasBeenCalled: BullshitPlayerNotification + * - PlayerAccusedFalseBullshit: FalseBullshitCallNotification + */ + +import type { EmptyResponse } from '../types'; +import type { BullshitBroadcastNotification, BullshitPlayerNotification, BullshitRequest, BullshitResponse, CardResponse, DiscardPileShuffledNotification, DrawCardRequest, FalseBullshitCallNotification, GameEndedNotification, GameStartedNotification, ItsPlayersTurnNotification, ItsYourTurnNotification, PassRequest, PlayerDrewCardNotification, PlayerIsDoneNotification, PlayerPassedNotification, PlayerPutCardNotification, PutCardRequest } from './types'; + +// Event handler types +export type GameStartedHandler = (data: GameStartedNotification) => void; +export type PlayerDrewCardHandler = (data: PlayerDrewCardNotification) => void; +export type ItsYourTurnHandler = (data: ItsYourTurnNotification) => void; +export type ItsPlayersTurnHandler = (data: ItsPlayersTurnNotification) => void; +export type PlayerPassedHandler = (data: PlayerPassedNotification) => void; +export type PlayerPutCardHandler = (data: PlayerPutCardNotification) => void; +export type GameEndedHandler = (data: GameEndedNotification) => void; +export type PlayerIsDoneHandler = (data: PlayerIsDoneNotification) => void; +export type DiscardPileShuffledHandler = (data: DiscardPileShuffledNotification) => void; +export type PlayersBullshitHasBeenCalledHandler = (data: BullshitBroadcastNotification) => void; +export type YourBullshitHasBeenCalledHandler = (data: BullshitPlayerNotification) => void; +export type PlayerAccusedFalseBullshitHandler = (data: FalseBullshitCallNotification) => void; + +export interface BullshitClient { + onGameStarted(handler: GameStartedHandler): void; + offGameStarted(handler: GameStartedHandler): void; + onPlayerDrewCard(handler: PlayerDrewCardHandler): void; + offPlayerDrewCard(handler: PlayerDrewCardHandler): void; + onItsYourTurn(handler: ItsYourTurnHandler): void; + offItsYourTurn(handler: ItsYourTurnHandler): void; + onItsPlayersTurn(handler: ItsPlayersTurnHandler): void; + offItsPlayersTurn(handler: ItsPlayersTurnHandler): void; + onPlayerPassed(handler: PlayerPassedHandler): void; + offPlayerPassed(handler: PlayerPassedHandler): void; + onPlayerPutCard(handler: PlayerPutCardHandler): void; + offPlayerPutCard(handler: PlayerPutCardHandler): void; + onGameEnded(handler: GameEndedHandler): void; + offGameEnded(handler: GameEndedHandler): void; + onPlayerIsDone(handler: PlayerIsDoneHandler): void; + offPlayerIsDone(handler: PlayerIsDoneHandler): void; + onDiscardPileShuffled(handler: DiscardPileShuffledHandler): void; + offDiscardPileShuffled(handler: DiscardPileShuffledHandler): void; + onPlayersBullshitHasBeenCalled(handler: PlayersBullshitHasBeenCalledHandler): void; + offPlayersBullshitHasBeenCalled(handler: PlayersBullshitHasBeenCalledHandler): void; + onYourBullshitHasBeenCalled(handler: YourBullshitHasBeenCalledHandler): void; + offYourBullshitHasBeenCalled(handler: YourBullshitHasBeenCalledHandler): void; + onPlayerAccusedFalseBullshit(handler: PlayerAccusedFalseBullshitHandler): void; + offPlayerAccusedFalseBullshit(handler: PlayerAccusedFalseBullshitHandler): void; + + putCard(request: PutCardRequest): Promise; + drawCard(request: DrawCardRequest): Promise; + pass(request: PassRequest): Promise; + callBullshit(request: BullshitRequest): Promise; +} + +export class BullshitClientImpl implements BullshitClient { + private gameStartedHandlers: GameStartedHandler[] = []; + private playerDrewCardHandlers: PlayerDrewCardHandler[] = []; + private itsYourTurnHandlers: ItsYourTurnHandler[] = []; + private itsPlayersTurnHandlers: ItsPlayersTurnHandler[] = []; + private playerPassedHandlers: PlayerPassedHandler[] = []; + private playerPutCardHandlers: PlayerPutCardHandler[] = []; + private gameEndedHandlers: GameEndedHandler[] = []; + private playerIsDoneHandlers: PlayerIsDoneHandler[] = []; + private discardPileShuffledHandlers: DiscardPileShuffledHandler[] = []; + private playersBullshitHasBeenCalledHandlers: PlayersBullshitHasBeenCalledHandler[] = []; + private yourBullshitHasBeenCalledHandlers: YourBullshitHasBeenCalledHandler[] = []; + private playerAccusedFalseBullshitHandlers: PlayerAccusedFalseBullshitHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'GameStarted': + this.gameStartedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerDrewCard': + this.playerDrewCardHandlers.forEach(h => h(notification.data)); + break; + case 'ItsYourTurn': + this.itsYourTurnHandlers.forEach(h => h(notification.data)); + break; + case 'ItsPlayersTurn': + this.itsPlayersTurnHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPassed': + this.playerPassedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPutCard': + this.playerPutCardHandlers.forEach(h => h(notification.data)); + break; + case 'GameEnded': + this.gameEndedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerIsDone': + this.playerIsDoneHandlers.forEach(h => h(notification.data)); + break; + case 'DiscardPileShuffled': + this.discardPileShuffledHandlers.forEach(h => h(notification.data)); + break; + case 'PlayersBullshitHasBeenCalled': + this.playersBullshitHasBeenCalledHandlers.forEach(h => h(notification.data)); + break; + case 'YourBullshitHasBeenCalled': + this.yourBullshitHasBeenCalledHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerAccusedFalseBullshit': + this.playerAccusedFalseBullshitHandlers.forEach(h => h(notification.data)); + break; + } + } + + onGameStarted(handler: GameStartedHandler): void { + this.gameStartedHandlers.push(handler); + } + + offGameStarted(handler: GameStartedHandler): void { + const index = this.gameStartedHandlers.indexOf(handler); + if (index > -1) { + this.gameStartedHandlers.splice(index, 1); + } + } + + onPlayerDrewCard(handler: PlayerDrewCardHandler): void { + this.playerDrewCardHandlers.push(handler); + } + + offPlayerDrewCard(handler: PlayerDrewCardHandler): void { + const index = this.playerDrewCardHandlers.indexOf(handler); + if (index > -1) { + this.playerDrewCardHandlers.splice(index, 1); + } + } + + onItsYourTurn(handler: ItsYourTurnHandler): void { + this.itsYourTurnHandlers.push(handler); + } + + offItsYourTurn(handler: ItsYourTurnHandler): void { + const index = this.itsYourTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsYourTurnHandlers.splice(index, 1); + } + } + + onItsPlayersTurn(handler: ItsPlayersTurnHandler): void { + this.itsPlayersTurnHandlers.push(handler); + } + + offItsPlayersTurn(handler: ItsPlayersTurnHandler): void { + const index = this.itsPlayersTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsPlayersTurnHandlers.splice(index, 1); + } + } + + onPlayerPassed(handler: PlayerPassedHandler): void { + this.playerPassedHandlers.push(handler); + } + + offPlayerPassed(handler: PlayerPassedHandler): void { + const index = this.playerPassedHandlers.indexOf(handler); + if (index > -1) { + this.playerPassedHandlers.splice(index, 1); + } + } + + onPlayerPutCard(handler: PlayerPutCardHandler): void { + this.playerPutCardHandlers.push(handler); + } + + offPlayerPutCard(handler: PlayerPutCardHandler): void { + const index = this.playerPutCardHandlers.indexOf(handler); + if (index > -1) { + this.playerPutCardHandlers.splice(index, 1); + } + } + + onGameEnded(handler: GameEndedHandler): void { + this.gameEndedHandlers.push(handler); + } + + offGameEnded(handler: GameEndedHandler): void { + const index = this.gameEndedHandlers.indexOf(handler); + if (index > -1) { + this.gameEndedHandlers.splice(index, 1); + } + } + + onPlayerIsDone(handler: PlayerIsDoneHandler): void { + this.playerIsDoneHandlers.push(handler); + } + + offPlayerIsDone(handler: PlayerIsDoneHandler): void { + const index = this.playerIsDoneHandlers.indexOf(handler); + if (index > -1) { + this.playerIsDoneHandlers.splice(index, 1); + } + } + + onDiscardPileShuffled(handler: DiscardPileShuffledHandler): void { + this.discardPileShuffledHandlers.push(handler); + } + + offDiscardPileShuffled(handler: DiscardPileShuffledHandler): void { + const index = this.discardPileShuffledHandlers.indexOf(handler); + if (index > -1) { + this.discardPileShuffledHandlers.splice(index, 1); + } + } + + onPlayersBullshitHasBeenCalled(handler: PlayersBullshitHasBeenCalledHandler): void { + this.playersBullshitHasBeenCalledHandlers.push(handler); + } + + offPlayersBullshitHasBeenCalled(handler: PlayersBullshitHasBeenCalledHandler): void { + const index = this.playersBullshitHasBeenCalledHandlers.indexOf(handler); + if (index > -1) { + this.playersBullshitHasBeenCalledHandlers.splice(index, 1); + } + } + + onYourBullshitHasBeenCalled(handler: YourBullshitHasBeenCalledHandler): void { + this.yourBullshitHasBeenCalledHandlers.push(handler); + } + + offYourBullshitHasBeenCalled(handler: YourBullshitHasBeenCalledHandler): void { + const index = this.yourBullshitHasBeenCalledHandlers.indexOf(handler); + if (index > -1) { + this.yourBullshitHasBeenCalledHandlers.splice(index, 1); + } + } + + onPlayerAccusedFalseBullshit(handler: PlayerAccusedFalseBullshitHandler): void { + this.playerAccusedFalseBullshitHandlers.push(handler); + } + + offPlayerAccusedFalseBullshit(handler: PlayerAccusedFalseBullshitHandler): void { + const index = this.playerAccusedFalseBullshitHandlers.indexOf(handler); + if (index > -1) { + this.playerAccusedFalseBullshitHandlers.splice(index, 1); + } + } + + async putCard(request: PutCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async drawCard(request: DrawCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'DrawCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async pass(request: PassRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'Pass', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async callBullshit(request: BullshitRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'CallBullshit', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + +} diff --git a/generated/typescript/bullshit/types.ts b/generated/typescript/bullshit/types.ts new file mode 100644 index 00000000..83051419 --- /dev/null +++ b/generated/typescript/bullshit/types.ts @@ -0,0 +1,160 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface GameStartedNotification { + gameId: string; + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface PlayerViewOfGame { + cards?: Card[]; + claimedTopOfPile?: Card; + stockPileCount: number; + discardPileCount: number; + otherPlayers?: OtherBullshitPlayer[]; +} + +export interface Card { + rank: number; + suit: Suit; +} + +export enum Suit { + Clubs = 0, + Diamonds = 1, + Hearts = 2, + Spades = 3, +} + +export interface PlayerDrewCardNotification { + playerId: string; + type?: string; +} + +export interface ItsYourTurnNotification { + type?: string; +} + +export interface ItsPlayersTurnNotification { + playerId: string; + type?: string; +} + +export interface PlayerPassedNotification { + playerId: string; + type?: string; +} + +export interface PlayerPutCardNotification { + playerId: string; + claimedToBeCard: Card; + type?: string; +} + +export interface GameEndedNotification { + players?: PlayerData[]; + loserId: string; + loserName?: string; + type?: string; +} + +export interface PlayerData { + name?: string; + points: number; + cardsInHand: number; + id: string; + info?: Record; +} + +export interface Dictionary { + comparer?: IEqualityComparer; + count: number; + capacity: number; + keys?: KeyCollection; + values?: ValueCollection; +} + +export interface ValueCollection { + count: number; +} + +export interface KeyCollection { + count: number; +} + +export interface PlayerIsDoneNotification { + playerId: string; + type?: string; +} + +export interface DiscardPileShuffledNotification { + type?: string; +} + +export interface BullshitBroadcastNotification { + playerId: string; + claimedToBeCard: Card; + actualCard: Card; + punishmentCardCount: number; + type?: string; +} + +export interface BullshitPlayerNotification { + calledByPlayerId: string; + card: Card; + punishmentCards?: Card[]; + type?: string; +} + +export interface FalseBullshitCallNotification { + playerId: string; + accusedPlayerId: string; + punishmentCardCount: number; + type?: string; +} + +export interface PutCardRequest { + actualCard: Card; + claimedToBeCard: Card; + playerId: string; + type?: string; +} + +export interface DrawCardRequest { + playerId: string; + type?: string; +} + +export interface CardResponse { + card: Card; + hasError: boolean; + error?: string; + type?: string; +} + +export interface PassRequest { + playerId: string; + type?: string; +} + +export interface BullshitRequest { + playerId: string; + type?: string; +} + +export interface BullshitResponse { + punishmentCards?: Card[]; + hasError: boolean; + error?: string; + type?: string; +} + +export interface OtherBullshitPlayer { + playerId: string; + name?: string; + numberOfCards: number; +} + diff --git a/generated/typescript/chatroom/ChatRoomClient.ts b/generated/typescript/chatroom/ChatRoomClient.ts new file mode 100644 index 00000000..54115abd --- /dev/null +++ b/generated/typescript/chatroom/ChatRoomClient.ts @@ -0,0 +1,79 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * ChatRoom Game Client + * + * Notifications (events) for this game: + * - PlayerSaid: ChatNotification + */ + +import type { ChatNotification, ChatResponse, SendChatRequest } from './types'; + +// Event handler types +export type PlayerSaidHandler = (data: ChatNotification) => void; + +export interface ChatRoomClient { + onPlayerSaid(handler: PlayerSaidHandler): void; + offPlayerSaid(handler: PlayerSaidHandler): void; + + chatAsync(request: SendChatRequest): Promise; +} + +export class ChatRoomClientImpl implements ChatRoomClient { + private playerSaidHandlers: PlayerSaidHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'PlayerSaid': + this.playerSaidHandlers.forEach(h => h(notification.data)); + break; + } + } + + onPlayerSaid(handler: PlayerSaidHandler): void { + this.playerSaidHandlers.push(handler); + } + + offPlayerSaid(handler: PlayerSaidHandler): void { + const index = this.playerSaidHandlers.indexOf(handler); + if (index > -1) { + this.playerSaidHandlers.splice(index, 1); + } + } + + async chatAsync(request: SendChatRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'ChatAsync', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + +} diff --git a/generated/typescript/chatroom/types.ts b/generated/typescript/chatroom/types.ts new file mode 100644 index 00000000..77164cb7 --- /dev/null +++ b/generated/typescript/chatroom/types.ts @@ -0,0 +1,23 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface ChatNotification { + sender?: string; + message?: string; + type?: string; +} + +export interface SendChatRequest { + message?: string; + playerId: string; + type?: string; +} + +export interface ChatResponse { + hasError: boolean; + error?: string; + type?: string; +} + diff --git a/generated/typescript/crazyeights/CrazyEightsClient.ts b/generated/typescript/crazyeights/CrazyEightsClient.ts new file mode 100644 index 00000000..8d189f77 --- /dev/null +++ b/generated/typescript/crazyeights/CrazyEightsClient.ts @@ -0,0 +1,326 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * CrazyEights Game Client + * + * Notifications (events) for this game: + * - GameStarted: GameStartedNotification + * - PlayerDrewCard: PlayerDrewCardNotification + * - ItsYourTurn: ItsYourTurnNotification + * - ItsPlayersTurn: ItsPlayersTurnNotification + * - PlayerPassed: PlayerPassedNotification + * - PlayerPutCard: PlayerPutCardNotification + * - PlayerPutEight: PlayerPutEightNotification + * - GameEnded: GameEndedNotification + * - PlayerIsDone: PlayerIsDoneNotification + * - DiscardPileShuffled: DiscardPileShuffledNotification + */ + +import type { EmptyResponse } from '../types'; +import type { CardResponse, DiscardPileShuffledNotification, DrawCardRequest, GameEndedNotification, GameStartedNotification, ItsPlayersTurnNotification, ItsYourTurnNotification, PassRequest, PlayerDrewCardNotification, PlayerIsDoneNotification, PlayerPassedNotification, PlayerPutCardNotification, PlayerPutEightNotification, PlayerViewOfGame, PutCardRequest, PutEightRequest } from './types'; + +// Event handler types +export type GameStartedHandler = (data: GameStartedNotification) => void; +export type PlayerDrewCardHandler = (data: PlayerDrewCardNotification) => void; +export type ItsYourTurnHandler = (data: ItsYourTurnNotification) => void; +export type ItsPlayersTurnHandler = (data: ItsPlayersTurnNotification) => void; +export type PlayerPassedHandler = (data: PlayerPassedNotification) => void; +export type PlayerPutCardHandler = (data: PlayerPutCardNotification) => void; +export type PlayerPutEightHandler = (data: PlayerPutEightNotification) => void; +export type GameEndedHandler = (data: GameEndedNotification) => void; +export type PlayerIsDoneHandler = (data: PlayerIsDoneNotification) => void; +export type DiscardPileShuffledHandler = (data: DiscardPileShuffledNotification) => void; + +export interface CrazyEightsClient { + onGameStarted(handler: GameStartedHandler): void; + offGameStarted(handler: GameStartedHandler): void; + onPlayerDrewCard(handler: PlayerDrewCardHandler): void; + offPlayerDrewCard(handler: PlayerDrewCardHandler): void; + onItsYourTurn(handler: ItsYourTurnHandler): void; + offItsYourTurn(handler: ItsYourTurnHandler): void; + onItsPlayersTurn(handler: ItsPlayersTurnHandler): void; + offItsPlayersTurn(handler: ItsPlayersTurnHandler): void; + onPlayerPassed(handler: PlayerPassedHandler): void; + offPlayerPassed(handler: PlayerPassedHandler): void; + onPlayerPutCard(handler: PlayerPutCardHandler): void; + offPlayerPutCard(handler: PlayerPutCardHandler): void; + onPlayerPutEight(handler: PlayerPutEightHandler): void; + offPlayerPutEight(handler: PlayerPutEightHandler): void; + onGameEnded(handler: GameEndedHandler): void; + offGameEnded(handler: GameEndedHandler): void; + onPlayerIsDone(handler: PlayerIsDoneHandler): void; + offPlayerIsDone(handler: PlayerIsDoneHandler): void; + onDiscardPileShuffled(handler: DiscardPileShuffledHandler): void; + offDiscardPileShuffled(handler: DiscardPileShuffledHandler): void; + + putCard(request: PutCardRequest): Promise; + putEight(request: PutEightRequest): Promise; + drawCard(request: DrawCardRequest): Promise; + pass(request: PassRequest): Promise; +} + +export class CrazyEightsClientImpl implements CrazyEightsClient { + private gameStartedHandlers: GameStartedHandler[] = []; + private playerDrewCardHandlers: PlayerDrewCardHandler[] = []; + private itsYourTurnHandlers: ItsYourTurnHandler[] = []; + private itsPlayersTurnHandlers: ItsPlayersTurnHandler[] = []; + private playerPassedHandlers: PlayerPassedHandler[] = []; + private playerPutCardHandlers: PlayerPutCardHandler[] = []; + private playerPutEightHandlers: PlayerPutEightHandler[] = []; + private gameEndedHandlers: GameEndedHandler[] = []; + private playerIsDoneHandlers: PlayerIsDoneHandler[] = []; + private discardPileShuffledHandlers: DiscardPileShuffledHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'GameStarted': + this.gameStartedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerDrewCard': + this.playerDrewCardHandlers.forEach(h => h(notification.data)); + break; + case 'ItsYourTurn': + this.itsYourTurnHandlers.forEach(h => h(notification.data)); + break; + case 'ItsPlayersTurn': + this.itsPlayersTurnHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPassed': + this.playerPassedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPutCard': + this.playerPutCardHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPutEight': + this.playerPutEightHandlers.forEach(h => h(notification.data)); + break; + case 'GameEnded': + this.gameEndedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerIsDone': + this.playerIsDoneHandlers.forEach(h => h(notification.data)); + break; + case 'DiscardPileShuffled': + this.discardPileShuffledHandlers.forEach(h => h(notification.data)); + break; + } + } + + onGameStarted(handler: GameStartedHandler): void { + this.gameStartedHandlers.push(handler); + } + + offGameStarted(handler: GameStartedHandler): void { + const index = this.gameStartedHandlers.indexOf(handler); + if (index > -1) { + this.gameStartedHandlers.splice(index, 1); + } + } + + onPlayerDrewCard(handler: PlayerDrewCardHandler): void { + this.playerDrewCardHandlers.push(handler); + } + + offPlayerDrewCard(handler: PlayerDrewCardHandler): void { + const index = this.playerDrewCardHandlers.indexOf(handler); + if (index > -1) { + this.playerDrewCardHandlers.splice(index, 1); + } + } + + onItsYourTurn(handler: ItsYourTurnHandler): void { + this.itsYourTurnHandlers.push(handler); + } + + offItsYourTurn(handler: ItsYourTurnHandler): void { + const index = this.itsYourTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsYourTurnHandlers.splice(index, 1); + } + } + + onItsPlayersTurn(handler: ItsPlayersTurnHandler): void { + this.itsPlayersTurnHandlers.push(handler); + } + + offItsPlayersTurn(handler: ItsPlayersTurnHandler): void { + const index = this.itsPlayersTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsPlayersTurnHandlers.splice(index, 1); + } + } + + onPlayerPassed(handler: PlayerPassedHandler): void { + this.playerPassedHandlers.push(handler); + } + + offPlayerPassed(handler: PlayerPassedHandler): void { + const index = this.playerPassedHandlers.indexOf(handler); + if (index > -1) { + this.playerPassedHandlers.splice(index, 1); + } + } + + onPlayerPutCard(handler: PlayerPutCardHandler): void { + this.playerPutCardHandlers.push(handler); + } + + offPlayerPutCard(handler: PlayerPutCardHandler): void { + const index = this.playerPutCardHandlers.indexOf(handler); + if (index > -1) { + this.playerPutCardHandlers.splice(index, 1); + } + } + + onPlayerPutEight(handler: PlayerPutEightHandler): void { + this.playerPutEightHandlers.push(handler); + } + + offPlayerPutEight(handler: PlayerPutEightHandler): void { + const index = this.playerPutEightHandlers.indexOf(handler); + if (index > -1) { + this.playerPutEightHandlers.splice(index, 1); + } + } + + onGameEnded(handler: GameEndedHandler): void { + this.gameEndedHandlers.push(handler); + } + + offGameEnded(handler: GameEndedHandler): void { + const index = this.gameEndedHandlers.indexOf(handler); + if (index > -1) { + this.gameEndedHandlers.splice(index, 1); + } + } + + onPlayerIsDone(handler: PlayerIsDoneHandler): void { + this.playerIsDoneHandlers.push(handler); + } + + offPlayerIsDone(handler: PlayerIsDoneHandler): void { + const index = this.playerIsDoneHandlers.indexOf(handler); + if (index > -1) { + this.playerIsDoneHandlers.splice(index, 1); + } + } + + onDiscardPileShuffled(handler: DiscardPileShuffledHandler): void { + this.discardPileShuffledHandlers.push(handler); + } + + offDiscardPileShuffled(handler: DiscardPileShuffledHandler): void { + const index = this.discardPileShuffledHandlers.indexOf(handler); + if (index > -1) { + this.discardPileShuffledHandlers.splice(index, 1); + } + } + + async putCard(request: PutCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async putEight(request: PutEightRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutEight', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async drawCard(request: DrawCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'DrawCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async pass(request: PassRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'Pass', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + +} diff --git a/generated/typescript/crazyeights/types.ts b/generated/typescript/crazyeights/types.ts new file mode 100644 index 00000000..8726583b --- /dev/null +++ b/generated/typescript/crazyeights/types.ts @@ -0,0 +1,144 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface GameStartedNotification { + gameId: string; + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface PlayerDrewCardNotification { + playerId: string; + type?: string; +} + +export interface ItsYourTurnNotification { + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface ItsPlayersTurnNotification { + playerId: string; + type?: string; +} + +export interface PlayerPassedNotification { + playerId: string; + type?: string; +} + +export interface PlayerPutCardNotification { + playerId: string; + card: Card; + type?: string; +} + +export interface Card { + rank: number; + suit: Suit; +} + +export enum Suit { + Clubs = 0, + Diamonds = 1, + Hearts = 2, + Spades = 3, +} + +export interface PlayerPutEightNotification { + playerId: string; + card: Card; + newSuit: Suit; + type?: string; +} + +export interface GameEndedNotification { + players?: PlayerData[]; + loserId: string; + loserName?: string; + type?: string; +} + +export interface PlayerData { + name?: string; + points: number; + cardsInHand: number; + id: string; + info?: Record; +} + +export interface Dictionary { + comparer?: IEqualityComparer; + count: number; + capacity: number; + keys?: KeyCollection; + values?: ValueCollection; +} + +export interface ValueCollection { + count: number; +} + +export interface KeyCollection { + count: number; +} + +export interface PlayerIsDoneNotification { + playerId: string; + type?: string; +} + +export interface DiscardPileShuffledNotification { + type?: string; +} + +export interface PutCardRequest { + card: Card; + playerId: string; + type?: string; +} + +export interface PlayerViewOfGame { + cards?: Card[]; + topOfPile: Card; + currentSuit: Suit; + stockPileCount: number; + discardPileCount: number; + otherPlayers?: OtherCrazyEightsPlayer[]; + hasError: boolean; + error?: string; + type?: string; +} + +export interface OtherCrazyEightsPlayer { + playerId: string; + name?: string; + numberOfCards: number; +} + +export interface PutEightRequest { + card: Card; + newSuit: Suit; + playerId: string; + type?: string; +} + +export interface DrawCardRequest { + playerId: string; + type?: string; +} + +export interface CardResponse { + card: Card; + hasError: boolean; + error?: string; + type?: string; +} + +export interface PassRequest { + playerId: string; + type?: string; +} + diff --git a/generated/typescript/gabong/GabongClient.ts b/generated/typescript/gabong/GabongClient.ts new file mode 100644 index 00000000..79ca681f --- /dev/null +++ b/generated/typescript/gabong/GabongClient.ts @@ -0,0 +1,312 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * Gabong Game Client + * + * Notifications (events) for this game: + * - GameStarted: GameStartedNotification + * - PlayerPutCard: PlayerPutCardNotification + * - PlayerDrewCard: PlayerDrewCardNotification + * - PlayerDrewPenaltyCard: PlayerDrewPenaltyCardNotification + * - GameEnded: GameEndedNotification + * - RoundStarted: RoundStartedNotification + * - RoundEnded: RoundEndedNotification + * - PlayerLostTheirTurn: PlayerLostTheirTurnNotification + */ + +import type { DrawCardRequest, GameEndedNotification, GameStartedNotification, PassRequest, PlayBongaRequest, PlayerDrewCardNotification, PlayerDrewPenaltyCardNotification, PlayerLostTheirTurnNotification, PlayerPutCardNotification, PlayerViewOfGame, PlayGabongRequest, PutCardRequest, RoundEndedNotification, RoundStartedNotification } from './types'; + +// Event handler types +export type GameStartedHandler = (data: GameStartedNotification) => void; +export type PlayerPutCardHandler = (data: PlayerPutCardNotification) => void; +export type PlayerDrewCardHandler = (data: PlayerDrewCardNotification) => void; +export type PlayerDrewPenaltyCardHandler = (data: PlayerDrewPenaltyCardNotification) => void; +export type GameEndedHandler = (data: GameEndedNotification) => void; +export type RoundStartedHandler = (data: RoundStartedNotification) => void; +export type RoundEndedHandler = (data: RoundEndedNotification) => void; +export type PlayerLostTheirTurnHandler = (data: PlayerLostTheirTurnNotification) => void; + +export interface GabongClient { + onGameStarted(handler: GameStartedHandler): void; + offGameStarted(handler: GameStartedHandler): void; + onPlayerPutCard(handler: PlayerPutCardHandler): void; + offPlayerPutCard(handler: PlayerPutCardHandler): void; + onPlayerDrewCard(handler: PlayerDrewCardHandler): void; + offPlayerDrewCard(handler: PlayerDrewCardHandler): void; + onPlayerDrewPenaltyCard(handler: PlayerDrewPenaltyCardHandler): void; + offPlayerDrewPenaltyCard(handler: PlayerDrewPenaltyCardHandler): void; + onGameEnded(handler: GameEndedHandler): void; + offGameEnded(handler: GameEndedHandler): void; + onRoundStarted(handler: RoundStartedHandler): void; + offRoundStarted(handler: RoundStartedHandler): void; + onRoundEnded(handler: RoundEndedHandler): void; + offRoundEnded(handler: RoundEndedHandler): void; + onPlayerLostTheirTurn(handler: PlayerLostTheirTurnHandler): void; + offPlayerLostTheirTurn(handler: PlayerLostTheirTurnHandler): void; + + drawCard(request: DrawCardRequest): Promise; + playGabong(request: PlayGabongRequest): Promise; + playBonga(request: PlayBongaRequest): Promise; + pass(request: PassRequest): Promise; + putCard(request: PutCardRequest): Promise; +} + +export class GabongClientImpl implements GabongClient { + private gameStartedHandlers: GameStartedHandler[] = []; + private playerPutCardHandlers: PlayerPutCardHandler[] = []; + private playerDrewCardHandlers: PlayerDrewCardHandler[] = []; + private playerDrewPenaltyCardHandlers: PlayerDrewPenaltyCardHandler[] = []; + private gameEndedHandlers: GameEndedHandler[] = []; + private roundStartedHandlers: RoundStartedHandler[] = []; + private roundEndedHandlers: RoundEndedHandler[] = []; + private playerLostTheirTurnHandlers: PlayerLostTheirTurnHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'GameStarted': + this.gameStartedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPutCard': + this.playerPutCardHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerDrewCard': + this.playerDrewCardHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerDrewPenaltyCard': + this.playerDrewPenaltyCardHandlers.forEach(h => h(notification.data)); + break; + case 'GameEnded': + this.gameEndedHandlers.forEach(h => h(notification.data)); + break; + case 'RoundStarted': + this.roundStartedHandlers.forEach(h => h(notification.data)); + break; + case 'RoundEnded': + this.roundEndedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerLostTheirTurn': + this.playerLostTheirTurnHandlers.forEach(h => h(notification.data)); + break; + } + } + + onGameStarted(handler: GameStartedHandler): void { + this.gameStartedHandlers.push(handler); + } + + offGameStarted(handler: GameStartedHandler): void { + const index = this.gameStartedHandlers.indexOf(handler); + if (index > -1) { + this.gameStartedHandlers.splice(index, 1); + } + } + + onPlayerPutCard(handler: PlayerPutCardHandler): void { + this.playerPutCardHandlers.push(handler); + } + + offPlayerPutCard(handler: PlayerPutCardHandler): void { + const index = this.playerPutCardHandlers.indexOf(handler); + if (index > -1) { + this.playerPutCardHandlers.splice(index, 1); + } + } + + onPlayerDrewCard(handler: PlayerDrewCardHandler): void { + this.playerDrewCardHandlers.push(handler); + } + + offPlayerDrewCard(handler: PlayerDrewCardHandler): void { + const index = this.playerDrewCardHandlers.indexOf(handler); + if (index > -1) { + this.playerDrewCardHandlers.splice(index, 1); + } + } + + onPlayerDrewPenaltyCard(handler: PlayerDrewPenaltyCardHandler): void { + this.playerDrewPenaltyCardHandlers.push(handler); + } + + offPlayerDrewPenaltyCard(handler: PlayerDrewPenaltyCardHandler): void { + const index = this.playerDrewPenaltyCardHandlers.indexOf(handler); + if (index > -1) { + this.playerDrewPenaltyCardHandlers.splice(index, 1); + } + } + + onGameEnded(handler: GameEndedHandler): void { + this.gameEndedHandlers.push(handler); + } + + offGameEnded(handler: GameEndedHandler): void { + const index = this.gameEndedHandlers.indexOf(handler); + if (index > -1) { + this.gameEndedHandlers.splice(index, 1); + } + } + + onRoundStarted(handler: RoundStartedHandler): void { + this.roundStartedHandlers.push(handler); + } + + offRoundStarted(handler: RoundStartedHandler): void { + const index = this.roundStartedHandlers.indexOf(handler); + if (index > -1) { + this.roundStartedHandlers.splice(index, 1); + } + } + + onRoundEnded(handler: RoundEndedHandler): void { + this.roundEndedHandlers.push(handler); + } + + offRoundEnded(handler: RoundEndedHandler): void { + const index = this.roundEndedHandlers.indexOf(handler); + if (index > -1) { + this.roundEndedHandlers.splice(index, 1); + } + } + + onPlayerLostTheirTurn(handler: PlayerLostTheirTurnHandler): void { + this.playerLostTheirTurnHandlers.push(handler); + } + + offPlayerLostTheirTurn(handler: PlayerLostTheirTurnHandler): void { + const index = this.playerLostTheirTurnHandlers.indexOf(handler); + if (index > -1) { + this.playerLostTheirTurnHandlers.splice(index, 1); + } + } + + async drawCard(request: DrawCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'DrawCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async playGabong(request: PlayGabongRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PlayGabong', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async playBonga(request: PlayBongaRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PlayBonga', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async pass(request: PassRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'Pass', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async putCard(request: PutCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + +} diff --git a/generated/typescript/gabong/types.ts b/generated/typescript/gabong/types.ts new file mode 100644 index 00000000..9c7b20e6 --- /dev/null +++ b/generated/typescript/gabong/types.ts @@ -0,0 +1,160 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface GameStartedNotification { + gameId: string; + type?: string; +} + +export interface PlayerPutCardNotification { + card: Card; + newSuit?: Suit; + playerId: string; + type?: string; +} + +export enum Suit { + Clubs = 0, + Diamonds = 1, + Hearts = 2, + Spades = 3, +} + +export interface Card { + rank: number; + suit: Suit; +} + +export interface PlayerDrewCardNotification { + playerId: string; + type?: string; +} + +export interface PlayerDrewPenaltyCardNotification { + penaltyReason: PenaltyReason; + playerId: string; + type?: string; +} + +export enum PenaltyReason { + PlayOutOfTurn = 0, + TookTooLong = 1, + WrongPlay = 2, + WrongGabong = 3, + WrongBonga = 4, + UnpaidDebt = 5, + PassWithoutDrawing = 6, +} + +export interface GameEndedNotification { + players?: PlayerData[]; + type?: string; +} + +export interface PlayerData { + name?: string; + points: number; + cardsInHand: number; + id: string; + info?: Record; +} + +export interface Dictionary { + comparer?: IEqualityComparer; + count: number; + capacity: number; + keys?: KeyCollection; + values?: ValueCollection; +} + +export interface ValueCollection { + count: number; +} + +export interface KeyCollection { + count: number; +} + +export interface RoundStartedNotification { + playerViewOfGame?: PlayerViewOfGame; + startingPlayerId: string; + type?: string; +} + +export interface RoundEndedNotification { + players?: PlayerData[]; + type?: string; +} + +export interface PlayerLostTheirTurnNotification { + lostTurnReason: PlayerLostTurnReason; + playerId: string; + type?: string; +} + +export enum PlayerLostTurnReason { + Passed = 0, + WrongPlay = 1, + TookTooLong = 2, + FinishedDrawingCardDebt = 3, +} + +export interface DrawCardRequest { + playerId: string; + type?: string; +} + +export interface PlayerViewOfGame { + cards?: Card[]; + topOfPile: Card; + currentSuit: Suit; + stockPileCount: number; + discardPileCount: number; + roundStarted: boolean; + lastPlayMadeByPlayerId: string; + lastPlay: GabongPlay; + players?: SlimGabongPlayer[]; + playersOrder?: string[]; + cardDebtToDraw: number; + cardsAdded?: Card[]; + hasError: boolean; + error?: string; + type?: string; +} + +export interface SlimGabongPlayer { + id: string; + name?: string; + numberOfCards: number; +} + +export enum GabongPlay { + CardPlayed = 0, + TurnLost = 1, + RoundStarted = 2, +} + +export interface PlayGabongRequest { + playerId: string; + type?: string; +} + +export interface PlayBongaRequest { + playerId: string; + type?: string; +} + +export interface PassRequest { + playerId: string; + type?: string; +} + +export interface PutCardRequest { + card: Card; + newSuit?: Suit; + playerId: string; + type?: string; +} + diff --git a/generated/typescript/hearts/HeartsClient.ts b/generated/typescript/hearts/HeartsClient.ts new file mode 100644 index 00000000..2b7126be --- /dev/null +++ b/generated/typescript/hearts/HeartsClient.ts @@ -0,0 +1,294 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * Hearts Game Client + * + * Notifications (events) for this game: + * - GameStarted: GameStartedNotification + * - PassingPhaseStarted: PassingPhaseStartedNotification + * - AllPlayersPassed: AllPlayersPassedNotification + * - PlayerPassedCards: PlayerPassedCardsNotification + * - ItsYourTurn: ItsYourTurnNotification + * - ItsPlayersTurn: ItsPlayersTurnNotification + * - PlayerPlayedCard: PlayerPlayedCardNotification + * - TrickCompleted: TrickCompletedNotification + * - RoundEnded: RoundEndedNotification + * - GameEnded: GameEndedNotification + * - HeartsWereBroken: HeartsAreBrokenNotification + */ + +import type { AllPlayersPassedNotification, GameEndedNotification, GameStartedNotification, HeartsAreBrokenNotification, ItsPlayersTurnNotification, ItsYourTurnNotification, PassCardsRequest, PassCardsResponse, PassingPhaseStartedNotification, PlayCardRequest, PlayerPassedCardsNotification, PlayerPlayedCardNotification, PlayerViewOfGame, RoundEndedNotification, TrickCompletedNotification } from './types'; + +// Event handler types +export type GameStartedHandler = (data: GameStartedNotification) => void; +export type PassingPhaseStartedHandler = (data: PassingPhaseStartedNotification) => void; +export type AllPlayersPassedHandler = (data: AllPlayersPassedNotification) => void; +export type PlayerPassedCardsHandler = (data: PlayerPassedCardsNotification) => void; +export type ItsYourTurnHandler = (data: ItsYourTurnNotification) => void; +export type ItsPlayersTurnHandler = (data: ItsPlayersTurnNotification) => void; +export type PlayerPlayedCardHandler = (data: PlayerPlayedCardNotification) => void; +export type TrickCompletedHandler = (data: TrickCompletedNotification) => void; +export type RoundEndedHandler = (data: RoundEndedNotification) => void; +export type GameEndedHandler = (data: GameEndedNotification) => void; +export type HeartsWereBrokenHandler = (data: HeartsAreBrokenNotification) => void; + +export interface HeartsClient { + onGameStarted(handler: GameStartedHandler): void; + offGameStarted(handler: GameStartedHandler): void; + onPassingPhaseStarted(handler: PassingPhaseStartedHandler): void; + offPassingPhaseStarted(handler: PassingPhaseStartedHandler): void; + onAllPlayersPassed(handler: AllPlayersPassedHandler): void; + offAllPlayersPassed(handler: AllPlayersPassedHandler): void; + onPlayerPassedCards(handler: PlayerPassedCardsHandler): void; + offPlayerPassedCards(handler: PlayerPassedCardsHandler): void; + onItsYourTurn(handler: ItsYourTurnHandler): void; + offItsYourTurn(handler: ItsYourTurnHandler): void; + onItsPlayersTurn(handler: ItsPlayersTurnHandler): void; + offItsPlayersTurn(handler: ItsPlayersTurnHandler): void; + onPlayerPlayedCard(handler: PlayerPlayedCardHandler): void; + offPlayerPlayedCard(handler: PlayerPlayedCardHandler): void; + onTrickCompleted(handler: TrickCompletedHandler): void; + offTrickCompleted(handler: TrickCompletedHandler): void; + onRoundEnded(handler: RoundEndedHandler): void; + offRoundEnded(handler: RoundEndedHandler): void; + onGameEnded(handler: GameEndedHandler): void; + offGameEnded(handler: GameEndedHandler): void; + onHeartsWereBroken(handler: HeartsWereBrokenHandler): void; + offHeartsWereBroken(handler: HeartsWereBrokenHandler): void; + + passCards(request: PassCardsRequest): Promise; + playCard(request: PlayCardRequest): Promise; +} + +export class HeartsClientImpl implements HeartsClient { + private gameStartedHandlers: GameStartedHandler[] = []; + private passingPhaseStartedHandlers: PassingPhaseStartedHandler[] = []; + private allPlayersPassedHandlers: AllPlayersPassedHandler[] = []; + private playerPassedCardsHandlers: PlayerPassedCardsHandler[] = []; + private itsYourTurnHandlers: ItsYourTurnHandler[] = []; + private itsPlayersTurnHandlers: ItsPlayersTurnHandler[] = []; + private playerPlayedCardHandlers: PlayerPlayedCardHandler[] = []; + private trickCompletedHandlers: TrickCompletedHandler[] = []; + private roundEndedHandlers: RoundEndedHandler[] = []; + private gameEndedHandlers: GameEndedHandler[] = []; + private heartsWereBrokenHandlers: HeartsWereBrokenHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'GameStarted': + this.gameStartedHandlers.forEach(h => h(notification.data)); + break; + case 'PassingPhaseStarted': + this.passingPhaseStartedHandlers.forEach(h => h(notification.data)); + break; + case 'AllPlayersPassed': + this.allPlayersPassedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPassedCards': + this.playerPassedCardsHandlers.forEach(h => h(notification.data)); + break; + case 'ItsYourTurn': + this.itsYourTurnHandlers.forEach(h => h(notification.data)); + break; + case 'ItsPlayersTurn': + this.itsPlayersTurnHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPlayedCard': + this.playerPlayedCardHandlers.forEach(h => h(notification.data)); + break; + case 'TrickCompleted': + this.trickCompletedHandlers.forEach(h => h(notification.data)); + break; + case 'RoundEnded': + this.roundEndedHandlers.forEach(h => h(notification.data)); + break; + case 'GameEnded': + this.gameEndedHandlers.forEach(h => h(notification.data)); + break; + case 'HeartsWereBroken': + this.heartsWereBrokenHandlers.forEach(h => h(notification.data)); + break; + } + } + + onGameStarted(handler: GameStartedHandler): void { + this.gameStartedHandlers.push(handler); + } + + offGameStarted(handler: GameStartedHandler): void { + const index = this.gameStartedHandlers.indexOf(handler); + if (index > -1) { + this.gameStartedHandlers.splice(index, 1); + } + } + + onPassingPhaseStarted(handler: PassingPhaseStartedHandler): void { + this.passingPhaseStartedHandlers.push(handler); + } + + offPassingPhaseStarted(handler: PassingPhaseStartedHandler): void { + const index = this.passingPhaseStartedHandlers.indexOf(handler); + if (index > -1) { + this.passingPhaseStartedHandlers.splice(index, 1); + } + } + + onAllPlayersPassed(handler: AllPlayersPassedHandler): void { + this.allPlayersPassedHandlers.push(handler); + } + + offAllPlayersPassed(handler: AllPlayersPassedHandler): void { + const index = this.allPlayersPassedHandlers.indexOf(handler); + if (index > -1) { + this.allPlayersPassedHandlers.splice(index, 1); + } + } + + onPlayerPassedCards(handler: PlayerPassedCardsHandler): void { + this.playerPassedCardsHandlers.push(handler); + } + + offPlayerPassedCards(handler: PlayerPassedCardsHandler): void { + const index = this.playerPassedCardsHandlers.indexOf(handler); + if (index > -1) { + this.playerPassedCardsHandlers.splice(index, 1); + } + } + + onItsYourTurn(handler: ItsYourTurnHandler): void { + this.itsYourTurnHandlers.push(handler); + } + + offItsYourTurn(handler: ItsYourTurnHandler): void { + const index = this.itsYourTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsYourTurnHandlers.splice(index, 1); + } + } + + onItsPlayersTurn(handler: ItsPlayersTurnHandler): void { + this.itsPlayersTurnHandlers.push(handler); + } + + offItsPlayersTurn(handler: ItsPlayersTurnHandler): void { + const index = this.itsPlayersTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsPlayersTurnHandlers.splice(index, 1); + } + } + + onPlayerPlayedCard(handler: PlayerPlayedCardHandler): void { + this.playerPlayedCardHandlers.push(handler); + } + + offPlayerPlayedCard(handler: PlayerPlayedCardHandler): void { + const index = this.playerPlayedCardHandlers.indexOf(handler); + if (index > -1) { + this.playerPlayedCardHandlers.splice(index, 1); + } + } + + onTrickCompleted(handler: TrickCompletedHandler): void { + this.trickCompletedHandlers.push(handler); + } + + offTrickCompleted(handler: TrickCompletedHandler): void { + const index = this.trickCompletedHandlers.indexOf(handler); + if (index > -1) { + this.trickCompletedHandlers.splice(index, 1); + } + } + + onRoundEnded(handler: RoundEndedHandler): void { + this.roundEndedHandlers.push(handler); + } + + offRoundEnded(handler: RoundEndedHandler): void { + const index = this.roundEndedHandlers.indexOf(handler); + if (index > -1) { + this.roundEndedHandlers.splice(index, 1); + } + } + + onGameEnded(handler: GameEndedHandler): void { + this.gameEndedHandlers.push(handler); + } + + offGameEnded(handler: GameEndedHandler): void { + const index = this.gameEndedHandlers.indexOf(handler); + if (index > -1) { + this.gameEndedHandlers.splice(index, 1); + } + } + + onHeartsWereBroken(handler: HeartsWereBrokenHandler): void { + this.heartsWereBrokenHandlers.push(handler); + } + + offHeartsWereBroken(handler: HeartsWereBrokenHandler): void { + const index = this.heartsWereBrokenHandlers.indexOf(handler); + if (index > -1) { + this.heartsWereBrokenHandlers.splice(index, 1); + } + } + + async passCards(request: PassCardsRequest): Promise { + return new Promise((resolve, reject) => { + const requestPayload = { + type: 'PassCards', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(requestPayload)); + }); + } + + async playCard(request: PlayCardRequest): Promise { + return new Promise((resolve, reject) => { + const requestPayload = { + type: 'PlayCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(requestPayload)); + }); + } + +} diff --git a/generated/typescript/hearts/types.ts b/generated/typescript/hearts/types.ts new file mode 100644 index 00000000..fafd9370 --- /dev/null +++ b/generated/typescript/hearts/types.ts @@ -0,0 +1,144 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface GameStartedNotification { + gameId: string; + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface PassingPhaseStartedNotification { + passDirection: PassDirection; + type?: string; +} + +export enum PassDirection { + None = 0, + Left = 1, + Right = 2, + Across = 3, +} + +export interface AllPlayersPassedNotification { + receivedCards?: Card[]; + type?: string; +} + +export interface Card { + rank: number; + suit: Suit; +} + +export enum Suit { + Clubs = 0, + Diamonds = 1, + Hearts = 2, + Spades = 3, +} + +export interface PlayerPassedCardsNotification { + playerId: string; + type?: string; +} + +export interface ItsYourTurnNotification { + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface ItsPlayersTurnNotification { + playerId: string; + type?: string; +} + +export interface PlayerPlayedCardNotification { + playerId: string; + card: Card; + type?: string; +} + +export interface TrickCompletedNotification { + winnerId: string; + winnerName?: string; + trickCards?: CardPlay[]; + points: number; + type?: string; +} + +export interface CardPlay { + playerId: string; + playerName?: string; + card: Card; +} + +export interface RoundEndedNotification { + scores?: PlayerScore[]; + moonShooterId?: string; + moonShooterName?: string; + type?: string; +} + +export interface PlayerScore { + playerId: string; + playerName?: string; + roundScore: number; + totalScore: number; +} + +export interface GameEndedNotification { + finalScores?: PlayerScore[]; + winnerId: string; + winnerName?: string; + type?: string; +} + +export interface HeartsAreBrokenNotification { + type?: string; +} + +export interface PassCardsRequest { + cards?: Card[]; + playerId: string; + type?: string; +} + +export interface PassCardsResponse { + receivedCards?: Card[]; + hasError: boolean; + error?: string; + type?: string; +} + +export interface PlayCardRequest { + card: Card; + playerId: string; + type?: string; +} + +export interface PlayerViewOfGame { + cards?: Card[]; + otherPlayers?: OtherHeartsPlayer[]; + roundNumber: number; + passDirection: PassDirection; + hasPassed: boolean; + currentTrick?: CardPlay[]; + totalScore: number; + roundScore: number; + heartsAreBroken: boolean; + isMyTurn: boolean; + hasError: boolean; + error?: string; + type?: string; +} + +export interface OtherHeartsPlayer { + playerId: string; + name?: string; + numberOfCards: number; + totalScore: number; + roundScore: number; + playedCard?: Card; +} + diff --git a/generated/typescript/idiot/IdiotClient.ts b/generated/typescript/idiot/IdiotClient.ts new file mode 100644 index 00000000..f38896a6 --- /dev/null +++ b/generated/typescript/idiot/IdiotClient.ts @@ -0,0 +1,439 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * Idiot Game Client + * + * Notifications (events) for this game: + * - ItsTimeToSwapCards: ItsTimeToSwapCardsNotification + * - PlayerIsReady: PlayerIsReadyNotification + * - GameHasStarted: GameStartedNotification + * - GameEnded: GameEndedNotification + * - ItsYourTurn: ItsYourTurnNotification + * - PlayerDrewCards: PlayerDrewCardsNotification + * - PlayerPutCards: PlayerPutCardsNotification + * - DiscardPileFlushed: DiscardPileFlushedNotification + * - PlayerIsDone: PlayerIsDoneNotification + * - PlayerSwappedCards: PlayerSwappedCardsNotification + * - PlayerAttemptedPuttingCard: PlayerAttemptedPuttingCardNotification + * - PlayerPulledInDiscardPile: PlayerPulledInDiscardPileNotification + */ + +import type { EmptyResponse } from '../types'; +import type { DiscardPileFlushedNotification, DrawCardsResponse, GameEndedNotification, GameStartedNotification, IamReadyRequest, ItsTimeToSwapCardsNotification, ItsYourTurnNotification, PlayerAttemptedPuttingCardNotification, PlayerDrewCardsNotification, PlayerIsDoneNotification, PlayerIsReadyNotification, PlayerPulledInDiscardPileNotification, PlayerPutCardsNotification, PlayerSwappedCardsNotification, PullInDiscardPileRequest, PullInResponse, PutBlindCardResponse, PutCardFacingDownRequest, PutCardsFacingUpRequest, PutCardsFromHandRequest, PutChanceCardRequest, SwapCardsRequest, SwapCardsResponse } from './types'; + +// Event handler types +export type ItsTimeToSwapCardsHandler = (data: ItsTimeToSwapCardsNotification) => void; +export type PlayerIsReadyHandler = (data: PlayerIsReadyNotification) => void; +export type GameHasStartedHandler = (data: GameStartedNotification) => void; +export type GameEndedHandler = (data: GameEndedNotification) => void; +export type ItsYourTurnHandler = (data: ItsYourTurnNotification) => void; +export type PlayerDrewCardsHandler = (data: PlayerDrewCardsNotification) => void; +export type PlayerPutCardsHandler = (data: PlayerPutCardsNotification) => void; +export type DiscardPileFlushedHandler = (data: DiscardPileFlushedNotification) => void; +export type PlayerIsDoneHandler = (data: PlayerIsDoneNotification) => void; +export type PlayerSwappedCardsHandler = (data: PlayerSwappedCardsNotification) => void; +export type PlayerAttemptedPuttingCardHandler = (data: PlayerAttemptedPuttingCardNotification) => void; +export type PlayerPulledInDiscardPileHandler = (data: PlayerPulledInDiscardPileNotification) => void; + +export interface IdiotClient { + onItsTimeToSwapCards(handler: ItsTimeToSwapCardsHandler): void; + offItsTimeToSwapCards(handler: ItsTimeToSwapCardsHandler): void; + onPlayerIsReady(handler: PlayerIsReadyHandler): void; + offPlayerIsReady(handler: PlayerIsReadyHandler): void; + onGameHasStarted(handler: GameHasStartedHandler): void; + offGameHasStarted(handler: GameHasStartedHandler): void; + onGameEnded(handler: GameEndedHandler): void; + offGameEnded(handler: GameEndedHandler): void; + onItsYourTurn(handler: ItsYourTurnHandler): void; + offItsYourTurn(handler: ItsYourTurnHandler): void; + onPlayerDrewCards(handler: PlayerDrewCardsHandler): void; + offPlayerDrewCards(handler: PlayerDrewCardsHandler): void; + onPlayerPutCards(handler: PlayerPutCardsHandler): void; + offPlayerPutCards(handler: PlayerPutCardsHandler): void; + onDiscardPileFlushed(handler: DiscardPileFlushedHandler): void; + offDiscardPileFlushed(handler: DiscardPileFlushedHandler): void; + onPlayerIsDone(handler: PlayerIsDoneHandler): void; + offPlayerIsDone(handler: PlayerIsDoneHandler): void; + onPlayerSwappedCards(handler: PlayerSwappedCardsHandler): void; + offPlayerSwappedCards(handler: PlayerSwappedCardsHandler): void; + onPlayerAttemptedPuttingCard(handler: PlayerAttemptedPuttingCardHandler): void; + offPlayerAttemptedPuttingCard(handler: PlayerAttemptedPuttingCardHandler): void; + onPlayerPulledInDiscardPile(handler: PlayerPulledInDiscardPileHandler): void; + offPlayerPulledInDiscardPile(handler: PlayerPulledInDiscardPileHandler): void; + + iamReady(request: IamReadyRequest): Promise; + swapCards(request: SwapCardsRequest): Promise; + putCardsFromHand(request: PutCardsFromHandRequest): Promise; + putCardsFacingUp(request: PutCardsFacingUpRequest): Promise; + putCardFacingDown(request: PutCardFacingDownRequest): Promise; + putChanceCard(request: PutChanceCardRequest): Promise; + pullInDiscardPile(request: PullInDiscardPileRequest): Promise; +} + +export class IdiotClientImpl implements IdiotClient { + private itsTimeToSwapCardsHandlers: ItsTimeToSwapCardsHandler[] = []; + private playerIsReadyHandlers: PlayerIsReadyHandler[] = []; + private gameHasStartedHandlers: GameHasStartedHandler[] = []; + private gameEndedHandlers: GameEndedHandler[] = []; + private itsYourTurnHandlers: ItsYourTurnHandler[] = []; + private playerDrewCardsHandlers: PlayerDrewCardsHandler[] = []; + private playerPutCardsHandlers: PlayerPutCardsHandler[] = []; + private discardPileFlushedHandlers: DiscardPileFlushedHandler[] = []; + private playerIsDoneHandlers: PlayerIsDoneHandler[] = []; + private playerSwappedCardsHandlers: PlayerSwappedCardsHandler[] = []; + private playerAttemptedPuttingCardHandlers: PlayerAttemptedPuttingCardHandler[] = []; + private playerPulledInDiscardPileHandlers: PlayerPulledInDiscardPileHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'ItsTimeToSwapCards': + this.itsTimeToSwapCardsHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerIsReady': + this.playerIsReadyHandlers.forEach(h => h(notification.data)); + break; + case 'GameHasStarted': + this.gameHasStartedHandlers.forEach(h => h(notification.data)); + break; + case 'GameEnded': + this.gameEndedHandlers.forEach(h => h(notification.data)); + break; + case 'ItsYourTurn': + this.itsYourTurnHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerDrewCards': + this.playerDrewCardsHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPutCards': + this.playerPutCardsHandlers.forEach(h => h(notification.data)); + break; + case 'DiscardPileFlushed': + this.discardPileFlushedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerIsDone': + this.playerIsDoneHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerSwappedCards': + this.playerSwappedCardsHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerAttemptedPuttingCard': + this.playerAttemptedPuttingCardHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPulledInDiscardPile': + this.playerPulledInDiscardPileHandlers.forEach(h => h(notification.data)); + break; + } + } + + onItsTimeToSwapCards(handler: ItsTimeToSwapCardsHandler): void { + this.itsTimeToSwapCardsHandlers.push(handler); + } + + offItsTimeToSwapCards(handler: ItsTimeToSwapCardsHandler): void { + const index = this.itsTimeToSwapCardsHandlers.indexOf(handler); + if (index > -1) { + this.itsTimeToSwapCardsHandlers.splice(index, 1); + } + } + + onPlayerIsReady(handler: PlayerIsReadyHandler): void { + this.playerIsReadyHandlers.push(handler); + } + + offPlayerIsReady(handler: PlayerIsReadyHandler): void { + const index = this.playerIsReadyHandlers.indexOf(handler); + if (index > -1) { + this.playerIsReadyHandlers.splice(index, 1); + } + } + + onGameHasStarted(handler: GameHasStartedHandler): void { + this.gameHasStartedHandlers.push(handler); + } + + offGameHasStarted(handler: GameHasStartedHandler): void { + const index = this.gameHasStartedHandlers.indexOf(handler); + if (index > -1) { + this.gameHasStartedHandlers.splice(index, 1); + } + } + + onGameEnded(handler: GameEndedHandler): void { + this.gameEndedHandlers.push(handler); + } + + offGameEnded(handler: GameEndedHandler): void { + const index = this.gameEndedHandlers.indexOf(handler); + if (index > -1) { + this.gameEndedHandlers.splice(index, 1); + } + } + + onItsYourTurn(handler: ItsYourTurnHandler): void { + this.itsYourTurnHandlers.push(handler); + } + + offItsYourTurn(handler: ItsYourTurnHandler): void { + const index = this.itsYourTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsYourTurnHandlers.splice(index, 1); + } + } + + onPlayerDrewCards(handler: PlayerDrewCardsHandler): void { + this.playerDrewCardsHandlers.push(handler); + } + + offPlayerDrewCards(handler: PlayerDrewCardsHandler): void { + const index = this.playerDrewCardsHandlers.indexOf(handler); + if (index > -1) { + this.playerDrewCardsHandlers.splice(index, 1); + } + } + + onPlayerPutCards(handler: PlayerPutCardsHandler): void { + this.playerPutCardsHandlers.push(handler); + } + + offPlayerPutCards(handler: PlayerPutCardsHandler): void { + const index = this.playerPutCardsHandlers.indexOf(handler); + if (index > -1) { + this.playerPutCardsHandlers.splice(index, 1); + } + } + + onDiscardPileFlushed(handler: DiscardPileFlushedHandler): void { + this.discardPileFlushedHandlers.push(handler); + } + + offDiscardPileFlushed(handler: DiscardPileFlushedHandler): void { + const index = this.discardPileFlushedHandlers.indexOf(handler); + if (index > -1) { + this.discardPileFlushedHandlers.splice(index, 1); + } + } + + onPlayerIsDone(handler: PlayerIsDoneHandler): void { + this.playerIsDoneHandlers.push(handler); + } + + offPlayerIsDone(handler: PlayerIsDoneHandler): void { + const index = this.playerIsDoneHandlers.indexOf(handler); + if (index > -1) { + this.playerIsDoneHandlers.splice(index, 1); + } + } + + onPlayerSwappedCards(handler: PlayerSwappedCardsHandler): void { + this.playerSwappedCardsHandlers.push(handler); + } + + offPlayerSwappedCards(handler: PlayerSwappedCardsHandler): void { + const index = this.playerSwappedCardsHandlers.indexOf(handler); + if (index > -1) { + this.playerSwappedCardsHandlers.splice(index, 1); + } + } + + onPlayerAttemptedPuttingCard(handler: PlayerAttemptedPuttingCardHandler): void { + this.playerAttemptedPuttingCardHandlers.push(handler); + } + + offPlayerAttemptedPuttingCard(handler: PlayerAttemptedPuttingCardHandler): void { + const index = this.playerAttemptedPuttingCardHandlers.indexOf(handler); + if (index > -1) { + this.playerAttemptedPuttingCardHandlers.splice(index, 1); + } + } + + onPlayerPulledInDiscardPile(handler: PlayerPulledInDiscardPileHandler): void { + this.playerPulledInDiscardPileHandlers.push(handler); + } + + offPlayerPulledInDiscardPile(handler: PlayerPulledInDiscardPileHandler): void { + const index = this.playerPulledInDiscardPileHandlers.indexOf(handler); + if (index > -1) { + this.playerPulledInDiscardPileHandlers.splice(index, 1); + } + } + + async iamReady(request: IamReadyRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'IamReady', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async swapCards(request: SwapCardsRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'SwapCards', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async putCardsFromHand(request: PutCardsFromHandRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutCardsFromHand', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async putCardsFacingUp(request: PutCardsFacingUpRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutCardsFacingUp', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async putCardFacingDown(request: PutCardFacingDownRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutCardFacingDown', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async putChanceCard(request: PutChanceCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutChanceCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async pullInDiscardPile(request: PullInDiscardPileRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PullInDiscardPile', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + +} diff --git a/generated/typescript/idiot/types.ts b/generated/typescript/idiot/types.ts new file mode 100644 index 00000000..90d4bed1 --- /dev/null +++ b/generated/typescript/idiot/types.ts @@ -0,0 +1,173 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface ItsTimeToSwapCardsNotification { + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface PlayerViewOfGame { + cardsOnHand?: Card[]; + cardsFacingUp?: Card[]; + stockPileCount: number; + otherPlayers?: OtherIdiotPlayer[]; + cardsFacingDownCount: number; +} + +export interface Card { + rank: number; + suit: Suit; +} + +export enum Suit { + Clubs = 0, + Diamonds = 1, + Hearts = 2, + Spades = 3, +} + +export interface PlayerIsReadyNotification { + playerId: string; + type?: string; +} + +export interface GameStartedNotification { + type?: string; +} + +export interface GameEndedNotification { + loserId: string; + type?: string; +} + +export interface ItsYourTurnNotification { + type?: string; +} + +export interface PlayerDrewCardsNotification { + playerId: string; + numberOfCards: number; + type?: string; +} + +export interface PlayerPutCardsNotification { + playerId: string; + cards?: Card[]; + from: PutCardFrom; + type?: string; +} + +export enum PutCardFrom { + Hand = 0, + FacingUp = 1, + FacingDown = 2, +} + +export interface DiscardPileFlushedNotification { + playerId: string; + type?: string; +} + +export interface PlayerIsDoneNotification { + playerId: string; + type?: string; +} + +export interface PlayerSwappedCardsNotification { + playerId: string; + cardNowOnHand: Card; + cardNowFacingUp: Card; + type?: string; +} + +export interface PlayerAttemptedPuttingCardNotification { + playerId: string; + card: Card; + type?: string; +} + +export interface PlayerPulledInDiscardPileNotification { + playerId: string; + type?: string; +} + +export interface IamReadyRequest { + playerId: string; + type?: string; +} + +export interface SwapCardsRequest { + cardOnHand: Card; + cardFacingUp: Card; + playerId: string; + type?: string; +} + +export interface SwapCardsResponse { + cardNowOnHand: Card; + cardNowFacingUp: Card; + hasError: boolean; + error?: string; + type?: string; +} + +export interface PutCardsFromHandRequest { + cards?: Card[]; + playerId: string; + type?: string; +} + +export interface DrawCardsResponse { + cards?: Card[]; + hasError: boolean; + error?: string; + type?: string; +} + +export interface PutCardsFacingUpRequest { + cards?: Card[]; + playerId: string; + type?: string; +} + +export interface PutCardFacingDownRequest { + index: number; + playerId: string; + type?: string; +} + +export interface PutBlindCardResponse { + attemptedCard: Card; + pullInCards?: Card[]; + hasError: boolean; + error?: string; + type?: string; +} + +export interface PutChanceCardRequest { + playerId: string; + type?: string; +} + +export interface PullInDiscardPileRequest { + playerId: string; + type?: string; +} + +export interface PullInResponse { + cards?: Card[]; + hasError: boolean; + error?: string; + type?: string; +} + +export interface OtherIdiotPlayer { + id: string; + name?: string; + cardsOnHandCount: number; + cardsFacingUp?: Card[]; + cardsFacingDownCount: number; +} + diff --git a/generated/typescript/texasholdem/TexasHoldEmClient.ts b/generated/typescript/texasholdem/TexasHoldEmClient.ts new file mode 100644 index 00000000..39498c2a --- /dev/null +++ b/generated/typescript/texasholdem/TexasHoldEmClient.ts @@ -0,0 +1,344 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * TexasHoldEm Game Client + * + * Notifications (events) for this game: + * - GameStarted: GameStartedNotification + * - ItsYourTurn: ItsYourTurnNotification + * - RoundStarted: NewRoundStartedNotification + * - RoundEnded: RoundEndedNotification + * - PlayerBetted: PlayerBettedNotification + * - PlayerAllIn: PlayerAllInNotification + * - PlayerChecked: PlayerCheckedNotification + * - PlayerFolded: PlayerFoldedNotification + * - PlayerCalled: PlayerCalledNotification + * - NewCardsRevealed: NewCardsRevealed + * - GameEnded: GameEndedNotification + */ + +import type { BetRequest, CallRequest, CheckRequest, FoldRequest, GameEndedNotification, GameStartedNotification, ItsYourTurnNotification, NewCardsRevealed, NewRoundStartedNotification, PlayerAllInNotification, PlayerBettedNotification, PlayerCalledNotification, PlayerCheckedNotification, PlayerFoldedNotification, PlayerViewOfGame, RoundEndedNotification } from './types'; + +// Event handler types +export type GameStartedHandler = (data: GameStartedNotification) => void; +export type ItsYourTurnHandler = (data: ItsYourTurnNotification) => void; +export type RoundStartedHandler = (data: NewRoundStartedNotification) => void; +export type RoundEndedHandler = (data: RoundEndedNotification) => void; +export type PlayerBettedHandler = (data: PlayerBettedNotification) => void; +export type PlayerAllInHandler = (data: PlayerAllInNotification) => void; +export type PlayerCheckedHandler = (data: PlayerCheckedNotification) => void; +export type PlayerFoldedHandler = (data: PlayerFoldedNotification) => void; +export type PlayerCalledHandler = (data: PlayerCalledNotification) => void; +export type NewCardsRevealedHandler = (data: NewCardsRevealed) => void; +export type GameEndedHandler = (data: GameEndedNotification) => void; + +export interface TexasHoldEmClient { + onGameStarted(handler: GameStartedHandler): void; + offGameStarted(handler: GameStartedHandler): void; + onItsYourTurn(handler: ItsYourTurnHandler): void; + offItsYourTurn(handler: ItsYourTurnHandler): void; + onRoundStarted(handler: RoundStartedHandler): void; + offRoundStarted(handler: RoundStartedHandler): void; + onRoundEnded(handler: RoundEndedHandler): void; + offRoundEnded(handler: RoundEndedHandler): void; + onPlayerBetted(handler: PlayerBettedHandler): void; + offPlayerBetted(handler: PlayerBettedHandler): void; + onPlayerAllIn(handler: PlayerAllInHandler): void; + offPlayerAllIn(handler: PlayerAllInHandler): void; + onPlayerChecked(handler: PlayerCheckedHandler): void; + offPlayerChecked(handler: PlayerCheckedHandler): void; + onPlayerFolded(handler: PlayerFoldedHandler): void; + offPlayerFolded(handler: PlayerFoldedHandler): void; + onPlayerCalled(handler: PlayerCalledHandler): void; + offPlayerCalled(handler: PlayerCalledHandler): void; + onNewCardsRevealed(handler: NewCardsRevealedHandler): void; + offNewCardsRevealed(handler: NewCardsRevealedHandler): void; + onGameEnded(handler: GameEndedHandler): void; + offGameEnded(handler: GameEndedHandler): void; + + playerBetRequest(request: BetRequest): Promise; + playerFoldRequest(request: FoldRequest): Promise; + playerCheckRequest(request: CheckRequest): Promise; + playerCallRequest(request: CallRequest): Promise; +} + +export class TexasHoldEmClientImpl implements TexasHoldEmClient { + private gameStartedHandlers: GameStartedHandler[] = []; + private itsYourTurnHandlers: ItsYourTurnHandler[] = []; + private roundStartedHandlers: RoundStartedHandler[] = []; + private roundEndedHandlers: RoundEndedHandler[] = []; + private playerBettedHandlers: PlayerBettedHandler[] = []; + private playerAllInHandlers: PlayerAllInHandler[] = []; + private playerCheckedHandlers: PlayerCheckedHandler[] = []; + private playerFoldedHandlers: PlayerFoldedHandler[] = []; + private playerCalledHandlers: PlayerCalledHandler[] = []; + private newCardsRevealedHandlers: NewCardsRevealedHandler[] = []; + private gameEndedHandlers: GameEndedHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'GameStarted': + this.gameStartedHandlers.forEach(h => h(notification.data)); + break; + case 'ItsYourTurn': + this.itsYourTurnHandlers.forEach(h => h(notification.data)); + break; + case 'RoundStarted': + this.roundStartedHandlers.forEach(h => h(notification.data)); + break; + case 'RoundEnded': + this.roundEndedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerBetted': + this.playerBettedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerAllIn': + this.playerAllInHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerChecked': + this.playerCheckedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerFolded': + this.playerFoldedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerCalled': + this.playerCalledHandlers.forEach(h => h(notification.data)); + break; + case 'NewCardsRevealed': + this.newCardsRevealedHandlers.forEach(h => h(notification.data)); + break; + case 'GameEnded': + this.gameEndedHandlers.forEach(h => h(notification.data)); + break; + } + } + + onGameStarted(handler: GameStartedHandler): void { + this.gameStartedHandlers.push(handler); + } + + offGameStarted(handler: GameStartedHandler): void { + const index = this.gameStartedHandlers.indexOf(handler); + if (index > -1) { + this.gameStartedHandlers.splice(index, 1); + } + } + + onItsYourTurn(handler: ItsYourTurnHandler): void { + this.itsYourTurnHandlers.push(handler); + } + + offItsYourTurn(handler: ItsYourTurnHandler): void { + const index = this.itsYourTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsYourTurnHandlers.splice(index, 1); + } + } + + onRoundStarted(handler: RoundStartedHandler): void { + this.roundStartedHandlers.push(handler); + } + + offRoundStarted(handler: RoundStartedHandler): void { + const index = this.roundStartedHandlers.indexOf(handler); + if (index > -1) { + this.roundStartedHandlers.splice(index, 1); + } + } + + onRoundEnded(handler: RoundEndedHandler): void { + this.roundEndedHandlers.push(handler); + } + + offRoundEnded(handler: RoundEndedHandler): void { + const index = this.roundEndedHandlers.indexOf(handler); + if (index > -1) { + this.roundEndedHandlers.splice(index, 1); + } + } + + onPlayerBetted(handler: PlayerBettedHandler): void { + this.playerBettedHandlers.push(handler); + } + + offPlayerBetted(handler: PlayerBettedHandler): void { + const index = this.playerBettedHandlers.indexOf(handler); + if (index > -1) { + this.playerBettedHandlers.splice(index, 1); + } + } + + onPlayerAllIn(handler: PlayerAllInHandler): void { + this.playerAllInHandlers.push(handler); + } + + offPlayerAllIn(handler: PlayerAllInHandler): void { + const index = this.playerAllInHandlers.indexOf(handler); + if (index > -1) { + this.playerAllInHandlers.splice(index, 1); + } + } + + onPlayerChecked(handler: PlayerCheckedHandler): void { + this.playerCheckedHandlers.push(handler); + } + + offPlayerChecked(handler: PlayerCheckedHandler): void { + const index = this.playerCheckedHandlers.indexOf(handler); + if (index > -1) { + this.playerCheckedHandlers.splice(index, 1); + } + } + + onPlayerFolded(handler: PlayerFoldedHandler): void { + this.playerFoldedHandlers.push(handler); + } + + offPlayerFolded(handler: PlayerFoldedHandler): void { + const index = this.playerFoldedHandlers.indexOf(handler); + if (index > -1) { + this.playerFoldedHandlers.splice(index, 1); + } + } + + onPlayerCalled(handler: PlayerCalledHandler): void { + this.playerCalledHandlers.push(handler); + } + + offPlayerCalled(handler: PlayerCalledHandler): void { + const index = this.playerCalledHandlers.indexOf(handler); + if (index > -1) { + this.playerCalledHandlers.splice(index, 1); + } + } + + onNewCardsRevealed(handler: NewCardsRevealedHandler): void { + this.newCardsRevealedHandlers.push(handler); + } + + offNewCardsRevealed(handler: NewCardsRevealedHandler): void { + const index = this.newCardsRevealedHandlers.indexOf(handler); + if (index > -1) { + this.newCardsRevealedHandlers.splice(index, 1); + } + } + + onGameEnded(handler: GameEndedHandler): void { + this.gameEndedHandlers.push(handler); + } + + offGameEnded(handler: GameEndedHandler): void { + const index = this.gameEndedHandlers.indexOf(handler); + if (index > -1) { + this.gameEndedHandlers.splice(index, 1); + } + } + + async playerBetRequest(request: BetRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PlayerBetRequest', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async playerFoldRequest(request: FoldRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PlayerFoldRequest', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async playerCheckRequest(request: CheckRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PlayerCheckRequest', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async playerCallRequest(request: CallRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PlayerCallRequest', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + +} diff --git a/generated/typescript/texasholdem/types.ts b/generated/typescript/texasholdem/types.ts new file mode 100644 index 00000000..db88f7fa --- /dev/null +++ b/generated/typescript/texasholdem/types.ts @@ -0,0 +1,146 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface GameStartedNotification { + gameId: string; + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface ItsYourTurnNotification { + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface NewRoundStartedNotification { + gameId: string; + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface RoundEndedNotification { + winnerId: string; + winnings: number; + type?: string; +} + +export interface PlayerBettedNotification { + playerId: string; + betSize: number; + type?: string; +} + +export interface PlayerAllInNotification { + playerId: string; + type?: string; +} + +export interface PlayerCheckedNotification { + playerId: string; + type?: string; +} + +export interface PlayerFoldedNotification { + playerId: string; + type?: string; +} + +export interface PlayerCalledNotification { + playerId: string; + type?: string; +} + +export interface NewCardsRevealed { + cards?: Card[]; + type?: string; +} + +export interface Card { + rank: number; + suit: Suit; +} + +export enum Suit { + Clubs = 0, + Diamonds = 1, + Hearts = 2, + Spades = 3, +} + +export interface GameEndedNotification { + players?: PlayerData[]; + type?: string; +} + +export interface PlayerData { + name?: string; + points: number; + cardsInHand: number; + id: string; + info?: Record; +} + +export interface Dictionary { + comparer?: IEqualityComparer; + count: number; + capacity: number; + keys?: KeyCollection; + values?: ValueCollection; +} + +export interface ValueCollection { + count: number; +} + +export interface KeyCollection { + count: number; +} + +export interface BetRequest { + bet: number; + playerId: string; + type?: string; +} + +export interface PlayerViewOfGame { + cards?: Card[]; + cardsOnTable?: Card[]; + stackSize: number; + currentBet: number; + potSize: number; + bigBlind: number; + numberOfRoundsUntilBigBlindIncreases: number; + otherPlayers?: OtherPokerPlayers[]; + nextRoundStartingPlayerId: string; + hasError: boolean; + error?: string; + type?: string; +} + +export interface OtherPokerPlayers { + playerId: string; + name?: string; + stackSize: number; + currentBet: number; + hasChecked: boolean; + isAllIn: boolean; + hasFolded: boolean; +} + +export interface FoldRequest { + playerId: string; + type?: string; +} + +export interface CheckRequest { + playerId: string; + type?: string; +} + +export interface CallRequest { + playerId: string; + type?: string; +} + diff --git a/generated/typescript/types.ts b/generated/typescript/types.ts new file mode 100644 index 00000000..44509d42 --- /dev/null +++ b/generated/typescript/types.ts @@ -0,0 +1,11 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface EmptyResponse { + hasError: boolean; + error?: string; + type?: string; +} + diff --git a/generated/typescript/uno/UnoClient.ts b/generated/typescript/uno/UnoClient.ts new file mode 100644 index 00000000..b531a44c --- /dev/null +++ b/generated/typescript/uno/UnoClient.ts @@ -0,0 +1,269 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * Uno Game Client + * + * Notifications (events) for this game: + * - GameStarted: GameStartedNotification + * - PlayerPutCard: PlayerPutCardNotification + * - PlayerPutWild: PlayerPutWildNotification + * - PlayerDrewCard: PlayerDrewCardNotification + * - PlayerPassed: PlayerPassedNotification + * - GameEnded: GameEndedNotification + * - ItsYourTurn: ItsYourTurnNotification + */ + +import type { EmptyResponse } from '../types'; +import type { DrawCardRequest, GameEndedNotification, GameStartedNotification, ItsYourTurnNotification, PassRequest, PlayerDrewCardNotification, PlayerPassedNotification, PlayerPutCardNotification, PlayerPutWildNotification, PlayerViewOfGame, PutCardRequest, PutWildRequest, UnoCardResponse } from './types'; + +// Event handler types +export type GameStartedHandler = (data: GameStartedNotification) => void; +export type PlayerPutCardHandler = (data: PlayerPutCardNotification) => void; +export type PlayerPutWildHandler = (data: PlayerPutWildNotification) => void; +export type PlayerDrewCardHandler = (data: PlayerDrewCardNotification) => void; +export type PlayerPassedHandler = (data: PlayerPassedNotification) => void; +export type GameEndedHandler = (data: GameEndedNotification) => void; +export type ItsYourTurnHandler = (data: ItsYourTurnNotification) => void; + +export interface UnoClient { + onGameStarted(handler: GameStartedHandler): void; + offGameStarted(handler: GameStartedHandler): void; + onPlayerPutCard(handler: PlayerPutCardHandler): void; + offPlayerPutCard(handler: PlayerPutCardHandler): void; + onPlayerPutWild(handler: PlayerPutWildHandler): void; + offPlayerPutWild(handler: PlayerPutWildHandler): void; + onPlayerDrewCard(handler: PlayerDrewCardHandler): void; + offPlayerDrewCard(handler: PlayerDrewCardHandler): void; + onPlayerPassed(handler: PlayerPassedHandler): void; + offPlayerPassed(handler: PlayerPassedHandler): void; + onGameEnded(handler: GameEndedHandler): void; + offGameEnded(handler: GameEndedHandler): void; + onItsYourTurn(handler: ItsYourTurnHandler): void; + offItsYourTurn(handler: ItsYourTurnHandler): void; + + putCard(request: PutCardRequest): Promise; + putWild(request: PutWildRequest): Promise; + drawCard(request: DrawCardRequest): Promise; + pass(request: PassRequest): Promise; +} + +export class UnoClientImpl implements UnoClient { + private gameStartedHandlers: GameStartedHandler[] = []; + private playerPutCardHandlers: PlayerPutCardHandler[] = []; + private playerPutWildHandlers: PlayerPutWildHandler[] = []; + private playerDrewCardHandlers: PlayerDrewCardHandler[] = []; + private playerPassedHandlers: PlayerPassedHandler[] = []; + private gameEndedHandlers: GameEndedHandler[] = []; + private itsYourTurnHandlers: ItsYourTurnHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'GameStarted': + this.gameStartedHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPutCard': + this.playerPutCardHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPutWild': + this.playerPutWildHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerDrewCard': + this.playerDrewCardHandlers.forEach(h => h(notification.data)); + break; + case 'PlayerPassed': + this.playerPassedHandlers.forEach(h => h(notification.data)); + break; + case 'GameEnded': + this.gameEndedHandlers.forEach(h => h(notification.data)); + break; + case 'ItsYourTurn': + this.itsYourTurnHandlers.forEach(h => h(notification.data)); + break; + } + } + + onGameStarted(handler: GameStartedHandler): void { + this.gameStartedHandlers.push(handler); + } + + offGameStarted(handler: GameStartedHandler): void { + const index = this.gameStartedHandlers.indexOf(handler); + if (index > -1) { + this.gameStartedHandlers.splice(index, 1); + } + } + + onPlayerPutCard(handler: PlayerPutCardHandler): void { + this.playerPutCardHandlers.push(handler); + } + + offPlayerPutCard(handler: PlayerPutCardHandler): void { + const index = this.playerPutCardHandlers.indexOf(handler); + if (index > -1) { + this.playerPutCardHandlers.splice(index, 1); + } + } + + onPlayerPutWild(handler: PlayerPutWildHandler): void { + this.playerPutWildHandlers.push(handler); + } + + offPlayerPutWild(handler: PlayerPutWildHandler): void { + const index = this.playerPutWildHandlers.indexOf(handler); + if (index > -1) { + this.playerPutWildHandlers.splice(index, 1); + } + } + + onPlayerDrewCard(handler: PlayerDrewCardHandler): void { + this.playerDrewCardHandlers.push(handler); + } + + offPlayerDrewCard(handler: PlayerDrewCardHandler): void { + const index = this.playerDrewCardHandlers.indexOf(handler); + if (index > -1) { + this.playerDrewCardHandlers.splice(index, 1); + } + } + + onPlayerPassed(handler: PlayerPassedHandler): void { + this.playerPassedHandlers.push(handler); + } + + offPlayerPassed(handler: PlayerPassedHandler): void { + const index = this.playerPassedHandlers.indexOf(handler); + if (index > -1) { + this.playerPassedHandlers.splice(index, 1); + } + } + + onGameEnded(handler: GameEndedHandler): void { + this.gameEndedHandlers.push(handler); + } + + offGameEnded(handler: GameEndedHandler): void { + const index = this.gameEndedHandlers.indexOf(handler); + if (index > -1) { + this.gameEndedHandlers.splice(index, 1); + } + } + + onItsYourTurn(handler: ItsYourTurnHandler): void { + this.itsYourTurnHandlers.push(handler); + } + + offItsYourTurn(handler: ItsYourTurnHandler): void { + const index = this.itsYourTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsYourTurnHandlers.splice(index, 1); + } + } + + async putCard(request: PutCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async putWild(request: PutWildRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutWild', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async drawCard(request: DrawCardRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'DrawCard', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async pass(request: PassRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'Pass', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + +} diff --git a/generated/typescript/uno/types.ts b/generated/typescript/uno/types.ts new file mode 100644 index 00000000..e277cf16 --- /dev/null +++ b/generated/typescript/uno/types.ts @@ -0,0 +1,147 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface GameStartedNotification { + gameId: string; + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface PlayerPutCardNotification { + playerId: string; + card?: UnoCard; + type?: string; +} + +export interface UnoCard { + color: UnoColor; + value: UnoValue; +} + +export enum UnoValue { + Zero = 0, + One = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, + Six = 6, + Seven = 7, + Eight = 8, + Nine = 9, + Skip = 21, + Reverse = 22, + DrawTwo = 23, + Wild = 51, + WildDrawFour = 52, +} + +export enum UnoColor { + Red = 0, + Yellow = 1, + Green = 2, + Blue = 3, + Wild = 4, +} + +export interface PlayerPutWildNotification { + playerId: string; + card?: UnoCard; + newColor: UnoColor; + type?: string; +} + +export interface PlayerDrewCardNotification { + playerId: string; + type?: string; +} + +export interface PlayerPassedNotification { + playerId: string; + type?: string; +} + +export interface GameEndedNotification { + players?: PlayerData[]; + type?: string; +} + +export interface PlayerData { + name?: string; + points: number; + cardsInHand: number; + id: string; + info?: Record; +} + +export interface Dictionary { + comparer?: IEqualityComparer; + count: number; + capacity: number; + keys?: KeyCollection; + values?: ValueCollection; +} + +export interface ValueCollection { + count: number; +} + +export interface KeyCollection { + count: number; +} + +export interface ItsYourTurnNotification { + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface PutCardRequest { + card?: UnoCard; + playerId: string; + type?: string; +} + +export interface PlayerViewOfGame { + cards?: UnoCard[]; + topOfPile?: UnoCard; + currentColor: UnoColor; + stockPileCount: number; + discardPileCount: number; + otherPlayers?: OtherUnoPlayer[]; + hasError: boolean; + error?: string; + type?: string; +} + +export interface OtherUnoPlayer { + id: string; + name?: string; + numberOfCards: number; +} + +export interface PutWildRequest { + card?: UnoCard; + newColor: UnoColor; + playerId: string; + type?: string; +} + +export interface DrawCardRequest { + playerId: string; + type?: string; +} + +export interface UnoCardResponse { + card?: UnoCard; + hasError: boolean; + error?: string; + type?: string; +} + +export interface PassRequest { + playerId: string; + type?: string; +} + diff --git a/generated/typescript/yaniv/YanivClient.ts b/generated/typescript/yaniv/YanivClient.ts new file mode 100644 index 00000000..ac9ccba2 --- /dev/null +++ b/generated/typescript/yaniv/YanivClient.ts @@ -0,0 +1,200 @@ +/** + * Autogenerated by really, really eager small hamsters. + * + * Yaniv Game Client + * + * Notifications (events) for this game: + * - PlayerPutCards: PlayerPutCardsNotification + * - ItsYourTurn: ItsYourTurnNotification + * - RoundStarted: RoundStartedNotification + * - RoundEnded: RoundEndedNotification + * - GameEnded: GameEndedNotification + * - DiscardPileShuffled: DiscardPileShuffledNotification + */ + +import type { EmptyResponse } from '../types'; +import type { CallYanivRequest, DiscardPileShuffledNotification, GameEndedNotification, ItsYourTurnNotification, PlayerPutCardsNotification, PutCardsRequest, PutCardsResponse, RoundEndedNotification, RoundStartedNotification } from './types'; + +// Event handler types +export type PlayerPutCardsHandler = (data: PlayerPutCardsNotification) => void; +export type ItsYourTurnHandler = (data: ItsYourTurnNotification) => void; +export type RoundStartedHandler = (data: RoundStartedNotification) => void; +export type RoundEndedHandler = (data: RoundEndedNotification) => void; +export type GameEndedHandler = (data: GameEndedNotification) => void; +export type DiscardPileShuffledHandler = (data: DiscardPileShuffledNotification) => void; + +export interface YanivClient { + onPlayerPutCards(handler: PlayerPutCardsHandler): void; + offPlayerPutCards(handler: PlayerPutCardsHandler): void; + onItsYourTurn(handler: ItsYourTurnHandler): void; + offItsYourTurn(handler: ItsYourTurnHandler): void; + onRoundStarted(handler: RoundStartedHandler): void; + offRoundStarted(handler: RoundStartedHandler): void; + onRoundEnded(handler: RoundEndedHandler): void; + offRoundEnded(handler: RoundEndedHandler): void; + onGameEnded(handler: GameEndedHandler): void; + offGameEnded(handler: GameEndedHandler): void; + onDiscardPileShuffled(handler: DiscardPileShuffledHandler): void; + offDiscardPileShuffled(handler: DiscardPileShuffledHandler): void; + + callYaniv(request: CallYanivRequest): Promise; + putCards(request: PutCardsRequest): Promise; +} + +export class YanivClientImpl implements YanivClient { + private playerPutCardsHandlers: PlayerPutCardsHandler[] = []; + private itsYourTurnHandlers: ItsYourTurnHandler[] = []; + private roundStartedHandlers: RoundStartedHandler[] = []; + private roundEndedHandlers: RoundEndedHandler[] = []; + private gameEndedHandlers: GameEndedHandler[] = []; + private discardPileShuffledHandlers: DiscardPileShuffledHandler[] = []; + + constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) { + this.setupNotificationHandlers(); + } + + private setupNotificationHandlers(): void { + this.notificationSocket.onmessage = (event) => { + const notification = JSON.parse(event.data); + this.handleNotification(notification); + }; + } + + private handleNotification(notification: any): void { + switch (notification.type) { + case 'PlayerPutCards': + this.playerPutCardsHandlers.forEach(h => h(notification.data)); + break; + case 'ItsYourTurn': + this.itsYourTurnHandlers.forEach(h => h(notification.data)); + break; + case 'RoundStarted': + this.roundStartedHandlers.forEach(h => h(notification.data)); + break; + case 'RoundEnded': + this.roundEndedHandlers.forEach(h => h(notification.data)); + break; + case 'GameEnded': + this.gameEndedHandlers.forEach(h => h(notification.data)); + break; + case 'DiscardPileShuffled': + this.discardPileShuffledHandlers.forEach(h => h(notification.data)); + break; + } + } + + onPlayerPutCards(handler: PlayerPutCardsHandler): void { + this.playerPutCardsHandlers.push(handler); + } + + offPlayerPutCards(handler: PlayerPutCardsHandler): void { + const index = this.playerPutCardsHandlers.indexOf(handler); + if (index > -1) { + this.playerPutCardsHandlers.splice(index, 1); + } + } + + onItsYourTurn(handler: ItsYourTurnHandler): void { + this.itsYourTurnHandlers.push(handler); + } + + offItsYourTurn(handler: ItsYourTurnHandler): void { + const index = this.itsYourTurnHandlers.indexOf(handler); + if (index > -1) { + this.itsYourTurnHandlers.splice(index, 1); + } + } + + onRoundStarted(handler: RoundStartedHandler): void { + this.roundStartedHandlers.push(handler); + } + + offRoundStarted(handler: RoundStartedHandler): void { + const index = this.roundStartedHandlers.indexOf(handler); + if (index > -1) { + this.roundStartedHandlers.splice(index, 1); + } + } + + onRoundEnded(handler: RoundEndedHandler): void { + this.roundEndedHandlers.push(handler); + } + + offRoundEnded(handler: RoundEndedHandler): void { + const index = this.roundEndedHandlers.indexOf(handler); + if (index > -1) { + this.roundEndedHandlers.splice(index, 1); + } + } + + onGameEnded(handler: GameEndedHandler): void { + this.gameEndedHandlers.push(handler); + } + + offGameEnded(handler: GameEndedHandler): void { + const index = this.gameEndedHandlers.indexOf(handler); + if (index > -1) { + this.gameEndedHandlers.splice(index, 1); + } + } + + onDiscardPileShuffled(handler: DiscardPileShuffledHandler): void { + this.discardPileShuffledHandlers.push(handler); + } + + offDiscardPileShuffled(handler: DiscardPileShuffledHandler): void { + const index = this.discardPileShuffledHandlers.indexOf(handler); + if (index > -1) { + this.discardPileShuffledHandlers.splice(index, 1); + } + } + + async callYaniv(request: CallYanivRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'CallYaniv', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + + async putCards(request: PutCardsRequest): Promise { + return new Promise((resolve, reject) => { + const request = { + type: 'PutCards', + data: { + request: request, + } + }; + + const messageHandler = (event: MessageEvent) => { + const response = JSON.parse(event.data); + if (response.error) { + reject(new Error(response.error)); + } else { + resolve(response.data); + } + this.actionSocket.removeEventListener('message', messageHandler); + }; + + this.actionSocket.addEventListener('message', messageHandler); + this.actionSocket.send(JSON.stringify(request)); + }); + } + +} diff --git a/generated/typescript/yaniv/types.ts b/generated/typescript/yaniv/types.ts new file mode 100644 index 00000000..85a4daca --- /dev/null +++ b/generated/typescript/yaniv/types.ts @@ -0,0 +1,104 @@ +/** + * Autogenerated by really, really eager small hamsters. + * Shared type definitions for Deckster game clients. + */ + +export interface PlayerPutCardsNotification { + playerId: string; + cards?: Card[]; + drewCardFrom: DrawCardFrom; + type?: string; +} + +export interface Card { + rank: number; + suit: Suit; +} + +export enum Suit { + Clubs = 0, + Diamonds = 1, + Hearts = 2, + Spades = 3, +} + +export interface ItsYourTurnNotification { + type?: string; +} + +export interface RoundStartedNotification { + playerViewOfGame?: PlayerViewOfGame; + type?: string; +} + +export interface PlayerViewOfGame { + deckSize: number; + topOfPile: Card; + cardsOnHand?: Card[]; + otherPlayers?: OtherYanivPlayer[]; +} + +export interface OtherYanivPlayer { + id: string; + numberOfCards: number; + name?: string; +} + +export interface RoundEndedNotification { + winnerPlayerId: string; + playerScores?: PlayerRoundScore[]; + type?: string; +} + +export interface PlayerRoundScore { + playerId: string; + cards?: Card[]; + points: number; + penalty: number; + totalPoints: number; +} + +export interface GameEndedNotification { + winnerPlayerId: string; + playerScores?: PlayerFinalScore[]; + type?: string; +} + +export interface PlayerFinalScore { + playerId: string; + points: number; + penalty: number; + totalPoints: number; + finalPoints: number; +} + +export interface DiscardPileShuffledNotification { + stockPileSize: number; + discardPileSize: number; + type?: string; +} + +export interface CallYanivRequest { + playerId: string; + type?: string; +} + +export interface PutCardsRequest { + cards?: Card[]; + drawCardFrom: DrawCardFrom; + playerId: string; + type?: string; +} + +export interface PutCardsResponse { + drawnCard: Card; + hasError: boolean; + error?: string; + type?: string; +} + +export enum DrawCardFrom { + StockPile = 0, + DiscardPile = 1, +} + diff --git a/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs b/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs index d41e1944..a105b9c1 100644 --- a/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs +++ b/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs @@ -141,7 +141,7 @@ public CsharpClientGenerator(CSharpGameMeta meta, string ns) "/// throws exception on error", "/// ", ]); - Source.AppendLine($"public static async Task<{extension.ReturnParameters[0].ParameterType.Name}> {extension.Name}OrThrowAsync(this {ClientName} self, {parameters})"); + Source.AppendLine($"public static async Task<{extension.ReturnParameters[0].ParameterType.ToDisplayString()}> {extension.Name}OrThrowAsync(this {ClientName} self, {parameters})"); break; default: var returnTuple = extension.ReturnParameters.Select(p => $"{p.ParameterType.ToDisplayString()} {p.Name}").StringJoined(", "); diff --git a/src/Deckster.CodeGenerator/Generators/TypeScriptClientGenerator.cs b/src/Deckster.CodeGenerator/Generators/TypeScriptClientGenerator.cs new file mode 100644 index 00000000..4d34d36e --- /dev/null +++ b/src/Deckster.CodeGenerator/Generators/TypeScriptClientGenerator.cs @@ -0,0 +1,283 @@ +using Deckster.Core.Extensions; +using Deckster.Games.CodeGeneration.Meta; + +namespace Deckster.CodeGenerator.Generators; + +public class TypeScriptClientGenerator : ClientGenerator +{ + public HashSet SharedTypeNames { get; } = new(); + public HashSet GameSpecificTypeNames { get; } = new(); + + public TypeScriptClientGenerator(GameMeta meta, string moduleName, HashSet gameSpecificTypeNames) + { + Source + .AppendLine("/**") + .AppendLine(" * Autogenerated by really, really eager small hamsters.") + .AppendLine(" *") + .AppendLine($" * {meta.Name} Game Client") + .AppendLine(" *") + .AppendLine(" * Notifications (events) for this game:") + .AppendLines(meta.Notifications.Select(n => $" * - {n.Name}: {n.Message}")) + .AppendLine(" */") + .AppendLine(); + + // Collect and categorize type names for import + var allTypeNames = new HashSet(); + + foreach (var method in meta.Methods) + { + foreach (var param in method.Parameters) + { + allTypeNames.Add(param.Type.Name); + } + if (method.ReturnType.Name != "void") + { + allTypeNames.Add(method.ReturnType.Name); + } + } + + foreach (var notification in meta.Notifications) + { + allTypeNames.Add(notification.Message.Name); + } + + // Separate shared types from game-specific types + foreach (var typeName in allTypeNames) + { + if (gameSpecificTypeNames.Contains(typeName)) + { + GameSpecificTypeNames.Add(typeName); + } + else + { + SharedTypeNames.Add(typeName); + } + } + + // Import types from shared types file + if (SharedTypeNames.Any()) + { + Source.Append("import type { "); + Source.Append(string.Join(", ", SharedTypeNames.OrderBy(t => t))); + Source.AppendLine(" } from '../types';"); + } + + // Import types from game-specific types file + if (GameSpecificTypeNames.Any()) + { + Source.Append("import type { "); + Source.Append(string.Join(", ", GameSpecificTypeNames.OrderBy(t => t))); + Source.AppendLine(" } from './types';"); + } + + if (SharedTypeNames.Any() || GameSpecificTypeNames.Any()) + { + Source.AppendLine(); + } + + // Event handler types + Source.AppendLine("// Event handler types"); + foreach (var notification in meta.Notifications) + { + Source.AppendLine($"export type {notification.Name}Handler = (data: {notification.Message.Name}) => void;"); + } + Source.AppendLine(); + + // Main client interface + Source.AppendLine($"export interface {meta.Name}Client {{"); + using (Source.Indent()) + { + // Event listeners + foreach (var notification in meta.Notifications) + { + Source.AppendLine($"on{notification.Name}(handler: {notification.Name}Handler): void;"); + Source.AppendLine($"off{notification.Name}(handler: {notification.Name}Handler): void;"); + } + + if (meta.Notifications.Any()) + { + Source.AppendLine(); + } + + // Methods + foreach (var method in meta.Methods) + { + var parameters = string.Join(", ", method.Parameters.Select(FormatParameter)); + var returnType = method.ReturnType.Name != "void" ? method.ReturnType.Name : "void"; + Source.AppendLine($"{method.Name.ToCamelCase()}({parameters}): Promise<{returnType}>;"); + } + } + Source.AppendLine("}"); + Source.AppendLine(); + + // Implementation class + Source.AppendLine($"export class {meta.Name}ClientImpl implements {meta.Name}Client {{"); + using (Source.Indent()) + { + // Event handler storage + foreach (var notification in meta.Notifications) + { + Source.AppendLine($"private {notification.Name.ToCamelCase()}Handlers: {notification.Name}Handler[] = [];"); + } + + if (meta.Notifications.Any()) + { + Source.AppendLine(); + } + + // Constructor + Source.AppendLine("constructor(private actionSocket: WebSocket, private notificationSocket: WebSocket) {"); + using (Source.Indent()) + { + Source.AppendLine("this.setupNotificationHandlers();"); + } + Source.AppendLine("}"); + Source.AppendLine(); + + // Setup notification handlers + Source.AppendLine("private setupNotificationHandlers(): void {"); + using (Source.Indent()) + { + Source.AppendLine("this.notificationSocket.onmessage = (event) => {"); + using (Source.Indent()) + { + Source.AppendLine("const notification = JSON.parse(event.data);"); + Source.AppendLine("this.handleNotification(notification);"); + } + Source.AppendLine("};"); + } + Source.AppendLine("}"); + Source.AppendLine(); + + // Handle notification + Source.AppendLine("private handleNotification(notification: any): void {"); + using (Source.Indent()) + { + Source.AppendLine("switch (notification.type) {"); + using (Source.Indent()) + { + foreach (var notification in meta.Notifications) + { + Source.AppendLine($"case '{notification.Name}':"); + using (Source.Indent()) + { + Source.AppendLine($"this.{notification.Name.ToCamelCase()}Handlers.forEach(h => h(notification.data));"); + Source.AppendLine("break;"); + } + } + } + Source.AppendLine("}"); + } + Source.AppendLine("}"); + Source.AppendLine(); + + // Event listener methods + foreach (var notification in meta.Notifications) + { + Source.AppendLine($"on{notification.Name}(handler: {notification.Name}Handler): void {{"); + using (Source.Indent()) + { + Source.AppendLine($"this.{notification.Name.ToCamelCase()}Handlers.push(handler);"); + } + Source.AppendLine("}"); + Source.AppendLine(); + + Source.AppendLine($"off{notification.Name}(handler: {notification.Name}Handler): void {{"); + using (Source.Indent()) + { + Source.AppendLine($"const index = this.{notification.Name.ToCamelCase()}Handlers.indexOf(handler);"); + Source.AppendLine("if (index > -1) {"); + using (Source.Indent()) + { + Source.AppendLine($"this.{notification.Name.ToCamelCase()}Handlers.splice(index, 1);"); + } + Source.AppendLine("}"); + } + Source.AppendLine("}"); + Source.AppendLine(); + } + + // Game methods + foreach (var method in meta.Methods) + { + var parameters = string.Join(", ", method.Parameters.Select(FormatParameter)); + var returnType = method.ReturnType.Name != "void" ? method.ReturnType.Name : "void"; + + Source.AppendLine($"async {method.Name.ToCamelCase()}({parameters}): Promise<{returnType}> {{"); + using (Source.Indent()) + { + Source.AppendLine("return new Promise((resolve, reject) => {"); + using (Source.Indent()) + { + Source.AppendLine("const request = {"); + using (Source.Indent()) + { + Source.AppendLine($"type: '{method.Name}',"); + if (method.Parameters.Any()) + { + Source.AppendLine("data: {"); + using (Source.Indent()) + { + foreach (var param in method.Parameters) + { + Source.AppendLine($"{param.Name}: {param.Name},"); + } + } + Source.AppendLine("}"); + } + } + Source.AppendLine("};"); + Source.AppendLine(); + Source.AppendLine("const messageHandler = (event: MessageEvent) => {"); + using (Source.Indent()) + { + Source.AppendLine("const response = JSON.parse(event.data);"); + if (returnType != "void") + { + Source.AppendLine("if (response.error) {"); + using (Source.Indent()) + { + Source.AppendLine("reject(new Error(response.error));"); + } + Source.AppendLine("} else {"); + using (Source.Indent()) + { + Source.AppendLine("resolve(response.data);"); + } + Source.AppendLine("}"); + } + else + { + Source.AppendLine("if (response.error) {"); + using (Source.Indent()) + { + Source.AppendLine("reject(new Error(response.error));"); + } + Source.AppendLine("} else {"); + using (Source.Indent()) + { + Source.AppendLine("resolve();"); + } + Source.AppendLine("}"); + } + Source.AppendLine("this.actionSocket.removeEventListener('message', messageHandler);"); + } + Source.AppendLine("};"); + Source.AppendLine(); + Source.AppendLine("this.actionSocket.addEventListener('message', messageHandler);"); + Source.AppendLine("this.actionSocket.send(JSON.stringify(request));"); + } + Source.AppendLine("});"); + } + Source.AppendLine("}"); + Source.AppendLine(); + } + } + Source.AppendLine("}"); + } + + private static string FormatParameter(ParameterMeta parameter) + { + return $"{parameter.Name}: {parameter.Type.Name}"; + } +} diff --git a/src/Deckster.CodeGenerator/Generators/TypeScriptTypeGenerator.cs b/src/Deckster.CodeGenerator/Generators/TypeScriptTypeGenerator.cs new file mode 100644 index 00000000..2be3a18f --- /dev/null +++ b/src/Deckster.CodeGenerator/Generators/TypeScriptTypeGenerator.cs @@ -0,0 +1,273 @@ +using System.Reflection; +using Deckster.CodeGenerator.Code; +using Deckster.Core.Extensions; + +namespace Deckster.CodeGenerator.Generators; + +public class TypeScriptTypeGenerator +{ + private readonly HashSet _processedTypes = new(); + private readonly HashSet _typesToProcess = new(); + private readonly SourceWriter _source = new(); + + public void AddType(Type type) + { + if (!_processedTypes.Contains(type) && !_typesToProcess.Contains(type)) + { + _typesToProcess.Add(type); + } + } + + public void GenerateTypes() + { + while (_typesToProcess.Count > 0) + { + var type = _typesToProcess.First(); + _typesToProcess.Remove(type); + + if (_processedTypes.Contains(type)) + { + continue; + } + + ProcessType(type); + _processedTypes.Add(type); + } + } + + private void ProcessType(Type type) + { + // Skip primitive types and common .NET types + if (IsPrimitiveOrKnownType(type)) + { + return; + } + + // Handle nullable types + var underlyingType = Nullable.GetUnderlyingType(type); + if (underlyingType != null) + { + ProcessType(underlyingType); + return; + } + + // Handle arrays and collections + if (type.IsArray) + { + ProcessType(type.GetElementType()!); + return; + } + + if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>) || + type.GetGenericTypeDefinition() == typeof(IEnumerable<>) || + type.GetGenericTypeDefinition() == typeof(ICollection<>))) + { + ProcessType(type.GetGenericArguments()[0]); + return; + } + + // Handle enums + if (type.IsEnum) + { + GenerateEnum(type); + return; + } + + // Handle classes and structs + if (type.IsClass || type.IsValueType) + { + GenerateInterface(type); + } + } + + private void GenerateEnum(Type type) + { + _source.AppendLine($"export enum {GetTypeName(type)} {{"); + using (_source.Indent()) + { + var names = Enum.GetNames(type); + var values = Enum.GetValues(type); + + for (int i = 0; i < names.Length; i++) + { + var name = names[i]; + var value = Convert.ToInt32(values.GetValue(i)); + _source.AppendLine($"{name} = {value},"); + } + } + _source.AppendLine("}"); + _source.AppendLine(); + } + + private void GenerateInterface(Type type) + { + var typeName = GetTypeName(type); + _source.AppendLine($"export interface {typeName} {{"); + + using (_source.Indent()) + { + var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(p => p.CanRead && !p.GetIndexParameters().Any()); + + foreach (var property in properties) + { + var propertyName = property.Name.ToCamelCase(); + var propertyType = GetTypeScriptType(property.PropertyType); + var optional = IsNullable(property.PropertyType) ? "?" : ""; + + _source.AppendLine($"{propertyName}{optional}: {propertyType};"); + + // Queue property types for processing + QueueTypeForProcessing(property.PropertyType); + } + } + + _source.AppendLine("}"); + _source.AppendLine(); + } + + private void QueueTypeForProcessing(Type type) + { + // Handle nullable types + var underlyingType = Nullable.GetUnderlyingType(type); + if (underlyingType != null) + { + QueueTypeForProcessing(underlyingType); + return; + } + + // Handle arrays + if (type.IsArray) + { + QueueTypeForProcessing(type.GetElementType()!); + return; + } + + // Handle generic collections + if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>) || + type.GetGenericTypeDefinition() == typeof(IEnumerable<>) || + type.GetGenericTypeDefinition() == typeof(ICollection<>))) + { + QueueTypeForProcessing(type.GetGenericArguments()[0]); + return; + } + + // Add complex types to the queue + if (!IsPrimitiveOrKnownType(type) && !_processedTypes.Contains(type) && !_typesToProcess.Contains(type)) + { + _typesToProcess.Add(type); + } + } + + private string GetTypeScriptType(Type type) + { + // Handle nullable types + var underlyingType = Nullable.GetUnderlyingType(type); + if (underlyingType != null) + { + return GetTypeScriptType(underlyingType); + } + + // Handle arrays + if (type.IsArray) + { + return $"{GetTypeScriptType(type.GetElementType()!)}[]"; + } + + // Handle generic collections + if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>) || + type.GetGenericTypeDefinition() == typeof(IEnumerable<>) || + type.GetGenericTypeDefinition() == typeof(ICollection<>))) + { + return $"{GetTypeScriptType(type.GetGenericArguments()[0])}[]"; + } + + // Handle dictionaries + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + var keyType = GetTypeScriptType(type.GetGenericArguments()[0]); + var valueType = GetTypeScriptType(type.GetGenericArguments()[1]); + return $"Record<{keyType}, {valueType}>"; + } + + // Primitive type mappings + if (type == typeof(string)) return "string"; + if (type == typeof(int) || type == typeof(long) || type == typeof(short) || + type == typeof(byte) || type == typeof(decimal) || type == typeof(double) || + type == typeof(float)) return "number"; + if (type == typeof(bool)) return "boolean"; + if (type == typeof(DateTime) || type == typeof(DateTimeOffset)) return "string"; // ISO date string + if (type == typeof(Guid)) return "string"; + if (type == typeof(object)) return "any"; + if (type == typeof(void)) return "void"; + + // Complex types + return GetTypeName(type); + } + + private string GetTypeName(Type type) + { + if (type.IsGenericType) + { + var backtickIndex = type.Name.IndexOf('`'); + if (backtickIndex > 0) + { + return type.Name.Substring(0, backtickIndex); + } + } + + return type.Name; + } + + private bool IsNullable(Type type) + { + if (Nullable.GetUnderlyingType(type) != null) + { + return true; + } + + if (!type.IsValueType) + { + return true; // Reference types are nullable by default + } + + return false; + } + + private bool IsPrimitiveOrKnownType(Type type) + { + return type.IsPrimitive || + type == typeof(string) || + type == typeof(decimal) || + type == typeof(DateTime) || + type == typeof(DateTimeOffset) || + type == typeof(Guid) || + type == typeof(object) || + type == typeof(void); + } + + public string GetGeneratedCode() + { + return _source.ToString(); + } + + public async Task WriteToAsync(FileInfo file) + { + if (file.Directory is { Exists: false }) + { + file.Directory.Create(); + } + + await using var fileStream = file.Exists ? file.Open(FileMode.Truncate) : file.Open(FileMode.CreateNew); + await using var writer = new StreamWriter(fileStream); + + await writer.WriteLineAsync("/**"); + await writer.WriteLineAsync(" * Autogenerated by really, really eager small hamsters."); + await writer.WriteLineAsync(" * Shared type definitions for Deckster game clients."); + await writer.WriteLineAsync(" */"); + await writer.WriteLineAsync(); + + await writer.WriteAsync(_source.ToString()); + await writer.FlushAsync(); + } +} diff --git a/src/Deckster.CodeGenerator/Program.cs b/src/Deckster.CodeGenerator/Program.cs index dae73b4f..229cdf54 100644 --- a/src/Deckster.CodeGenerator/Program.cs +++ b/src/Deckster.CodeGenerator/Program.cs @@ -87,21 +87,116 @@ private static async Task GenerateClientsAsync(DirectoryInfo gitDirectory) var types = baseType.Assembly.GetTypes() .Where(t => t is {IsClass: true, IsAbstract: false} && baseType.IsAssignableFrom(t)) .ToArray(); - + var kotlinDirectory = gitDirectory.GetCleanSubDirectory("generated", "kotlin"); - + var typeScriptDirectory = gitDirectory.GetSubDirectory("generated", "typescript"); + if (!typeScriptDirectory.Exists) + { + typeScriptDirectory.Create(); + } + + // Collect types per game for TypeScript generation + var gameTypesMap = new Dictionary>(); + var gameClients = new List<(Type gameType, GameMeta gameMeta, CSharpGameMeta csharpMeta)>(); + foreach (var type in types) { if (CSharpGameMeta.TryGetFor(type, out var gameMeta)) { - await GenerateCsharpAsync(gitDirectory, type, gameMeta); + await GenerateCsharpAsync(gitDirectory, type, gameMeta); + + var gameName = type.Name.Replace("Game", ""); + var gameTypes = new HashSet(); + + // Collect types for this game + foreach (var notification in gameMeta.Notifications) + { + gameTypes.Add(notification.MessageType); + } + + foreach (var method in gameMeta.Methods) + { + gameTypes.Add(method.Request.ParameterType); + gameTypes.Add(method.ResponseType); + } + + gameTypesMap[gameName] = gameTypes; + + if (GameMeta.TryGetFor(type, out var game)) + { + await GenerateKotlinAsync(kotlinDirectory, type, game); + gameClients.Add((type, game, gameMeta)); + } } - - if (GameMeta.TryGetFor(type, out var game)) + } + + // Determine shared vs game-specific types + var allTypes = new HashSet(); + foreach (var gameTypes in gameTypesMap.Values) + { + foreach (var type in gameTypes) { - await GenerateKotlinAsync(kotlinDirectory, type, game); + allTypes.Add(type); } } + + var sharedTypes = new HashSet(); + var gameSpecificTypes = new Dictionary>(); + + foreach (var type in allTypes) + { + var gamesUsingType = gameTypesMap.Where(kvp => kvp.Value.Contains(type)).Select(kvp => kvp.Key).ToList(); + + if (gamesUsingType.Count > 1) + { + sharedTypes.Add(type); + } + else if (gamesUsingType.Count == 1) + { + var gameName = gamesUsingType[0]; + if (!gameSpecificTypes.ContainsKey(gameName)) + { + gameSpecificTypes[gameName] = new HashSet(); + } + gameSpecificTypes[gameName].Add(type); + } + } + + // Generate shared TypeScript types + var sharedTypeGenerator = new TypeScriptTypeGenerator(); + foreach (var type in sharedTypes) + { + sharedTypeGenerator.AddType(type); + } + sharedTypeGenerator.GenerateTypes(); + await sharedTypeGenerator.WriteToAsync(typeScriptDirectory.GetFile("types.ts")); + + // Generate game-specific TypeScript types and clients + foreach (var (gameType, game, csharpMeta) in gameClients) + { + var gameName = gameType.Name.Replace("Game", ""); + var ns = gameType.Namespace?.Split('.').LastOrDefault()?.ToLowerInvariant() ?? throw new Exception($"OMG CANT HAZ NAEMSPAZE OF ITZ TAYP '{gameType.Name}'"); + + // Generate game-specific types + if (gameSpecificTypes.TryGetValue(gameName, out var specificTypes)) + { + var gameTypeGenerator = new TypeScriptTypeGenerator(); + foreach (var type in specificTypes) + { + gameTypeGenerator.AddType(type); + } + gameTypeGenerator.GenerateTypes(); + + var gameTypeFile = typeScriptDirectory.GetFile(ns, "types.ts"); + await gameTypeGenerator.WriteToAsync(gameTypeFile); + } + + // Generate client + var gameSpecificTypeNames = gameSpecificTypes.ContainsKey(gameName) + ? gameSpecificTypes[gameName].Select(t => t.Name).ToHashSet() + : new HashSet(); + await GenerateTypeScriptAsync(typeScriptDirectory, gameType, game, gameSpecificTypeNames); + } } private static async Task GenerateCsharpAsync(DirectoryInfo gitDirectory, Type gameType, CSharpGameMeta game) @@ -117,9 +212,19 @@ private static async Task GenerateKotlinAsync(DirectoryInfo kotlinDirectory, Typ { var ns = type.Namespace?.Split('.').LastOrDefault()?.ToLowerInvariant() ?? throw new Exception($"OMG CANT HAZ NAEMSPAZE OF ITZ TAYP '{type.Name}'"); var file = kotlinDirectory.GetFile("no.forse.decksterlib", ns, $"{game.Name}Client.kt"); - + Console.WriteLine(file); var kotlin = new KotlinClientGenerator(game, $"no.forse.decksterlib.{ns}"); await kotlin.WriteToAsync(file); } + + private static async Task GenerateTypeScriptAsync(DirectoryInfo typeScriptDirectory, Type type, GameMeta game, HashSet gameSpecificTypeNames) + { + var ns = type.Namespace?.Split('.').LastOrDefault()?.ToLowerInvariant() ?? throw new Exception($"OMG CANT HAZ NAEMSPAZE OF ITZ TAYP '{type.Name}'"); + var file = typeScriptDirectory.GetFile(ns, $"{game.Name}Client.ts"); + + Console.WriteLine(file); + var typeScript = new TypeScriptClientGenerator(game, ns, gameSpecificTypeNames); + await typeScript.WriteToAsync(file); + } } diff --git a/src/Deckster.Server/Startup.cs b/src/Deckster.Server/Startup.cs index 11c3df85..7c1a841e 100644 --- a/src/Deckster.Server/Startup.cs +++ b/src/Deckster.Server/Startup.cs @@ -81,8 +81,19 @@ public static void ConfigureServices(IServiceCollection services, DecksterConfig o.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; }); mvc.AddRazorRuntimeCompilation(); - - + + // Add CORS + services.AddCors(options => + { + options.AddPolicy("AllowWebClient", builder => + { + builder.WithOrigins("http://localhost:3000") + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials(); + }); + }); + services.AddAuthentication(o => { o.DefaultScheme = AuthenticationSchemes.Cookie; @@ -130,8 +141,12 @@ public static void Configure(IApplicationBuilder app) o.DocumentTitle = "Deckster"; o.RoutePrefix = "swagger"; }); - + app.MapExtensionToAcceptHeader(); + + // Enable CORS + app.UseCors("AllowWebClient"); + app.UseAuthentication(); app.LoadUser(); app.UseWebSockets(); diff --git a/web-clients/hearts/README.md b/web-clients/hearts/README.md new file mode 100644 index 00000000..88041e38 --- /dev/null +++ b/web-clients/hearts/README.md @@ -0,0 +1,138 @@ +# Hearts Web Client + +A 3D web-based client for the Hearts card game built with TypeScript, three.js, and Vite. + +## Features + +- 3D card visualization using three.js +- Real-time WebSocket communication with Deckster server +- Interactive card selection and gameplay +- Visual feedback for game events (passing phase, tricks, scoring) +- Responsive UI with game state tracking + +## Prerequisites + +- Node.js (v18 or higher) +- npm +- Running Deckster Hearts server + +## Installation + +```bash +npm install +``` + +## Development + +Start the development server: + +```bash +npm run dev +``` + +This will start Vite dev server on http://localhost:3000 + +## Building for Production + +Build the project: + +```bash +npm run build +``` + +Preview the production build: + +```bash +npm run preview +``` + +The build output will be in the `dist/` directory. + +## How to Play + +1. **Start the Deckster server** (from the root of the Deckster repository): + ```bash + cd src/Deckster.Server + dotnet run + ``` + +2. **Open the web client** in your browser (if using dev server, it should open automatically) + +3. **Enter connection details**: + - Player Name: Your display name + - Game ID: The Hearts game session ID + + Note: The server URL is automatically set to `ws://localhost:13992` and a unique player ID (GUID) is generated automatically. + +4. **Click Connect** to join the game + +5. **Game Flow**: + - **Passing Phase**: Select 3 cards by clicking on them, they will be highlighted + - **Playing Phase**: Click on a card to play it when it's your turn + - Watch the center area for the current trick + - Monitor your score in the top-left panel + +## Project Structure + +``` +hearts/ +├── src/ +│ ├── main.ts # Application entry point +│ ├── game/ +│ │ └── HeartsGame.ts # Game controller and logic +│ ├── graphics/ +│ │ ├── CardScene.ts # three.js scene management +│ │ └── Card3D.ts # 3D card rendering +│ └── ui/ +│ └── GameUI.ts # DOM UI management +├── index.html # HTML template +├── vite.config.ts # Vite configuration +├── tsconfig.json # TypeScript configuration +└── package.json # Dependencies and scripts +``` + +## Technologies Used + +- **TypeScript**: Type-safe development +- **three.js**: 3D graphics rendering +- **Vite**: Fast build tool and dev server +- **WebSocket**: Real-time bidirectional communication +- Generated TypeScript client from Deckster OpenAPI specification + +## Controls + +- **Mouse hover**: Highlights cards in your hand +- **Click**: Select cards (passing phase) or play cards (your turn) +- **Selected cards**: Elevated and highlighted +- Cards can be deselected by clicking again + +## Known Limitations + +- Card graphics are simplified (geometric shapes representing suits) +- Player positions are not fully mapped (all opponent cards appear at same positions) +- Production version would benefit from actual card textures/images + +## Future Enhancements + +- Add card textures with actual rank and suit designs +- Implement proper player position mapping (North, East, South, West) +- Add animation for card dealing and trick collection +- Implement sound effects +- Add chat functionality +- Mobile touch support optimization +- Better error handling and reconnection logic + +## Troubleshooting + +**Cannot connect to server**: +- Ensure the Deckster server is running on port 13992 +- Verify the game ID exists on the server +- Check browser console for connection errors + +**Cards not displaying**: +- Check browser console for errors +- Ensure WebGL is supported in your browser + +**Build errors**: +- Run `npm install` to ensure all dependencies are installed +- Clear node_modules and reinstall if needed: `rm -rf node_modules && npm install` diff --git a/web-clients/hearts/dist/assets/index-w1daCLpV.js b/web-clients/hearts/dist/assets/index-w1daCLpV.js new file mode 100644 index 00000000..bf9cd767 --- /dev/null +++ b/web-clients/hearts/dist/assets/index-w1daCLpV.js @@ -0,0 +1,3844 @@ +(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))n(r);new MutationObserver(r=>{for(const s of r)if(s.type==="childList")for(const a of s.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&n(a)}).observe(document,{childList:!0,subtree:!0});function t(r){const s={};return r.integrity&&(s.integrity=r.integrity),r.referrerPolicy&&(s.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?s.credentials="include":r.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function n(r){if(r.ep)return;r.ep=!0;const s=t(r);fetch(r.href,s)}})();/** + * @license + * Copyright 2010-2025 Three.js Authors + * SPDX-License-Identifier: MIT + */const Gs="180",Zo=0,ca=1,jo=2,po=1,Jo=2,tn=3,pn=0,yt=1,kt=2,dn=0,$n=1,la=2,ua=3,ha=4,Qo=5,bn=100,ec=101,tc=102,nc=103,ic=104,rc=200,sc=201,ac=202,oc=203,Zr=204,jr=205,cc=206,lc=207,uc=208,hc=209,dc=210,fc=211,pc=212,mc=213,gc=214,Jr=0,Qr=1,es=2,Zn=3,ts=4,ns=5,is=6,rs=7,mo=0,_c=1,vc=2,fn=0,xc=1,Mc=2,Sc=3,Ec=4,yc=5,Tc=6,Ac=7,go=300,jn=301,Jn=302,ss=303,as=304,dr=306,os=1e3,Rn=1001,cs=1002,Ht=1003,bc=1004,wi=1005,Wt=1006,_r=1007,Cn=1008,Yt=1009,_o=1010,vo=1011,pi=1012,Vs=1013,Pn=1014,nn=1015,xi=1016,ks=1017,Ws=1018,mi=1020,xo=35902,Mo=35899,So=1021,Eo=1022,zt=1023,gi=1026,_i=1027,yo=1028,Xs=1029,To=1030,qs=1031,Ys=1033,Qi=33776,er=33777,tr=33778,nr=33779,ls=35840,us=35841,hs=35842,ds=35843,fs=36196,ps=37492,ms=37496,gs=37808,_s=37809,vs=37810,xs=37811,Ms=37812,Ss=37813,Es=37814,ys=37815,Ts=37816,As=37817,bs=37818,ws=37819,Rs=37820,Cs=37821,Ps=36492,Ds=36494,Ls=36495,Is=36283,Us=36284,Ns=36285,Fs=36286,wc=3200,Rc=3201,Ao=0,Cc=1,hn="",Lt="srgb",Qn="srgb-linear",sr="linear",Ye="srgb",In=7680,da=519,Pc=512,Dc=513,Lc=514,bo=515,Ic=516,Uc=517,Nc=518,Fc=519,fa=35044,pa="300 es",Xt=2e3,ar=2001;class ti{addEventListener(e,t){this._listeners===void 0&&(this._listeners={});const n=this._listeners;n[e]===void 0&&(n[e]=[]),n[e].indexOf(t)===-1&&n[e].push(t)}hasEventListener(e,t){const n=this._listeners;return n===void 0?!1:n[e]!==void 0&&n[e].indexOf(t)!==-1}removeEventListener(e,t){const n=this._listeners;if(n===void 0)return;const r=n[e];if(r!==void 0){const s=r.indexOf(t);s!==-1&&r.splice(s,1)}}dispatchEvent(e){const t=this._listeners;if(t===void 0)return;const n=t[e.type];if(n!==void 0){e.target=this;const r=n.slice(0);for(let s=0,a=r.length;s>8&255]+gt[i>>16&255]+gt[i>>24&255]+"-"+gt[e&255]+gt[e>>8&255]+"-"+gt[e>>16&15|64]+gt[e>>24&255]+"-"+gt[t&63|128]+gt[t>>8&255]+"-"+gt[t>>16&255]+gt[t>>24&255]+gt[n&255]+gt[n>>8&255]+gt[n>>16&255]+gt[n>>24&255]).toLowerCase()}function ze(i,e,t){return Math.max(e,Math.min(t,i))}function Oc(i,e){return(i%e+e)%e}function vr(i,e,t){return(1-t)*i+t*e}function si(i,e){switch(e.constructor){case Float32Array:return i;case Uint32Array:return i/4294967295;case Uint16Array:return i/65535;case Uint8Array:return i/255;case Int32Array:return Math.max(i/2147483647,-1);case Int16Array:return Math.max(i/32767,-1);case Int8Array:return Math.max(i/127,-1);default:throw new Error("Invalid component type.")}}function St(i,e){switch(e.constructor){case Float32Array:return i;case Uint32Array:return Math.round(i*4294967295);case Uint16Array:return Math.round(i*65535);case Uint8Array:return Math.round(i*255);case Int32Array:return Math.round(i*2147483647);case Int16Array:return Math.round(i*32767);case Int8Array:return Math.round(i*127);default:throw new Error("Invalid component type.")}}class Ge{constructor(e=0,t=0){Ge.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){const t=this.x,n=this.y,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6],this.y=r[1]*t+r[4]*n+r[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=ze(this.x,e.x,t.x),this.y=ze(this.y,e.y,t.y),this}clampScalar(e,t){return this.x=ze(this.x,e,t),this.y=ze(this.y,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(ze(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(ze(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y;return t*t+n*n}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){const n=Math.cos(t),r=Math.sin(t),s=this.x-e.x,a=this.y-e.y;return this.x=s*n-a*r+e.x,this.y=s*r+a*n+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Si{constructor(e=0,t=0,n=0,r=1){this.isQuaternion=!0,this._x=e,this._y=t,this._z=n,this._w=r}static slerpFlat(e,t,n,r,s,a,o){let l=n[r+0],c=n[r+1],d=n[r+2],h=n[r+3];const f=s[a+0],m=s[a+1],_=s[a+2],x=s[a+3];if(o===0){e[t+0]=l,e[t+1]=c,e[t+2]=d,e[t+3]=h;return}if(o===1){e[t+0]=f,e[t+1]=m,e[t+2]=_,e[t+3]=x;return}if(h!==x||l!==f||c!==m||d!==_){let p=1-o;const u=l*f+c*m+d*_+h*x,b=u>=0?1:-1,A=1-u*u;if(A>Number.EPSILON){const C=Math.sqrt(A),R=Math.atan2(C,u*b);p=Math.sin(p*R)/C,o=Math.sin(o*R)/C}const E=o*b;if(l=l*p+f*E,c=c*p+m*E,d=d*p+_*E,h=h*p+x*E,p===1-o){const C=1/Math.sqrt(l*l+c*c+d*d+h*h);l*=C,c*=C,d*=C,h*=C}}e[t]=l,e[t+1]=c,e[t+2]=d,e[t+3]=h}static multiplyQuaternionsFlat(e,t,n,r,s,a){const o=n[r],l=n[r+1],c=n[r+2],d=n[r+3],h=s[a],f=s[a+1],m=s[a+2],_=s[a+3];return e[t]=o*_+d*h+l*m-c*f,e[t+1]=l*_+d*f+c*h-o*m,e[t+2]=c*_+d*m+o*f-l*h,e[t+3]=d*_-o*h-l*f-c*m,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,n,r){return this._x=e,this._y=t,this._z=n,this._w=r,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){const n=e._x,r=e._y,s=e._z,a=e._order,o=Math.cos,l=Math.sin,c=o(n/2),d=o(r/2),h=o(s/2),f=l(n/2),m=l(r/2),_=l(s/2);switch(a){case"XYZ":this._x=f*d*h+c*m*_,this._y=c*m*h-f*d*_,this._z=c*d*_+f*m*h,this._w=c*d*h-f*m*_;break;case"YXZ":this._x=f*d*h+c*m*_,this._y=c*m*h-f*d*_,this._z=c*d*_-f*m*h,this._w=c*d*h+f*m*_;break;case"ZXY":this._x=f*d*h-c*m*_,this._y=c*m*h+f*d*_,this._z=c*d*_+f*m*h,this._w=c*d*h-f*m*_;break;case"ZYX":this._x=f*d*h-c*m*_,this._y=c*m*h+f*d*_,this._z=c*d*_-f*m*h,this._w=c*d*h+f*m*_;break;case"YZX":this._x=f*d*h+c*m*_,this._y=c*m*h+f*d*_,this._z=c*d*_-f*m*h,this._w=c*d*h-f*m*_;break;case"XZY":this._x=f*d*h-c*m*_,this._y=c*m*h-f*d*_,this._z=c*d*_+f*m*h,this._w=c*d*h+f*m*_;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+a)}return t===!0&&this._onChangeCallback(),this}setFromAxisAngle(e,t){const n=t/2,r=Math.sin(n);return this._x=e.x*r,this._y=e.y*r,this._z=e.z*r,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(e){const t=e.elements,n=t[0],r=t[4],s=t[8],a=t[1],o=t[5],l=t[9],c=t[2],d=t[6],h=t[10],f=n+o+h;if(f>0){const m=.5/Math.sqrt(f+1);this._w=.25/m,this._x=(d-l)*m,this._y=(s-c)*m,this._z=(a-r)*m}else if(n>o&&n>h){const m=2*Math.sqrt(1+n-o-h);this._w=(d-l)/m,this._x=.25*m,this._y=(r+a)/m,this._z=(s+c)/m}else if(o>h){const m=2*Math.sqrt(1+o-n-h);this._w=(s-c)/m,this._x=(r+a)/m,this._y=.25*m,this._z=(l+d)/m}else{const m=2*Math.sqrt(1+h-n-o);this._w=(a-r)/m,this._x=(s+c)/m,this._y=(l+d)/m,this._z=.25*m}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let n=e.dot(t)+1;return n<1e-8?(n=0,Math.abs(e.x)>Math.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs(ze(this.dot(e),-1,1)))}rotateTowards(e,t){const n=this.angleTo(e);if(n===0)return this;const r=Math.min(1,t/n);return this.slerp(e,r),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return e===0?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){const n=e._x,r=e._y,s=e._z,a=e._w,o=t._x,l=t._y,c=t._z,d=t._w;return this._x=n*d+a*o+r*c-s*l,this._y=r*d+a*l+s*o-n*c,this._z=s*d+a*c+n*l-r*o,this._w=a*d-n*o-r*l-s*c,this._onChangeCallback(),this}slerp(e,t){if(t===0)return this;if(t===1)return this.copy(e);const n=this._x,r=this._y,s=this._z,a=this._w;let o=a*e._w+n*e._x+r*e._y+s*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=a,this._x=n,this._y=r,this._z=s,this;const l=1-o*o;if(l<=Number.EPSILON){const m=1-t;return this._w=m*a+t*this._w,this._x=m*n+t*this._x,this._y=m*r+t*this._y,this._z=m*s+t*this._z,this.normalize(),this}const c=Math.sqrt(l),d=Math.atan2(c,o),h=Math.sin((1-t)*d)/c,f=Math.sin(t*d)/c;return this._w=a*h+this._w*f,this._x=n*h+this._x*f,this._y=r*h+this._y*f,this._z=s*h+this._z*f,this._onChangeCallback(),this}slerpQuaternions(e,t,n){return this.copy(e).slerp(t,n)}random(){const e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),n=Math.random(),r=Math.sqrt(1-n),s=Math.sqrt(n);return this.set(r*Math.sin(e),r*Math.cos(e),s*Math.sin(t),s*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class N{constructor(e=0,t=0,n=0){N.prototype.isVector3=!0,this.x=e,this.y=t,this.z=n}set(e,t,n){return n===void 0&&(n=this.z),this.x=e,this.y=t,this.z=n,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(ma.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(ma.setFromAxisAngle(e,t))}applyMatrix3(e){const t=this.x,n=this.y,r=this.z,s=e.elements;return this.x=s[0]*t+s[3]*n+s[6]*r,this.y=s[1]*t+s[4]*n+s[7]*r,this.z=s[2]*t+s[5]*n+s[8]*r,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){const t=this.x,n=this.y,r=this.z,s=e.elements,a=1/(s[3]*t+s[7]*n+s[11]*r+s[15]);return this.x=(s[0]*t+s[4]*n+s[8]*r+s[12])*a,this.y=(s[1]*t+s[5]*n+s[9]*r+s[13])*a,this.z=(s[2]*t+s[6]*n+s[10]*r+s[14])*a,this}applyQuaternion(e){const t=this.x,n=this.y,r=this.z,s=e.x,a=e.y,o=e.z,l=e.w,c=2*(a*r-o*n),d=2*(o*t-s*r),h=2*(s*n-a*t);return this.x=t+l*c+a*h-o*d,this.y=n+l*d+o*c-s*h,this.z=r+l*h+s*d-a*c,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){const t=this.x,n=this.y,r=this.z,s=e.elements;return this.x=s[0]*t+s[4]*n+s[8]*r,this.y=s[1]*t+s[5]*n+s[9]*r,this.z=s[2]*t+s[6]*n+s[10]*r,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=ze(this.x,e.x,t.x),this.y=ze(this.y,e.y,t.y),this.z=ze(this.z,e.z,t.z),this}clampScalar(e,t){return this.x=ze(this.x,e,t),this.y=ze(this.y,e,t),this.z=ze(this.z,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(ze(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){const n=e.x,r=e.y,s=e.z,a=t.x,o=t.y,l=t.z;return this.x=r*l-s*o,this.y=s*a-n*l,this.z=n*o-r*a,this}projectOnVector(e){const t=e.lengthSq();if(t===0)return this.set(0,0,0);const n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)}projectOnPlane(e){return xr.copy(this).projectOnVector(e),this.sub(xr)}reflect(e){return this.sub(xr.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(ze(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y,r=this.z-e.z;return t*t+n*n+r*r}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,n){const r=Math.sin(t)*e;return this.x=r*Math.sin(n),this.y=Math.cos(t)*e,this.z=r*Math.cos(n),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){const t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),r=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=r,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,t*4)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,t*3)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const e=Math.random()*Math.PI*2,t=Math.random()*2-1,n=Math.sqrt(1-t*t);return this.x=n*Math.cos(e),this.y=t,this.z=n*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const xr=new N,ma=new Si;class Ie{constructor(e,t,n,r,s,a,o,l,c){Ie.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],e!==void 0&&this.set(e,t,n,r,s,a,o,l,c)}set(e,t,n,r,s,a,o,l,c){const d=this.elements;return d[0]=e,d[1]=r,d[2]=o,d[3]=t,d[4]=s,d[5]=l,d[6]=n,d[7]=a,d[8]=c,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this}extractBasis(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(e){const t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,r=t.elements,s=this.elements,a=n[0],o=n[3],l=n[6],c=n[1],d=n[4],h=n[7],f=n[2],m=n[5],_=n[8],x=r[0],p=r[3],u=r[6],b=r[1],A=r[4],E=r[7],C=r[2],R=r[5],w=r[8];return s[0]=a*x+o*b+l*C,s[3]=a*p+o*A+l*R,s[6]=a*u+o*E+l*w,s[1]=c*x+d*b+h*C,s[4]=c*p+d*A+h*R,s[7]=c*u+d*E+h*w,s[2]=f*x+m*b+_*C,s[5]=f*p+m*A+_*R,s[8]=f*u+m*E+_*w,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],l=e[6],c=e[7],d=e[8];return t*a*d-t*o*c-n*s*d+n*o*l+r*s*c-r*a*l}invert(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],l=e[6],c=e[7],d=e[8],h=d*a-o*c,f=o*l-d*s,m=c*s-a*l,_=t*h+n*f+r*m;if(_===0)return this.set(0,0,0,0,0,0,0,0,0);const x=1/_;return e[0]=h*x,e[1]=(r*c-d*n)*x,e[2]=(o*n-r*a)*x,e[3]=f*x,e[4]=(d*t-r*l)*x,e[5]=(r*s-o*t)*x,e[6]=m*x,e[7]=(n*l-c*t)*x,e[8]=(a*t-n*s)*x,this}transpose(){let e;const t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){const t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,n,r,s,a,o){const l=Math.cos(s),c=Math.sin(s);return this.set(n*l,n*c,-n*(l*a+c*o)+a+e,-r*c,r*l,-r*(-c*a+l*o)+o+t,0,0,1),this}scale(e,t){return this.premultiply(Mr.makeScale(e,t)),this}rotate(e){return this.premultiply(Mr.makeRotation(-e)),this}translate(e,t){return this.premultiply(Mr.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,n,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){const t=this.elements,n=e.elements;for(let r=0;r<9;r++)if(t[r]!==n[r])return!1;return!0}fromArray(e,t=0){for(let n=0;n<9;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}clone(){return new this.constructor().fromArray(this.elements)}}const Mr=new Ie;function wo(i){for(let e=i.length-1;e>=0;--e)if(i[e]>=65535)return!0;return!1}function or(i){return document.createElementNS("http://www.w3.org/1999/xhtml",i)}function Bc(){const i=or("canvas");return i.style.display="block",i}const ga={};function vi(i){i in ga||(ga[i]=!0,console.warn(i))}function zc(i,e,t){return new Promise(function(n,r){function s(){switch(i.clientWaitSync(e,i.SYNC_FLUSH_COMMANDS_BIT,0)){case i.WAIT_FAILED:r();break;case i.TIMEOUT_EXPIRED:setTimeout(s,t);break;default:n()}}setTimeout(s,t)})}const _a=new Ie().set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),va=new Ie().set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function Hc(){const i={enabled:!0,workingColorSpace:Qn,spaces:{},convert:function(r,s,a){return this.enabled===!1||s===a||!s||!a||(this.spaces[s].transfer===Ye&&(r.r=rn(r.r),r.g=rn(r.g),r.b=rn(r.b)),this.spaces[s].primaries!==this.spaces[a].primaries&&(r.applyMatrix3(this.spaces[s].toXYZ),r.applyMatrix3(this.spaces[a].fromXYZ)),this.spaces[a].transfer===Ye&&(r.r=Kn(r.r),r.g=Kn(r.g),r.b=Kn(r.b))),r},workingToColorSpace:function(r,s){return this.convert(r,this.workingColorSpace,s)},colorSpaceToWorking:function(r,s){return this.convert(r,s,this.workingColorSpace)},getPrimaries:function(r){return this.spaces[r].primaries},getTransfer:function(r){return r===hn?sr:this.spaces[r].transfer},getToneMappingMode:function(r){return this.spaces[r].outputColorSpaceConfig.toneMappingMode||"standard"},getLuminanceCoefficients:function(r,s=this.workingColorSpace){return r.fromArray(this.spaces[s].luminanceCoefficients)},define:function(r){Object.assign(this.spaces,r)},_getMatrix:function(r,s,a){return r.copy(this.spaces[s].toXYZ).multiply(this.spaces[a].fromXYZ)},_getDrawingBufferColorSpace:function(r){return this.spaces[r].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(r=this.workingColorSpace){return this.spaces[r].workingColorSpaceConfig.unpackColorSpace},fromWorkingColorSpace:function(r,s){return vi("THREE.ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."),i.workingToColorSpace(r,s)},toWorkingColorSpace:function(r,s){return vi("THREE.ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."),i.colorSpaceToWorking(r,s)}},e=[.64,.33,.3,.6,.15,.06],t=[.2126,.7152,.0722],n=[.3127,.329];return i.define({[Qn]:{primaries:e,whitePoint:n,transfer:sr,toXYZ:_a,fromXYZ:va,luminanceCoefficients:t,workingColorSpaceConfig:{unpackColorSpace:Lt},outputColorSpaceConfig:{drawingBufferColorSpace:Lt}},[Lt]:{primaries:e,whitePoint:n,transfer:Ye,toXYZ:_a,fromXYZ:va,luminanceCoefficients:t,outputColorSpaceConfig:{drawingBufferColorSpace:Lt}}}),i}const ke=Hc();function rn(i){return i<.04045?i*.0773993808:Math.pow(i*.9478672986+.0521327014,2.4)}function Kn(i){return i<.0031308?i*12.92:1.055*Math.pow(i,.41666)-.055}let Un;class Gc{static getDataURL(e,t="image/png"){if(/^data:/i.test(e.src)||typeof HTMLCanvasElement>"u")return e.src;let n;if(e instanceof HTMLCanvasElement)n=e;else{Un===void 0&&(Un=or("canvas")),Un.width=e.width,Un.height=e.height;const r=Un.getContext("2d");e instanceof ImageData?r.putImageData(e,0,0):r.drawImage(e,0,0,e.width,e.height),n=Un}return n.toDataURL(t)}static sRGBToLinear(e){if(typeof HTMLImageElement<"u"&&e instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&e instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&e instanceof ImageBitmap){const t=or("canvas");t.width=e.width,t.height=e.height;const n=t.getContext("2d");n.drawImage(e,0,0,e.width,e.height);const r=n.getImageData(0,0,e.width,e.height),s=r.data;for(let a=0;a1),this.pmremVersion=0}get width(){return this.source.getSize(Er).x}get height(){return this.source.getSize(Er).y}get depth(){return this.source.getSize(Er).z}get image(){return this.source.data}set image(e=null){this.source.data=e}updateMatrix(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}clone(){return new this.constructor().copy(this)}copy(e){return this.name=e.name,this.source=e.source,this.mipmaps=e.mipmaps.slice(0),this.mapping=e.mapping,this.channel=e.channel,this.wrapS=e.wrapS,this.wrapT=e.wrapT,this.magFilter=e.magFilter,this.minFilter=e.minFilter,this.anisotropy=e.anisotropy,this.format=e.format,this.internalFormat=e.internalFormat,this.type=e.type,this.offset.copy(e.offset),this.repeat.copy(e.repeat),this.center.copy(e.center),this.rotation=e.rotation,this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrix.copy(e.matrix),this.generateMipmaps=e.generateMipmaps,this.premultiplyAlpha=e.premultiplyAlpha,this.flipY=e.flipY,this.unpackAlignment=e.unpackAlignment,this.colorSpace=e.colorSpace,this.renderTarget=e.renderTarget,this.isRenderTargetTexture=e.isRenderTargetTexture,this.isArrayTexture=e.isArrayTexture,this.userData=JSON.parse(JSON.stringify(e.userData)),this.needsUpdate=!0,this}setValues(e){for(const t in e){const n=e[t];if(n===void 0){console.warn(`THREE.Texture.setValues(): parameter '${t}' has value of undefined.`);continue}const r=this[t];if(r===void 0){console.warn(`THREE.Texture.setValues(): property '${t}' does not exist.`);continue}r&&n&&r.isVector2&&n.isVector2||r&&n&&r.isVector3&&n.isVector3||r&&n&&r.isMatrix3&&n.isMatrix3?r.copy(n):this[t]=n}}toJSON(e){const t=e===void 0||typeof e=="string";if(!t&&e.textures[this.uuid]!==void 0)return e.textures[this.uuid];const n={metadata:{version:4.7,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,image:this.source.toJSON(e).uuid,mapping:this.mapping,channel:this.channel,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,internalFormat:this.internalFormat,type:this.type,colorSpace:this.colorSpace,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,generateMipmaps:this.generateMipmaps,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};return Object.keys(this.userData).length>0&&(n.userData=this.userData),t||(e.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==go)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case os:e.x=e.x-Math.floor(e.x);break;case Rn:e.x=e.x<0?0:1;break;case cs:Math.abs(Math.floor(e.x)%2)===1?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x);break}if(e.y<0||e.y>1)switch(this.wrapT){case os:e.y=e.y-Math.floor(e.y);break;case Rn:e.y=e.y<0?0:1;break;case cs:Math.abs(Math.floor(e.y)%2)===1?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y);break}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){e===!0&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){e===!0&&this.pmremVersion++}}Tt.DEFAULT_IMAGE=null;Tt.DEFAULT_MAPPING=go;Tt.DEFAULT_ANISOTROPY=1;class st{constructor(e=0,t=0,n=0,r=1){st.prototype.isVector4=!0,this.x=e,this.y=t,this.z=n,this.w=r}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,n,r){return this.x=e,this.y=t,this.z=n,this.w=r,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w!==void 0?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){const t=this.x,n=this.y,r=this.z,s=this.w,a=e.elements;return this.x=a[0]*t+a[4]*n+a[8]*r+a[12]*s,this.y=a[1]*t+a[5]*n+a[9]*r+a[13]*s,this.z=a[2]*t+a[6]*n+a[10]*r+a[14]*s,this.w=a[3]*t+a[7]*n+a[11]*r+a[15]*s,this}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this.w/=e.w,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);const t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,n,r,s;const l=e.elements,c=l[0],d=l[4],h=l[8],f=l[1],m=l[5],_=l[9],x=l[2],p=l[6],u=l[10];if(Math.abs(d-f)<.01&&Math.abs(h-x)<.01&&Math.abs(_-p)<.01){if(Math.abs(d+f)<.1&&Math.abs(h+x)<.1&&Math.abs(_+p)<.1&&Math.abs(c+m+u-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;const A=(c+1)/2,E=(m+1)/2,C=(u+1)/2,R=(d+f)/4,w=(h+x)/4,U=(_+p)/4;return A>E&&A>C?A<.01?(n=0,r=.707106781,s=.707106781):(n=Math.sqrt(A),r=R/n,s=w/n):E>C?E<.01?(n=.707106781,r=0,s=.707106781):(r=Math.sqrt(E),n=R/r,s=U/r):C<.01?(n=.707106781,r=.707106781,s=0):(s=Math.sqrt(C),n=w/s,r=U/s),this.set(n,r,s,t),this}let b=Math.sqrt((p-_)*(p-_)+(h-x)*(h-x)+(f-d)*(f-d));return Math.abs(b)<.001&&(b=1),this.x=(p-_)/b,this.y=(h-x)/b,this.z=(f-d)/b,this.w=Math.acos((c+m+u-1)/2),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this.w=t[15],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this}clamp(e,t){return this.x=ze(this.x,e.x,t.x),this.y=ze(this.y,e.y,t.y),this.z=ze(this.z,e.z,t.z),this.w=ze(this.w,e.w,t.w),this}clampScalar(e,t){return this.x=ze(this.x,e,t),this.y=ze(this.y,e,t),this.z=ze(this.z,e,t),this.w=ze(this.w,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(ze(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this.w=Math.trunc(this.w),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this.w=e.w+(t.w-e.w)*n,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this.w=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z,yield this.w}}class Wc extends ti{constructor(e=1,t=1,n={}){super(),n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:Wt,depthBuffer:!0,stencilBuffer:!1,resolveDepthBuffer:!0,resolveStencilBuffer:!0,depthTexture:null,samples:0,count:1,depth:1,multiview:!1},n),this.isRenderTarget=!0,this.width=e,this.height=t,this.depth=n.depth,this.scissor=new st(0,0,e,t),this.scissorTest=!1,this.viewport=new st(0,0,e,t);const r={width:e,height:t,depth:n.depth},s=new Tt(r);this.textures=[];const a=n.count;for(let o=0;o1;this.dispose()}this.viewport.set(0,0,e,t),this.scissor.set(0,0,e,t)}clone(){return new this.constructor().copy(this)}copy(e){this.width=e.width,this.height=e.height,this.depth=e.depth,this.scissor.copy(e.scissor),this.scissorTest=e.scissorTest,this.viewport.copy(e.viewport),this.textures.length=0;for(let t=0,n=e.textures.length;t=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}intersectsSphere(e){return this.clampPoint(e.center,Ft),Ft.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(ai),Ci.subVectors(this.max,ai),Nn.subVectors(e.a,ai),Fn.subVectors(e.b,ai),On.subVectors(e.c,ai),sn.subVectors(Fn,Nn),an.subVectors(On,Fn),vn.subVectors(Nn,On);let t=[0,-sn.z,sn.y,0,-an.z,an.y,0,-vn.z,vn.y,sn.z,0,-sn.x,an.z,0,-an.x,vn.z,0,-vn.x,-sn.y,sn.x,0,-an.y,an.x,0,-vn.y,vn.x,0];return!yr(t,Nn,Fn,On,Ci)||(t=[1,0,0,0,1,0,0,0,1],!yr(t,Nn,Fn,On,Ci))?!1:(Pi.crossVectors(sn,an),t=[Pi.x,Pi.y,Pi.z],yr(t,Nn,Fn,On,Ci))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Ft).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=this.getSize(Ft).length()*.5),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()?this:(Zt[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),Zt[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),Zt[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),Zt[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),Zt[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),Zt[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),Zt[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),Zt[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(Zt),this)}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}toJSON(){return{min:this.min.toArray(),max:this.max.toArray()}}fromJSON(e){return this.min.fromArray(e.min),this.max.fromArray(e.max),this}}const Zt=[new N,new N,new N,new N,new N,new N,new N,new N],Ft=new N,Ri=new Ei,Nn=new N,Fn=new N,On=new N,sn=new N,an=new N,vn=new N,ai=new N,Ci=new N,Pi=new N,xn=new N;function yr(i,e,t,n,r){for(let s=0,a=i.length-3;s<=a;s+=3){xn.fromArray(i,s);const o=r.x*Math.abs(xn.x)+r.y*Math.abs(xn.y)+r.z*Math.abs(xn.z),l=e.dot(xn),c=t.dot(xn),d=n.dot(xn);if(Math.max(-Math.max(l,c,d),Math.min(l,c,d))>o)return!1}return!0}const qc=new Ei,oi=new N,Tr=new N;class fr{constructor(e=new N,t=-1){this.isSphere=!0,this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){const n=this.center;t!==void 0?n.copy(t):qc.setFromPoints(e).getCenter(n);let r=0;for(let s=0,a=e.length;sthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;oi.subVectors(e,this.center);const t=oi.lengthSq();if(t>this.radius*this.radius){const n=Math.sqrt(t),r=(n-this.radius)*.5;this.center.addScaledVector(oi,r/n),this.radius+=r}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(this.center.equals(e.center)===!0?this.radius=Math.max(this.radius,e.radius):(Tr.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(oi.copy(e.center).add(Tr)),this.expandByPoint(oi.copy(e.center).sub(Tr))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return new this.constructor().copy(this)}toJSON(){return{radius:this.radius,center:this.center.toArray()}}fromJSON(e){return this.radius=e.radius,this.center.fromArray(e.center),this}}const jt=new N,Ar=new N,Di=new N,on=new N,br=new N,Li=new N,wr=new N;class Ks{constructor(e=new N,t=new N(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,jt)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);const n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){const t=jt.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(jt.copy(this.origin).addScaledVector(this.direction,t),jt.distanceToSquared(e))}distanceSqToSegment(e,t,n,r){Ar.copy(e).add(t).multiplyScalar(.5),Di.copy(t).sub(e).normalize(),on.copy(this.origin).sub(Ar);const s=e.distanceTo(t)*.5,a=-this.direction.dot(Di),o=on.dot(this.direction),l=-on.dot(Di),c=on.lengthSq(),d=Math.abs(1-a*a);let h,f,m,_;if(d>0)if(h=a*l-o,f=a*o-l,_=s*d,h>=0)if(f>=-_)if(f<=_){const x=1/d;h*=x,f*=x,m=h*(h+a*f+2*o)+f*(a*h+f+2*l)+c}else f=s,h=Math.max(0,-(a*f+o)),m=-h*h+f*(f+2*l)+c;else f=-s,h=Math.max(0,-(a*f+o)),m=-h*h+f*(f+2*l)+c;else f<=-_?(h=Math.max(0,-(-a*s+o)),f=h>0?-s:Math.min(Math.max(-s,-l),s),m=-h*h+f*(f+2*l)+c):f<=_?(h=0,f=Math.min(Math.max(-s,-l),s),m=f*(f+2*l)+c):(h=Math.max(0,-(a*s+o)),f=h>0?s:Math.min(Math.max(-s,-l),s),m=-h*h+f*(f+2*l)+c);else f=a>0?-s:s,h=Math.max(0,-(a*f+o)),m=-h*h+f*(f+2*l)+c;return n&&n.copy(this.origin).addScaledVector(this.direction,h),r&&r.copy(Ar).addScaledVector(Di,f),m}intersectSphere(e,t){jt.subVectors(e.center,this.origin);const n=jt.dot(this.direction),r=jt.dot(jt)-n*n,s=e.radius*e.radius;if(r>s)return null;const a=Math.sqrt(s-r),o=n-a,l=n+a;return l<0?null:o<0?this.at(l,t):this.at(o,t)}intersectsSphere(e){return e.radius<0?!1:this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){const t=e.normal.dot(this.direction);if(t===0)return e.distanceToPoint(this.origin)===0?0:null;const n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null}intersectPlane(e,t){const n=this.distanceToPlane(e);return n===null?null:this.at(n,t)}intersectsPlane(e){const t=e.distanceToPoint(this.origin);return t===0||e.normal.dot(this.direction)*t<0}intersectBox(e,t){let n,r,s,a,o,l;const c=1/this.direction.x,d=1/this.direction.y,h=1/this.direction.z,f=this.origin;return c>=0?(n=(e.min.x-f.x)*c,r=(e.max.x-f.x)*c):(n=(e.max.x-f.x)*c,r=(e.min.x-f.x)*c),d>=0?(s=(e.min.y-f.y)*d,a=(e.max.y-f.y)*d):(s=(e.max.y-f.y)*d,a=(e.min.y-f.y)*d),n>a||s>r||((s>n||isNaN(n))&&(n=s),(a=0?(o=(e.min.z-f.z)*h,l=(e.max.z-f.z)*h):(o=(e.max.z-f.z)*h,l=(e.min.z-f.z)*h),n>l||o>r)||((o>n||n!==n)&&(n=o),(l=0?n:r,t)}intersectsBox(e){return this.intersectBox(e,jt)!==null}intersectTriangle(e,t,n,r,s){br.subVectors(t,e),Li.subVectors(n,e),wr.crossVectors(br,Li);let a=this.direction.dot(wr),o;if(a>0){if(r)return null;o=1}else if(a<0)o=-1,a=-a;else return null;on.subVectors(this.origin,e);const l=o*this.direction.dot(Li.crossVectors(on,Li));if(l<0)return null;const c=o*this.direction.dot(br.cross(on));if(c<0||l+c>a)return null;const d=-o*on.dot(wr);return d<0?null:this.at(d/a,s)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}}class it{constructor(e,t,n,r,s,a,o,l,c,d,h,f,m,_,x,p){it.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],e!==void 0&&this.set(e,t,n,r,s,a,o,l,c,d,h,f,m,_,x,p)}set(e,t,n,r,s,a,o,l,c,d,h,f,m,_,x,p){const u=this.elements;return u[0]=e,u[4]=t,u[8]=n,u[12]=r,u[1]=s,u[5]=a,u[9]=o,u[13]=l,u[2]=c,u[6]=d,u[10]=h,u[14]=f,u[3]=m,u[7]=_,u[11]=x,u[15]=p,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return new it().fromArray(this.elements)}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],this}copyPosition(e){const t=this.elements,n=e.elements;return t[12]=n[12],t[13]=n[13],t[14]=n[14],this}setFromMatrix3(e){const t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,n){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(e,t,n){return this.set(e.x,t.x,n.x,0,e.y,t.y,n.y,0,e.z,t.z,n.z,0,0,0,0,1),this}extractRotation(e){const t=this.elements,n=e.elements,r=1/Bn.setFromMatrixColumn(e,0).length(),s=1/Bn.setFromMatrixColumn(e,1).length(),a=1/Bn.setFromMatrixColumn(e,2).length();return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=0,t[4]=n[4]*s,t[5]=n[5]*s,t[6]=n[6]*s,t[7]=0,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){const t=this.elements,n=e.x,r=e.y,s=e.z,a=Math.cos(n),o=Math.sin(n),l=Math.cos(r),c=Math.sin(r),d=Math.cos(s),h=Math.sin(s);if(e.order==="XYZ"){const f=a*d,m=a*h,_=o*d,x=o*h;t[0]=l*d,t[4]=-l*h,t[8]=c,t[1]=m+_*c,t[5]=f-x*c,t[9]=-o*l,t[2]=x-f*c,t[6]=_+m*c,t[10]=a*l}else if(e.order==="YXZ"){const f=l*d,m=l*h,_=c*d,x=c*h;t[0]=f+x*o,t[4]=_*o-m,t[8]=a*c,t[1]=a*h,t[5]=a*d,t[9]=-o,t[2]=m*o-_,t[6]=x+f*o,t[10]=a*l}else if(e.order==="ZXY"){const f=l*d,m=l*h,_=c*d,x=c*h;t[0]=f-x*o,t[4]=-a*h,t[8]=_+m*o,t[1]=m+_*o,t[5]=a*d,t[9]=x-f*o,t[2]=-a*c,t[6]=o,t[10]=a*l}else if(e.order==="ZYX"){const f=a*d,m=a*h,_=o*d,x=o*h;t[0]=l*d,t[4]=_*c-m,t[8]=f*c+x,t[1]=l*h,t[5]=x*c+f,t[9]=m*c-_,t[2]=-c,t[6]=o*l,t[10]=a*l}else if(e.order==="YZX"){const f=a*l,m=a*c,_=o*l,x=o*c;t[0]=l*d,t[4]=x-f*h,t[8]=_*h+m,t[1]=h,t[5]=a*d,t[9]=-o*d,t[2]=-c*d,t[6]=m*h+_,t[10]=f-x*h}else if(e.order==="XZY"){const f=a*l,m=a*c,_=o*l,x=o*c;t[0]=l*d,t[4]=-h,t[8]=c*d,t[1]=f*h+x,t[5]=a*d,t[9]=m*h-_,t[2]=_*h-m,t[6]=o*d,t[10]=x*h+f}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(Yc,e,$c)}lookAt(e,t,n){const r=this.elements;return wt.subVectors(e,t),wt.lengthSq()===0&&(wt.z=1),wt.normalize(),cn.crossVectors(n,wt),cn.lengthSq()===0&&(Math.abs(n.z)===1?wt.x+=1e-4:wt.z+=1e-4,wt.normalize(),cn.crossVectors(n,wt)),cn.normalize(),Ii.crossVectors(wt,cn),r[0]=cn.x,r[4]=Ii.x,r[8]=wt.x,r[1]=cn.y,r[5]=Ii.y,r[9]=wt.y,r[2]=cn.z,r[6]=Ii.z,r[10]=wt.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,r=t.elements,s=this.elements,a=n[0],o=n[4],l=n[8],c=n[12],d=n[1],h=n[5],f=n[9],m=n[13],_=n[2],x=n[6],p=n[10],u=n[14],b=n[3],A=n[7],E=n[11],C=n[15],R=r[0],w=r[4],U=r[8],S=r[12],M=r[1],P=r[5],O=r[9],H=r[13],q=r[2],W=r[6],X=r[10],Z=r[14],G=r[3],se=r[7],le=r[11],Ee=r[15];return s[0]=a*R+o*M+l*q+c*G,s[4]=a*w+o*P+l*W+c*se,s[8]=a*U+o*O+l*X+c*le,s[12]=a*S+o*H+l*Z+c*Ee,s[1]=d*R+h*M+f*q+m*G,s[5]=d*w+h*P+f*W+m*se,s[9]=d*U+h*O+f*X+m*le,s[13]=d*S+h*H+f*Z+m*Ee,s[2]=_*R+x*M+p*q+u*G,s[6]=_*w+x*P+p*W+u*se,s[10]=_*U+x*O+p*X+u*le,s[14]=_*S+x*H+p*Z+u*Ee,s[3]=b*R+A*M+E*q+C*G,s[7]=b*w+A*P+E*W+C*se,s[11]=b*U+A*O+E*X+C*le,s[15]=b*S+A*H+E*Z+C*Ee,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[4],r=e[8],s=e[12],a=e[1],o=e[5],l=e[9],c=e[13],d=e[2],h=e[6],f=e[10],m=e[14],_=e[3],x=e[7],p=e[11],u=e[15];return _*(+s*l*h-r*c*h-s*o*f+n*c*f+r*o*m-n*l*m)+x*(+t*l*m-t*c*f+s*a*f-r*a*m+r*c*d-s*l*d)+p*(+t*c*h-t*o*m-s*a*h+n*a*m+s*o*d-n*c*d)+u*(-r*o*d-t*l*h+t*o*f+r*a*h-n*a*f+n*l*d)}transpose(){const e=this.elements;let t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,n){const r=this.elements;return e.isVector3?(r[12]=e.x,r[13]=e.y,r[14]=e.z):(r[12]=e,r[13]=t,r[14]=n),this}invert(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],l=e[6],c=e[7],d=e[8],h=e[9],f=e[10],m=e[11],_=e[12],x=e[13],p=e[14],u=e[15],b=h*p*c-x*f*c+x*l*m-o*p*m-h*l*u+o*f*u,A=_*f*c-d*p*c-_*l*m+a*p*m+d*l*u-a*f*u,E=d*x*c-_*h*c+_*o*m-a*x*m-d*o*u+a*h*u,C=_*h*l-d*x*l-_*o*f+a*x*f+d*o*p-a*h*p,R=t*b+n*A+r*E+s*C;if(R===0)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const w=1/R;return e[0]=b*w,e[1]=(x*f*s-h*p*s-x*r*m+n*p*m+h*r*u-n*f*u)*w,e[2]=(o*p*s-x*l*s+x*r*c-n*p*c-o*r*u+n*l*u)*w,e[3]=(h*l*s-o*f*s-h*r*c+n*f*c+o*r*m-n*l*m)*w,e[4]=A*w,e[5]=(d*p*s-_*f*s+_*r*m-t*p*m-d*r*u+t*f*u)*w,e[6]=(_*l*s-a*p*s-_*r*c+t*p*c+a*r*u-t*l*u)*w,e[7]=(a*f*s-d*l*s+d*r*c-t*f*c-a*r*m+t*l*m)*w,e[8]=E*w,e[9]=(_*h*s-d*x*s-_*n*m+t*x*m+d*n*u-t*h*u)*w,e[10]=(a*x*s-_*o*s+_*n*c-t*x*c-a*n*u+t*o*u)*w,e[11]=(d*o*s-a*h*s-d*n*c+t*h*c+a*n*m-t*o*m)*w,e[12]=C*w,e[13]=(d*x*r-_*h*r+_*n*f-t*x*f-d*n*p+t*h*p)*w,e[14]=(_*o*r-a*x*r-_*n*l+t*x*l+a*n*p-t*o*p)*w,e[15]=(a*h*r-d*o*r+d*n*l-t*h*l-a*n*f+t*o*f)*w,this}scale(e){const t=this.elements,n=e.x,r=e.y,s=e.z;return t[0]*=n,t[4]*=r,t[8]*=s,t[1]*=n,t[5]*=r,t[9]*=s,t[2]*=n,t[6]*=r,t[10]*=s,t[3]*=n,t[7]*=r,t[11]*=s,this}getMaxScaleOnAxis(){const e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],n=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],r=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,n,r))}makeTranslation(e,t,n){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,n,0,0,0,1),this}makeRotationX(e){const t=Math.cos(e),n=Math.sin(e);return this.set(1,0,0,0,0,t,-n,0,0,n,t,0,0,0,0,1),this}makeRotationY(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,0,n,0,0,1,0,0,-n,0,t,0,0,0,0,1),this}makeRotationZ(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,0,n,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){const n=Math.cos(t),r=Math.sin(t),s=1-n,a=e.x,o=e.y,l=e.z,c=s*a,d=s*o;return this.set(c*a+n,c*o-r*l,c*l+r*o,0,c*o+r*l,d*o+n,d*l-r*a,0,c*l-r*o,d*l+r*a,s*l*l+n,0,0,0,0,1),this}makeScale(e,t,n){return this.set(e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1),this}makeShear(e,t,n,r,s,a){return this.set(1,n,s,0,e,1,a,0,t,r,1,0,0,0,0,1),this}compose(e,t,n){const r=this.elements,s=t._x,a=t._y,o=t._z,l=t._w,c=s+s,d=a+a,h=o+o,f=s*c,m=s*d,_=s*h,x=a*d,p=a*h,u=o*h,b=l*c,A=l*d,E=l*h,C=n.x,R=n.y,w=n.z;return r[0]=(1-(x+u))*C,r[1]=(m+E)*C,r[2]=(_-A)*C,r[3]=0,r[4]=(m-E)*R,r[5]=(1-(f+u))*R,r[6]=(p+b)*R,r[7]=0,r[8]=(_+A)*w,r[9]=(p-b)*w,r[10]=(1-(f+x))*w,r[11]=0,r[12]=e.x,r[13]=e.y,r[14]=e.z,r[15]=1,this}decompose(e,t,n){const r=this.elements;let s=Bn.set(r[0],r[1],r[2]).length();const a=Bn.set(r[4],r[5],r[6]).length(),o=Bn.set(r[8],r[9],r[10]).length();this.determinant()<0&&(s=-s),e.x=r[12],e.y=r[13],e.z=r[14],Ot.copy(this);const c=1/s,d=1/a,h=1/o;return Ot.elements[0]*=c,Ot.elements[1]*=c,Ot.elements[2]*=c,Ot.elements[4]*=d,Ot.elements[5]*=d,Ot.elements[6]*=d,Ot.elements[8]*=h,Ot.elements[9]*=h,Ot.elements[10]*=h,t.setFromRotationMatrix(Ot),n.x=s,n.y=a,n.z=o,this}makePerspective(e,t,n,r,s,a,o=Xt,l=!1){const c=this.elements,d=2*s/(t-e),h=2*s/(n-r),f=(t+e)/(t-e),m=(n+r)/(n-r);let _,x;if(l)_=s/(a-s),x=a*s/(a-s);else if(o===Xt)_=-(a+s)/(a-s),x=-2*a*s/(a-s);else if(o===ar)_=-a/(a-s),x=-a*s/(a-s);else throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+o);return c[0]=d,c[4]=0,c[8]=f,c[12]=0,c[1]=0,c[5]=h,c[9]=m,c[13]=0,c[2]=0,c[6]=0,c[10]=_,c[14]=x,c[3]=0,c[7]=0,c[11]=-1,c[15]=0,this}makeOrthographic(e,t,n,r,s,a,o=Xt,l=!1){const c=this.elements,d=2/(t-e),h=2/(n-r),f=-(t+e)/(t-e),m=-(n+r)/(n-r);let _,x;if(l)_=1/(a-s),x=a/(a-s);else if(o===Xt)_=-2/(a-s),x=-(a+s)/(a-s);else if(o===ar)_=-1/(a-s),x=-s/(a-s);else throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);return c[0]=d,c[4]=0,c[8]=0,c[12]=f,c[1]=0,c[5]=h,c[9]=0,c[13]=m,c[2]=0,c[6]=0,c[10]=_,c[14]=x,c[3]=0,c[7]=0,c[11]=0,c[15]=1,this}equals(e){const t=this.elements,n=e.elements;for(let r=0;r<16;r++)if(t[r]!==n[r])return!1;return!0}fromArray(e,t=0){for(let n=0;n<16;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e[t+9]=n[9],e[t+10]=n[10],e[t+11]=n[11],e[t+12]=n[12],e[t+13]=n[13],e[t+14]=n[14],e[t+15]=n[15],e}}const Bn=new N,Ot=new it,Yc=new N(0,0,0),$c=new N(1,1,1),cn=new N,Ii=new N,wt=new N,xa=new it,Ma=new Si;class $t{constructor(e=0,t=0,n=0,r=$t.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=n,this._order=r}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,n,r=this._order){return this._x=e,this._y=t,this._z=n,this._order=r,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,n=!0){const r=e.elements,s=r[0],a=r[4],o=r[8],l=r[1],c=r[5],d=r[9],h=r[2],f=r[6],m=r[10];switch(t){case"XYZ":this._y=Math.asin(ze(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-d,m),this._z=Math.atan2(-a,s)):(this._x=Math.atan2(f,c),this._z=0);break;case"YXZ":this._x=Math.asin(-ze(d,-1,1)),Math.abs(d)<.9999999?(this._y=Math.atan2(o,m),this._z=Math.atan2(l,c)):(this._y=Math.atan2(-h,s),this._z=0);break;case"ZXY":this._x=Math.asin(ze(f,-1,1)),Math.abs(f)<.9999999?(this._y=Math.atan2(-h,m),this._z=Math.atan2(-a,c)):(this._y=0,this._z=Math.atan2(l,s));break;case"ZYX":this._y=Math.asin(-ze(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(f,m),this._z=Math.atan2(l,s)):(this._x=0,this._z=Math.atan2(-a,c));break;case"YZX":this._z=Math.asin(ze(l,-1,1)),Math.abs(l)<.9999999?(this._x=Math.atan2(-d,c),this._y=Math.atan2(-h,s)):(this._x=0,this._y=Math.atan2(o,m));break;case"XZY":this._z=Math.asin(-ze(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(f,c),this._y=Math.atan2(o,s)):(this._x=Math.atan2(-d,m),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,n===!0&&this._onChangeCallback(),this}setFromQuaternion(e,t,n){return xa.makeRotationFromQuaternion(e),this.setFromRotationMatrix(xa,t,n)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return Ma.setFromEuler(this),this.setFromQuaternion(Ma,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],e[3]!==void 0&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}$t.DEFAULT_ORDER="XYZ";class Zs{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let t=0;t1){for(let n=0;n0&&(r.userData=this.userData),r.layers=this.layers.mask,r.matrix=this.matrix.toArray(),r.up=this.up.toArray(),this.matrixAutoUpdate===!1&&(r.matrixAutoUpdate=!1),this.isInstancedMesh&&(r.type="InstancedMesh",r.count=this.count,r.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(r.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(r.type="BatchedMesh",r.perObjectFrustumCulled=this.perObjectFrustumCulled,r.sortObjects=this.sortObjects,r.drawRanges=this._drawRanges,r.reservedRanges=this._reservedRanges,r.geometryInfo=this._geometryInfo.map(o=>({...o,boundingBox:o.boundingBox?o.boundingBox.toJSON():void 0,boundingSphere:o.boundingSphere?o.boundingSphere.toJSON():void 0})),r.instanceInfo=this._instanceInfo.map(o=>({...o})),r.availableInstanceIds=this._availableInstanceIds.slice(),r.availableGeometryIds=this._availableGeometryIds.slice(),r.nextIndexStart=this._nextIndexStart,r.nextVertexStart=this._nextVertexStart,r.geometryCount=this._geometryCount,r.maxInstanceCount=this._maxInstanceCount,r.maxVertexCount=this._maxVertexCount,r.maxIndexCount=this._maxIndexCount,r.geometryInitialized=this._geometryInitialized,r.matricesTexture=this._matricesTexture.toJSON(e),r.indirectTexture=this._indirectTexture.toJSON(e),this._colorsTexture!==null&&(r.colorsTexture=this._colorsTexture.toJSON(e)),this.boundingSphere!==null&&(r.boundingSphere=this.boundingSphere.toJSON()),this.boundingBox!==null&&(r.boundingBox=this.boundingBox.toJSON()));function s(o,l){return o[l.uuid]===void 0&&(o[l.uuid]=l.toJSON(e)),l.uuid}if(this.isScene)this.background&&(this.background.isColor?r.background=this.background.toJSON():this.background.isTexture&&(r.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(r.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){r.geometry=s(e.geometries,this.geometry);const o=this.geometry.parameters;if(o!==void 0&&o.shapes!==void 0){const l=o.shapes;if(Array.isArray(l))for(let c=0,d=l.length;c0){r.children=[];for(let o=0;o0){r.animations=[];for(let o=0;o0&&(n.geometries=o),l.length>0&&(n.materials=l),c.length>0&&(n.textures=c),d.length>0&&(n.images=d),h.length>0&&(n.shapes=h),f.length>0&&(n.skeletons=f),m.length>0&&(n.animations=m),_.length>0&&(n.nodes=_)}return n.object=r,n;function a(o){const l=[];for(const c in o){const d=o[c];delete d.metadata,l.push(d)}return l}}clone(e){return new this.constructor().copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),t===!0)for(let n=0;n0?r.multiplyScalar(1/Math.sqrt(s)):r.set(0,0,0)}static getBarycoord(e,t,n,r,s){Bt.subVectors(r,t),Qt.subVectors(n,t),Cr.subVectors(e,t);const a=Bt.dot(Bt),o=Bt.dot(Qt),l=Bt.dot(Cr),c=Qt.dot(Qt),d=Qt.dot(Cr),h=a*c-o*o;if(h===0)return s.set(0,0,0),null;const f=1/h,m=(c*l-o*d)*f,_=(a*d-o*l)*f;return s.set(1-m-_,_,m)}static containsPoint(e,t,n,r){return this.getBarycoord(e,t,n,r,en)===null?!1:en.x>=0&&en.y>=0&&en.x+en.y<=1}static getInterpolation(e,t,n,r,s,a,o,l){return this.getBarycoord(e,t,n,r,en)===null?(l.x=0,l.y=0,"z"in l&&(l.z=0),"w"in l&&(l.w=0),null):(l.setScalar(0),l.addScaledVector(s,en.x),l.addScaledVector(a,en.y),l.addScaledVector(o,en.z),l)}static getInterpolatedAttribute(e,t,n,r,s,a){return Ir.setScalar(0),Ur.setScalar(0),Nr.setScalar(0),Ir.fromBufferAttribute(e,t),Ur.fromBufferAttribute(e,n),Nr.fromBufferAttribute(e,r),a.setScalar(0),a.addScaledVector(Ir,s.x),a.addScaledVector(Ur,s.y),a.addScaledVector(Nr,s.z),a}static isFrontFacing(e,t,n,r){return Bt.subVectors(n,t),Qt.subVectors(e,t),Bt.cross(Qt).dot(r)<0}set(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this}setFromPointsAndIndices(e,t,n,r){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[r]),this}setFromAttributeAndIndices(e,t,n,r){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,n),this.c.fromBufferAttribute(e,r),this}clone(){return new this.constructor().copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return Bt.subVectors(this.c,this.b),Qt.subVectors(this.a,this.b),Bt.cross(Qt).length()*.5}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return Ut.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return Ut.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,n,r,s){return Ut.getInterpolation(e,this.a,this.b,this.c,t,n,r,s)}containsPoint(e){return Ut.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return Ut.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){const n=this.a,r=this.b,s=this.c;let a,o;Gn.subVectors(r,n),Vn.subVectors(s,n),Pr.subVectors(e,n);const l=Gn.dot(Pr),c=Vn.dot(Pr);if(l<=0&&c<=0)return t.copy(n);Dr.subVectors(e,r);const d=Gn.dot(Dr),h=Vn.dot(Dr);if(d>=0&&h<=d)return t.copy(r);const f=l*h-d*c;if(f<=0&&l>=0&&d<=0)return a=l/(l-d),t.copy(n).addScaledVector(Gn,a);Lr.subVectors(e,s);const m=Gn.dot(Lr),_=Vn.dot(Lr);if(_>=0&&m<=_)return t.copy(s);const x=m*c-l*_;if(x<=0&&c>=0&&_<=0)return o=c/(c-_),t.copy(n).addScaledVector(Vn,o);const p=d*_-m*h;if(p<=0&&h-d>=0&&m-_>=0)return ba.subVectors(s,r),o=(h-d)/(h-d+(m-_)),t.copy(r).addScaledVector(ba,o);const u=1/(p+x+f);return a=x*u,o=f*u,t.copy(n).addScaledVector(Gn,a).addScaledVector(Vn,o)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}}const Co={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},ln={h:0,s:0,l:0},Ni={h:0,s:0,l:0};function Fr(i,e,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?i+(e-i)*6*t:t<1/2?e:t<2/3?i+(e-i)*6*(2/3-t):i}class Fe{constructor(e,t,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,n)}set(e,t,n){if(t===void 0&&n===void 0){const r=e;r&&r.isColor?this.copy(r):typeof r=="number"?this.setHex(r):typeof r=="string"&&this.setStyle(r)}else this.setRGB(e,t,n);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=Lt){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(e&255)/255,ke.colorSpaceToWorking(this,t),this}setRGB(e,t,n,r=ke.workingColorSpace){return this.r=e,this.g=t,this.b=n,ke.colorSpaceToWorking(this,r),this}setHSL(e,t,n,r=ke.workingColorSpace){if(e=Oc(e,1),t=ze(t,0,1),n=ze(n,0,1),t===0)this.r=this.g=this.b=n;else{const s=n<=.5?n*(1+t):n+t-n*t,a=2*n-s;this.r=Fr(a,s,e+1/3),this.g=Fr(a,s,e),this.b=Fr(a,s,e-1/3)}return ke.colorSpaceToWorking(this,r),this}setStyle(e,t=Lt){function n(s){s!==void 0&&parseFloat(s)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let r;if(r=/^(\w+)\(([^\)]*)\)/.exec(e)){let s;const a=r[1],o=r[2];switch(a){case"rgb":case"rgba":if(s=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setRGB(Math.min(255,parseInt(s[1],10))/255,Math.min(255,parseInt(s[2],10))/255,Math.min(255,parseInt(s[3],10))/255,t);if(s=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setRGB(Math.min(100,parseInt(s[1],10))/100,Math.min(100,parseInt(s[2],10))/100,Math.min(100,parseInt(s[3],10))/100,t);break;case"hsl":case"hsla":if(s=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setHSL(parseFloat(s[1])/360,parseFloat(s[2])/100,parseFloat(s[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(r=/^\#([A-Fa-f\d]+)$/.exec(e)){const s=r[1],a=s.length;if(a===3)return this.setRGB(parseInt(s.charAt(0),16)/15,parseInt(s.charAt(1),16)/15,parseInt(s.charAt(2),16)/15,t);if(a===6)return this.setHex(parseInt(s,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=Lt){const n=Co[e.toLowerCase()];return n!==void 0?this.setHex(n,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=rn(e.r),this.g=rn(e.g),this.b=rn(e.b),this}copyLinearToSRGB(e){return this.r=Kn(e.r),this.g=Kn(e.g),this.b=Kn(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=Lt){return ke.workingToColorSpace(_t.copy(this),e),Math.round(ze(_t.r*255,0,255))*65536+Math.round(ze(_t.g*255,0,255))*256+Math.round(ze(_t.b*255,0,255))}getHexString(e=Lt){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=ke.workingColorSpace){ke.workingToColorSpace(_t.copy(this),t);const n=_t.r,r=_t.g,s=_t.b,a=Math.max(n,r,s),o=Math.min(n,r,s);let l,c;const d=(o+a)/2;if(o===a)l=0,c=0;else{const h=a-o;switch(c=d<=.5?h/(a+o):h/(2-a-o),a){case n:l=(r-s)/h+(r0!=e>0&&this.version++,this._alphaTest=e}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(e!==void 0)for(const t in e){const n=e[t];if(n===void 0){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}const r=this[t];if(r===void 0){console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`);continue}r&&r.isColor?r.set(n):r&&r.isVector3&&n&&n.isVector3?r.copy(n):this[t]=n}}toJSON(e){const t=e===void 0||typeof e=="string";t&&(e={textures:{},images:{}});const n={metadata:{version:4.7,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,this.name!==""&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),this.roughness!==void 0&&(n.roughness=this.roughness),this.metalness!==void 0&&(n.metalness=this.metalness),this.sheen!==void 0&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),this.sheenRoughness!==void 0&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity!==void 0&&this.emissiveIntensity!==1&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),this.specularIntensity!==void 0&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),this.shininess!==void 0&&(n.shininess=this.shininess),this.clearcoat!==void 0&&(n.clearcoat=this.clearcoat),this.clearcoatRoughness!==void 0&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.sheenColorMap&&this.sheenColorMap.isTexture&&(n.sheenColorMap=this.sheenColorMap.toJSON(e).uuid),this.sheenRoughnessMap&&this.sheenRoughnessMap.isTexture&&(n.sheenRoughnessMap=this.sheenRoughnessMap.toJSON(e).uuid),this.dispersion!==void 0&&(n.dispersion=this.dispersion),this.iridescence!==void 0&&(n.iridescence=this.iridescence),this.iridescenceIOR!==void 0&&(n.iridescenceIOR=this.iridescenceIOR),this.iridescenceThicknessRange!==void 0&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),this.anisotropy!==void 0&&(n.anisotropy=this.anisotropy),this.anisotropyRotation!==void 0&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(e).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(e).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(e).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(e).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(e).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(e).uuid,this.combine!==void 0&&(n.combine=this.combine)),this.envMapRotation!==void 0&&(n.envMapRotation=this.envMapRotation.toArray()),this.envMapIntensity!==void 0&&(n.envMapIntensity=this.envMapIntensity),this.reflectivity!==void 0&&(n.reflectivity=this.reflectivity),this.refractionRatio!==void 0&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(e).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(e).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(e).uuid),this.attenuationDistance!==void 0&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.shadowSide!==null&&(n.shadowSide=this.shadowSide),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==$n&&(n.blending=this.blending),this.side!==pn&&(n.side=this.side),this.vertexColors===!0&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.transparent===!0&&(n.transparent=!0),this.blendSrc!==Zr&&(n.blendSrc=this.blendSrc),this.blendDst!==jr&&(n.blendDst=this.blendDst),this.blendEquation!==bn&&(n.blendEquation=this.blendEquation),this.blendSrcAlpha!==null&&(n.blendSrcAlpha=this.blendSrcAlpha),this.blendDstAlpha!==null&&(n.blendDstAlpha=this.blendDstAlpha),this.blendEquationAlpha!==null&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),this.blendAlpha!==0&&(n.blendAlpha=this.blendAlpha),this.depthFunc!==Zn&&(n.depthFunc=this.depthFunc),this.depthTest===!1&&(n.depthTest=this.depthTest),this.depthWrite===!1&&(n.depthWrite=this.depthWrite),this.colorWrite===!1&&(n.colorWrite=this.colorWrite),this.stencilWriteMask!==255&&(n.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==da&&(n.stencilFunc=this.stencilFunc),this.stencilRef!==0&&(n.stencilRef=this.stencilRef),this.stencilFuncMask!==255&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==In&&(n.stencilFail=this.stencilFail),this.stencilZFail!==In&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==In&&(n.stencilZPass=this.stencilZPass),this.stencilWrite===!0&&(n.stencilWrite=this.stencilWrite),this.rotation!==void 0&&this.rotation!==0&&(n.rotation=this.rotation),this.polygonOffset===!0&&(n.polygonOffset=!0),this.polygonOffsetFactor!==0&&(n.polygonOffsetFactor=this.polygonOffsetFactor),this.polygonOffsetUnits!==0&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth!==void 0&&this.linewidth!==1&&(n.linewidth=this.linewidth),this.dashSize!==void 0&&(n.dashSize=this.dashSize),this.gapSize!==void 0&&(n.gapSize=this.gapSize),this.scale!==void 0&&(n.scale=this.scale),this.dithering===!0&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),this.alphaHash===!0&&(n.alphaHash=!0),this.alphaToCoverage===!0&&(n.alphaToCoverage=!0),this.premultipliedAlpha===!0&&(n.premultipliedAlpha=!0),this.forceSinglePass===!0&&(n.forceSinglePass=!0),this.wireframe===!0&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!=="round"&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!=="round"&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading===!0&&(n.flatShading=!0),this.visible===!1&&(n.visible=!1),this.toneMapped===!1&&(n.toneMapped=!1),this.fog===!1&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData);function r(s){const a=[];for(const o in s){const l=s[o];delete l.metadata,a.push(l)}return a}if(t){const s=r(e.textures),a=r(e.images);s.length>0&&(n.textures=s),a.length>0&&(n.images=a)}return n}clone(){return new this.constructor().copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;const t=e.clippingPlanes;let n=null;if(t!==null){const r=t.length;n=new Array(r);for(let s=0;s!==r;++s)n[s]=t[s].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){e===!0&&this.version++}}class cr extends ni{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Fe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new $t,this.combine=mo,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}const ot=new N,Fi=new Ge;let el=0;class qt{constructor(e,t,n=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,Object.defineProperty(this,"id",{value:el++}),this.name="",this.array=e,this.itemSize=t,this.count=e!==void 0?e.length/t:0,this.normalized=n,this.usage=fa,this.updateRanges=[],this.gpuType=nn,this.version=0}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,n){e*=this.itemSize,n*=t.itemSize;for(let r=0,s=this.itemSize;rt.count&&console.warn("THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),t.needsUpdate=!0}return this}computeBoundingBox(){this.boundingBox===null&&(this.boundingBox=new Ei);const e=this.attributes.position,t=this.morphAttributes.position;if(e&&e.isGLBufferAttribute){console.error("THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),this.boundingBox.set(new N(-1/0,-1/0,-1/0),new N(1/0,1/0,1/0));return}if(e!==void 0){if(this.boundingBox.setFromBufferAttribute(e),t)for(let n=0,r=t.length;n0&&(e.userData=this.userData),this.parameters!==void 0){const l=this.parameters;for(const c in l)l[c]!==void 0&&(e[c]=l[c]);return e}e.data={attributes:{}};const t=this.index;t!==null&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});const n=this.attributes;for(const l in n){const c=n[l];e.data.attributes[l]=c.toJSON(e.data)}const r={};let s=!1;for(const l in this.morphAttributes){const c=this.morphAttributes[l],d=[];for(let h=0,f=c.length;h0&&(r[l]=d,s=!0)}s&&(e.data.morphAttributes=r,e.data.morphTargetsRelative=this.morphTargetsRelative);const a=this.groups;a.length>0&&(e.data.groups=JSON.parse(JSON.stringify(a)));const o=this.boundingSphere;return o!==null&&(e.data.boundingSphere=o.toJSON()),e}clone(){return new this.constructor().copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const t={};this.name=e.name;const n=e.index;n!==null&&this.setIndex(n.clone());const r=e.attributes;for(const c in r){const d=r[c];this.setAttribute(c,d.clone(t))}const s=e.morphAttributes;for(const c in s){const d=[],h=s[c];for(let f=0,m=h.length;f0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,a=r.length;s(e.far-e.near)**2))&&(wa.copy(s).invert(),Mn.copy(e.ray).applyMatrix4(wa),!(n.boundingBox!==null&&Mn.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(e,t,Mn)))}_computeIntersections(e,t,n){let r;const s=this.geometry,a=this.material,o=s.index,l=s.attributes.position,c=s.attributes.uv,d=s.attributes.uv1,h=s.attributes.normal,f=s.groups,m=s.drawRange;if(o!==null)if(Array.isArray(a))for(let _=0,x=f.length;_t.far?null:{distance:c,point:Vi.clone(),object:i}}function ki(i,e,t,n,r,s,a,o,l,c){i.getVertexPosition(o,Bi),i.getVertexPosition(l,zi),i.getVertexPosition(c,Hi);const d=nl(i,e,t,n,Bi,zi,Hi,Ca);if(d){const h=new N;Ut.getBarycoord(Ca,Bi,zi,Hi,h),r&&(d.uv=Ut.getInterpolatedAttribute(r,o,l,c,h,new Ge)),s&&(d.uv1=Ut.getInterpolatedAttribute(s,o,l,c,h,new Ge)),a&&(d.normal=Ut.getInterpolatedAttribute(a,o,l,c,h,new N),d.normal.dot(n.direction)>0&&d.normal.multiplyScalar(-1));const f={a:o,b:l,c,normal:new N,materialIndex:0};Ut.getNormal(Bi,zi,Hi,f.normal),d.face=f,d.barycoord=h}return d}class yi extends Nt{constructor(e=1,t=1,n=1,r=1,s=1,a=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:n,widthSegments:r,heightSegments:s,depthSegments:a};const o=this;r=Math.floor(r),s=Math.floor(s),a=Math.floor(a);const l=[],c=[],d=[],h=[];let f=0,m=0;_("z","y","x",-1,-1,n,t,e,a,s,0),_("z","y","x",1,-1,n,t,-e,a,s,1),_("x","z","y",1,1,e,n,t,r,a,2),_("x","z","y",1,-1,e,n,-t,r,a,3),_("x","y","z",1,-1,e,t,n,r,s,4),_("x","y","z",-1,-1,e,t,-n,r,s,5),this.setIndex(l),this.setAttribute("position",new ct(c,3)),this.setAttribute("normal",new ct(d,3)),this.setAttribute("uv",new ct(h,2));function _(x,p,u,b,A,E,C,R,w,U,S){const M=E/w,P=C/U,O=E/2,H=C/2,q=R/2,W=w+1,X=U+1;let Z=0,G=0;const se=new N;for(let le=0;le0?1:-1,d.push(se.x,se.y,se.z),h.push(Oe/w),h.push(1-le/U),Z+=1}}for(let le=0;le0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const n={};for(const r in this.extensions)this.extensions[r]===!0&&(n[r]=!0);return Object.keys(n).length>0&&(t.extensions=n),t}}class Io extends ft{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new it,this.projectionMatrix=new it,this.projectionMatrixInverse=new it,this.coordinateSystem=Xt,this._reversedDepth=!1}get reversedDepth(){return this._reversedDepth}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return new this.constructor().copy(this)}}const un=new N,Pa=new Ge,Da=new Ge;class It extends Io{constructor(e=50,t=1,n=.1,r=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=n,this.far=r,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=e.view===null?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=Os*2*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(ir*.5*this.fov);return .5*this.getFilmHeight()/e}getEffectiveFOV(){return Os*2*Math.atan(Math.tan(ir*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,n){un.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(un.x,un.y).multiplyScalar(-e/un.z),un.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(un.x,un.y).multiplyScalar(-e/un.z)}getViewSize(e,t){return this.getViewBounds(e,Pa,Da),t.subVectors(Da,Pa)}setViewOffset(e,t,n,r,s,a){this.aspect=e/t,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=r,this.view.width=s,this.view.height=a,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=this.near;let t=e*Math.tan(ir*.5*this.fov)/this.zoom,n=2*t,r=this.aspect*n,s=-.5*r;const a=this.view;if(this.view!==null&&this.view.enabled){const l=a.fullWidth,c=a.fullHeight;s+=a.offsetX*r/l,t-=a.offsetY*n/c,r*=a.width/l,n*=a.height/c}const o=this.filmOffset;o!==0&&(s+=e*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(s,s+r,t,t-n,e,this.far,this.coordinateSystem,this.reversedDepth),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,this.view!==null&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}}const Wn=-90,Xn=1;class ol extends ft{constructor(e,t,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const r=new It(Wn,Xn,e,t);r.layers=this.layers,this.add(r);const s=new It(Wn,Xn,e,t);s.layers=this.layers,this.add(s);const a=new It(Wn,Xn,e,t);a.layers=this.layers,this.add(a);const o=new It(Wn,Xn,e,t);o.layers=this.layers,this.add(o);const l=new It(Wn,Xn,e,t);l.layers=this.layers,this.add(l);const c=new It(Wn,Xn,e,t);c.layers=this.layers,this.add(c)}updateCoordinateSystem(){const e=this.coordinateSystem,t=this.children.concat(),[n,r,s,a,o,l]=t;for(const c of t)this.remove(c);if(e===Xt)n.up.set(0,1,0),n.lookAt(1,0,0),r.up.set(0,1,0),r.lookAt(-1,0,0),s.up.set(0,0,-1),s.lookAt(0,1,0),a.up.set(0,0,1),a.lookAt(0,-1,0),o.up.set(0,1,0),o.lookAt(0,0,1),l.up.set(0,1,0),l.lookAt(0,0,-1);else if(e===ar)n.up.set(0,-1,0),n.lookAt(-1,0,0),r.up.set(0,-1,0),r.lookAt(1,0,0),s.up.set(0,0,1),s.lookAt(0,1,0),a.up.set(0,0,-1),a.lookAt(0,-1,0),o.up.set(0,-1,0),o.lookAt(0,0,1),l.up.set(0,-1,0),l.lookAt(0,0,-1);else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);for(const c of t)this.add(c),c.updateMatrixWorld()}update(e,t){this.parent===null&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:r}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());const[s,a,o,l,c,d]=this.children,h=e.getRenderTarget(),f=e.getActiveCubeFace(),m=e.getActiveMipmapLevel(),_=e.xr.enabled;e.xr.enabled=!1;const x=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,e.setRenderTarget(n,0,r),e.render(t,s),e.setRenderTarget(n,1,r),e.render(t,a),e.setRenderTarget(n,2,r),e.render(t,o),e.setRenderTarget(n,3,r),e.render(t,l),e.setRenderTarget(n,4,r),e.render(t,c),n.texture.generateMipmaps=x,e.setRenderTarget(n,5,r),e.render(t,d),e.setRenderTarget(h,f,m),e.xr.enabled=_,n.texture.needsPMREMUpdate=!0}}class Uo extends Tt{constructor(e=[],t=jn,n,r,s,a,o,l,c,d){super(e,t,n,r,s,a,o,l,c,d),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}}class cl extends Dn{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;const n={width:e,height:e,depth:1},r=[n,n,n,n,n,n];this.texture=new Uo(r),this._setTextureOptions(t),this.texture.isRenderTargetTexture=!0}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:` + + varying vec3 vWorldDirection; + + vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); + + } + + void main() { + + vWorldDirection = transformDirection( position, modelMatrix ); + + #include + #include + + } + `,fragmentShader:` + + uniform sampler2D tEquirect; + + varying vec3 vWorldDirection; + + #include + + void main() { + + vec3 direction = normalize( vWorldDirection ); + + vec2 sampleUV = equirectUv( direction ); + + gl_FragColor = texture2D( tEquirect, sampleUV ); + + } + `},r=new yi(5,5,5),s=new mn({name:"CubemapFromEquirect",uniforms:ei(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:yt,blending:dn});s.uniforms.tEquirect.value=t;const a=new Et(r,s),o=t.minFilter;return t.minFilter===Cn&&(t.minFilter=Wt),new ol(1,10,this).update(e,a),t.minFilter=o,a.geometry.dispose(),a.material.dispose(),this}clear(e,t=!0,n=!0,r=!0){const s=e.getRenderTarget();for(let a=0;a<6;a++)e.setRenderTarget(this,a),e.clear(t,n,r);e.setRenderTarget(s)}}class hi extends ft{constructor(){super(),this.isGroup=!0,this.type="Group"}}const ll={type:"move"};class zr{constructor(){this._targetRay=null,this._grip=null,this._hand=null}getHandSpace(){return this._hand===null&&(this._hand=new hi,this._hand.matrixAutoUpdate=!1,this._hand.visible=!1,this._hand.joints={},this._hand.inputState={pinching:!1}),this._hand}getTargetRaySpace(){return this._targetRay===null&&(this._targetRay=new hi,this._targetRay.matrixAutoUpdate=!1,this._targetRay.visible=!1,this._targetRay.hasLinearVelocity=!1,this._targetRay.linearVelocity=new N,this._targetRay.hasAngularVelocity=!1,this._targetRay.angularVelocity=new N),this._targetRay}getGripSpace(){return this._grip===null&&(this._grip=new hi,this._grip.matrixAutoUpdate=!1,this._grip.visible=!1,this._grip.hasLinearVelocity=!1,this._grip.linearVelocity=new N,this._grip.hasAngularVelocity=!1,this._grip.angularVelocity=new N),this._grip}dispatchEvent(e){return this._targetRay!==null&&this._targetRay.dispatchEvent(e),this._grip!==null&&this._grip.dispatchEvent(e),this._hand!==null&&this._hand.dispatchEvent(e),this}connect(e){if(e&&e.hand){const t=this._hand;if(t)for(const n of e.hand.values())this._getHandJoint(t,n)}return this.dispatchEvent({type:"connected",data:e}),this}disconnect(e){return this.dispatchEvent({type:"disconnected",data:e}),this._targetRay!==null&&(this._targetRay.visible=!1),this._grip!==null&&(this._grip.visible=!1),this._hand!==null&&(this._hand.visible=!1),this}update(e,t,n){let r=null,s=null,a=null;const o=this._targetRay,l=this._grip,c=this._hand;if(e&&t.session.visibilityState!=="visible-blurred"){if(c&&e.hand){a=!0;for(const x of e.hand.values()){const p=t.getJointPose(x,n),u=this._getHandJoint(c,x);p!==null&&(u.matrix.fromArray(p.transform.matrix),u.matrix.decompose(u.position,u.rotation,u.scale),u.matrixWorldNeedsUpdate=!0,u.jointRadius=p.radius),u.visible=p!==null}const d=c.joints["index-finger-tip"],h=c.joints["thumb-tip"],f=d.position.distanceTo(h.position),m=.02,_=.005;c.inputState.pinching&&f>m+_?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!c.inputState.pinching&&f<=m-_&&(c.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else l!==null&&e.gripSpace&&(s=t.getPose(e.gripSpace,n),s!==null&&(l.matrix.fromArray(s.transform.matrix),l.matrix.decompose(l.position,l.rotation,l.scale),l.matrixWorldNeedsUpdate=!0,s.linearVelocity?(l.hasLinearVelocity=!0,l.linearVelocity.copy(s.linearVelocity)):l.hasLinearVelocity=!1,s.angularVelocity?(l.hasAngularVelocity=!0,l.angularVelocity.copy(s.angularVelocity)):l.hasAngularVelocity=!1));o!==null&&(r=t.getPose(e.targetRaySpace,n),r===null&&s!==null&&(r=s),r!==null&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(ll)))}return o!==null&&(o.visible=r!==null),l!==null&&(l.visible=s!==null),c!==null&&(c.visible=a!==null),this}_getHandJoint(e,t){if(e.joints[t.jointName]===void 0){const n=new hi;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}class ul extends ft{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new $t,this.environmentIntensity=1,this.environmentRotation=new $t,this.overrideMaterial=null,typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),e.background!==null&&(this.background=e.background.clone()),e.environment!==null&&(this.environment=e.environment.clone()),e.fog!==null&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentIntensity=e.environmentIntensity,this.environmentRotation.copy(e.environmentRotation),e.overrideMaterial!==null&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return this.fog!==null&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),this.environmentIntensity!==1&&(t.object.environmentIntensity=this.environmentIntensity),t.object.environmentRotation=this.environmentRotation.toArray(),t}}const Hr=new N,hl=new N,dl=new Ie;class Tn{constructor(e=new N(1,0,0),t=0){this.isPlane=!0,this.normal=e,this.constant=t}set(e,t){return this.normal.copy(e),this.constant=t,this}setComponents(e,t,n,r){return this.normal.set(e,t,n),this.constant=r,this}setFromNormalAndCoplanarPoint(e,t){return this.normal.copy(e),this.constant=-t.dot(this.normal),this}setFromCoplanarPoints(e,t,n){const r=Hr.subVectors(n,t).cross(hl.subVectors(e,t)).normalize();return this.setFromNormalAndCoplanarPoint(r,e),this}copy(e){return this.normal.copy(e.normal),this.constant=e.constant,this}normalize(){const e=1/this.normal.length();return this.normal.multiplyScalar(e),this.constant*=e,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(e){return this.normal.dot(e)+this.constant}distanceToSphere(e){return this.distanceToPoint(e.center)-e.radius}projectPoint(e,t){return t.copy(e).addScaledVector(this.normal,-this.distanceToPoint(e))}intersectLine(e,t){const n=e.delta(Hr),r=this.normal.dot(n);if(r===0)return this.distanceToPoint(e.start)===0?t.copy(e.start):null;const s=-(e.start.dot(this.normal)+this.constant)/r;return s<0||s>1?null:t.copy(e.start).addScaledVector(n,s)}intersectsLine(e){const t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){const n=t||dl.getNormalMatrix(e),r=this.coplanarPoint(Hr).applyMatrix4(e),s=this.normal.applyMatrix3(n).normalize();return this.constant=-r.dot(s),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return new this.constructor().copy(this)}}const Sn=new fr,fl=new Ge(.5,.5),Wi=new N;class js{constructor(e=new Tn,t=new Tn,n=new Tn,r=new Tn,s=new Tn,a=new Tn){this.planes=[e,t,n,r,s,a]}set(e,t,n,r,s,a){const o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(n),o[3].copy(r),o[4].copy(s),o[5].copy(a),this}copy(e){const t=this.planes;for(let n=0;n<6;n++)t[n].copy(e.planes[n]);return this}setFromProjectionMatrix(e,t=Xt,n=!1){const r=this.planes,s=e.elements,a=s[0],o=s[1],l=s[2],c=s[3],d=s[4],h=s[5],f=s[6],m=s[7],_=s[8],x=s[9],p=s[10],u=s[11],b=s[12],A=s[13],E=s[14],C=s[15];if(r[0].setComponents(c-a,m-d,u-_,C-b).normalize(),r[1].setComponents(c+a,m+d,u+_,C+b).normalize(),r[2].setComponents(c+o,m+h,u+x,C+A).normalize(),r[3].setComponents(c-o,m-h,u-x,C-A).normalize(),n)r[4].setComponents(l,f,p,E).normalize(),r[5].setComponents(c-l,m-f,u-p,C-E).normalize();else if(r[4].setComponents(c-l,m-f,u-p,C-E).normalize(),t===Xt)r[5].setComponents(c+l,m+f,u+p,C+E).normalize();else if(t===ar)r[5].setComponents(l,f,p,E).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);return this}intersectsObject(e){if(e.boundingSphere!==void 0)e.boundingSphere===null&&e.computeBoundingSphere(),Sn.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{const t=e.geometry;t.boundingSphere===null&&t.computeBoundingSphere(),Sn.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(Sn)}intersectsSprite(e){Sn.center.set(0,0,0);const t=fl.distanceTo(e.center);return Sn.radius=.7071067811865476+t,Sn.applyMatrix4(e.matrixWorld),this.intersectsSphere(Sn)}intersectsSphere(e){const t=this.planes,n=e.center,r=-e.radius;for(let s=0;s<6;s++)if(t[s].distanceToPoint(n)0?e.max.x:e.min.x,Wi.y=r.normal.y>0?e.max.y:e.min.y,Wi.z=r.normal.z>0?e.max.z:e.min.z,r.distanceToPoint(Wi)<0)return!1}return!0}containsPoint(e){const t=this.planes;for(let n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}}class No extends ni{constructor(e){super(),this.isLineBasicMaterial=!0,this.type="LineBasicMaterial",this.color=new Fe(16777215),this.map=null,this.linewidth=1,this.linecap="round",this.linejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.linewidth=e.linewidth,this.linecap=e.linecap,this.linejoin=e.linejoin,this.fog=e.fog,this}}const lr=new N,ur=new N,La=new it,ui=new Ks,Xi=new fr,Gr=new N,Ia=new N;class pl extends ft{constructor(e=new Nt,t=new No){super(),this.isLine=!0,this.type="Line",this.geometry=e,this.material=t,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.updateMorphTargets()}copy(e,t){return super.copy(e,t),this.material=Array.isArray(e.material)?e.material.slice():e.material,this.geometry=e.geometry,this}computeLineDistances(){const e=this.geometry;if(e.index===null){const t=e.attributes.position,n=[0];for(let r=1,s=t.count;r0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,a=r.length;sn)return;Gr.applyMatrix4(i.matrixWorld);const c=e.ray.origin.distanceTo(Gr);if(!(ce.far))return{distance:c,point:Ia.clone().applyMatrix4(i.matrixWorld),index:a,face:null,faceIndex:null,barycoord:null,object:i}}const Ua=new N,Na=new N;class ml extends pl{constructor(e,t){super(e,t),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const e=this.geometry;if(e.index===null){const t=e.attributes.position,n=[];for(let r=0,s=t.count;r0&&A(!0),t>0&&A(!1)),this.setIndex(d),this.setAttribute("position",new ct(h,3)),this.setAttribute("normal",new ct(f,3)),this.setAttribute("uv",new ct(m,2));function b(){const E=new N,C=new N;let R=0;const w=(t-e)/n;for(let U=0;U<=s;U++){const S=[],M=U/s,P=M*(t-e)+e;for(let O=0;O<=r;O++){const H=O/r,q=H*l+o,W=Math.sin(q),X=Math.cos(q);C.x=P*W,C.y=-M*n+p,C.z=P*X,h.push(C.x,C.y,C.z),E.set(W,w,X).normalize(),f.push(E.x,E.y,E.z),m.push(H,1-M),S.push(_++)}x.push(S)}for(let U=0;U0||S!==0)&&(d.push(M,P,H),R+=3),(t>0||S!==s-1)&&(d.push(P,O,H),R+=3)}c.addGroup(u,R,0),u+=R}function A(E){const C=_,R=new Ge,w=new N;let U=0;const S=E===!0?e:t,M=E===!0?1:-1;for(let O=1;O<=r;O++)h.push(0,p*M,0),f.push(0,M,0),m.push(.5,.5),_++;const P=_;for(let O=0;O<=r;O++){const q=O/r*l+o,W=Math.cos(q),X=Math.sin(q);w.x=S*X,w.y=p*M,w.z=S*W,h.push(w.x,w.y,w.z),f.push(0,M,0),R.x=W*.5+.5,R.y=X*.5*M+.5,m.push(R.x,R.y),_++}for(let O=0;Om.start-_.start);let f=0;for(let m=1;m 0 + vec4 plane; + #ifdef ALPHA_TO_COVERAGE + float distanceToPlane, distanceGradient; + float clipOpacity = 1.0; + #pragma unroll_loop_start + for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + distanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w; + distanceGradient = fwidth( distanceToPlane ) / 2.0; + clipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane ); + if ( clipOpacity == 0.0 ) discard; + } + #pragma unroll_loop_end + #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES + float unionClipOpacity = 1.0; + #pragma unroll_loop_start + for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + distanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w; + distanceGradient = fwidth( distanceToPlane ) / 2.0; + unionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane ); + } + #pragma unroll_loop_end + clipOpacity *= 1.0 - unionClipOpacity; + #endif + diffuseColor.a *= clipOpacity; + if ( diffuseColor.a == 0.0 ) discard; + #else + #pragma unroll_loop_start + for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + if ( dot( vClipPosition, plane.xyz ) > plane.w ) discard; + } + #pragma unroll_loop_end + #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES + bool clipped = true; + #pragma unroll_loop_start + for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + clipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped; + } + #pragma unroll_loop_end + if ( clipped ) discard; + #endif + #endif +#endif`,Wl=`#if NUM_CLIPPING_PLANES > 0 + varying vec3 vClipPosition; + uniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ]; +#endif`,Xl=`#if NUM_CLIPPING_PLANES > 0 + varying vec3 vClipPosition; +#endif`,ql=`#if NUM_CLIPPING_PLANES > 0 + vClipPosition = - mvPosition.xyz; +#endif`,Yl=`#if defined( USE_COLOR_ALPHA ) + diffuseColor *= vColor; +#elif defined( USE_COLOR ) + diffuseColor.rgb *= vColor; +#endif`,$l=`#if defined( USE_COLOR_ALPHA ) + varying vec4 vColor; +#elif defined( USE_COLOR ) + varying vec3 vColor; +#endif`,Kl=`#if defined( USE_COLOR_ALPHA ) + varying vec4 vColor; +#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) + varying vec3 vColor; +#endif`,Zl=`#if defined( USE_COLOR_ALPHA ) + vColor = vec4( 1.0 ); +#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) + vColor = vec3( 1.0 ); +#endif +#ifdef USE_COLOR + vColor *= color; +#endif +#ifdef USE_INSTANCING_COLOR + vColor.xyz *= instanceColor.xyz; +#endif +#ifdef USE_BATCHING_COLOR + vec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) ); + vColor.xyz *= batchingColor.xyz; +#endif`,jl=`#define PI 3.141592653589793 +#define PI2 6.283185307179586 +#define PI_HALF 1.5707963267948966 +#define RECIPROCAL_PI 0.3183098861837907 +#define RECIPROCAL_PI2 0.15915494309189535 +#define EPSILON 1e-6 +#ifndef saturate +#define saturate( a ) clamp( a, 0.0, 1.0 ) +#endif +#define whiteComplement( a ) ( 1.0 - saturate( a ) ) +float pow2( const in float x ) { return x*x; } +vec3 pow2( const in vec3 x ) { return x*x; } +float pow3( const in float x ) { return x*x*x; } +float pow4( const in float x ) { float x2 = x*x; return x2*x2; } +float max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); } +float average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); } +highp float rand( const in vec2 uv ) { + const highp float a = 12.9898, b = 78.233, c = 43758.5453; + highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); + return fract( sin( sn ) * c ); +} +#ifdef HIGH_PRECISION + float precisionSafeLength( vec3 v ) { return length( v ); } +#else + float precisionSafeLength( vec3 v ) { + float maxComponent = max3( abs( v ) ); + return length( v / maxComponent ) * maxComponent; + } +#endif +struct IncidentLight { + vec3 color; + vec3 direction; + bool visible; +}; +struct ReflectedLight { + vec3 directDiffuse; + vec3 directSpecular; + vec3 indirectDiffuse; + vec3 indirectSpecular; +}; +#ifdef USE_ALPHAHASH + varying vec3 vPosition; +#endif +vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); +} +vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) { + return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz ); +} +mat3 transposeMat3( const in mat3 m ) { + mat3 tmp; + tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x ); + tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y ); + tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z ); + return tmp; +} +bool isPerspectiveMatrix( mat4 m ) { + return m[ 2 ][ 3 ] == - 1.0; +} +vec2 equirectUv( in vec3 dir ) { + float u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5; + float v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; + return vec2( u, v ); +} +vec3 BRDF_Lambert( const in vec3 diffuseColor ) { + return RECIPROCAL_PI * diffuseColor; +} +vec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) { + float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); + return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); +} +float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { + float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); + return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); +} // validated`,Jl=`#ifdef ENVMAP_TYPE_CUBE_UV + #define cubeUV_minMipLevel 4.0 + #define cubeUV_minTileSize 16.0 + float getFace( vec3 direction ) { + vec3 absDirection = abs( direction ); + float face = - 1.0; + if ( absDirection.x > absDirection.z ) { + if ( absDirection.x > absDirection.y ) + face = direction.x > 0.0 ? 0.0 : 3.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } else { + if ( absDirection.z > absDirection.y ) + face = direction.z > 0.0 ? 2.0 : 5.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } + return face; + } + vec2 getUV( vec3 direction, float face ) { + vec2 uv; + if ( face == 0.0 ) { + uv = vec2( direction.z, direction.y ) / abs( direction.x ); + } else if ( face == 1.0 ) { + uv = vec2( - direction.x, - direction.z ) / abs( direction.y ); + } else if ( face == 2.0 ) { + uv = vec2( - direction.x, direction.y ) / abs( direction.z ); + } else if ( face == 3.0 ) { + uv = vec2( - direction.z, direction.y ) / abs( direction.x ); + } else if ( face == 4.0 ) { + uv = vec2( - direction.x, direction.z ) / abs( direction.y ); + } else { + uv = vec2( direction.x, direction.y ) / abs( direction.z ); + } + return 0.5 * ( uv + 1.0 ); + } + vec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) { + float face = getFace( direction ); + float filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 ); + mipInt = max( mipInt, cubeUV_minMipLevel ); + float faceSize = exp2( mipInt ); + highp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0; + if ( face > 2.0 ) { + uv.y += faceSize; + face -= 3.0; + } + uv.x += face * faceSize; + uv.x += filterInt * 3.0 * cubeUV_minTileSize; + uv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize ); + uv.x *= CUBEUV_TEXEL_WIDTH; + uv.y *= CUBEUV_TEXEL_HEIGHT; + #ifdef texture2DGradEXT + return texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb; + #else + return texture2D( envMap, uv ).rgb; + #endif + } + #define cubeUV_r0 1.0 + #define cubeUV_m0 - 2.0 + #define cubeUV_r1 0.8 + #define cubeUV_m1 - 1.0 + #define cubeUV_r4 0.4 + #define cubeUV_m4 2.0 + #define cubeUV_r5 0.305 + #define cubeUV_m5 3.0 + #define cubeUV_r6 0.21 + #define cubeUV_m6 4.0 + float roughnessToMip( float roughness ) { + float mip = 0.0; + if ( roughness >= cubeUV_r1 ) { + mip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0; + } else if ( roughness >= cubeUV_r4 ) { + mip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1; + } else if ( roughness >= cubeUV_r5 ) { + mip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4; + } else if ( roughness >= cubeUV_r6 ) { + mip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5; + } else { + mip = - 2.0 * log2( 1.16 * roughness ); } + return mip; + } + vec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) { + float mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); + float mipF = fract( mip ); + float mipInt = floor( mip ); + vec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt ); + if ( mipF == 0.0 ) { + return vec4( color0, 1.0 ); + } else { + vec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 ); + return vec4( mix( color0, color1, mipF ), 1.0 ); + } + } +#endif`,Ql=`vec3 transformedNormal = objectNormal; +#ifdef USE_TANGENT + vec3 transformedTangent = objectTangent; +#endif +#ifdef USE_BATCHING + mat3 bm = mat3( batchingMatrix ); + transformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) ); + transformedNormal = bm * transformedNormal; + #ifdef USE_TANGENT + transformedTangent = bm * transformedTangent; + #endif +#endif +#ifdef USE_INSTANCING + mat3 im = mat3( instanceMatrix ); + transformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) ); + transformedNormal = im * transformedNormal; + #ifdef USE_TANGENT + transformedTangent = im * transformedTangent; + #endif +#endif +transformedNormal = normalMatrix * transformedNormal; +#ifdef FLIP_SIDED + transformedNormal = - transformedNormal; +#endif +#ifdef USE_TANGENT + transformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz; + #ifdef FLIP_SIDED + transformedTangent = - transformedTangent; + #endif +#endif`,eu=`#ifdef USE_DISPLACEMENTMAP + uniform sampler2D displacementMap; + uniform float displacementScale; + uniform float displacementBias; +#endif`,tu=`#ifdef USE_DISPLACEMENTMAP + transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias ); +#endif`,nu=`#ifdef USE_EMISSIVEMAP + vec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv ); + #ifdef DECODE_VIDEO_TEXTURE_EMISSIVE + emissiveColor = sRGBTransferEOTF( emissiveColor ); + #endif + totalEmissiveRadiance *= emissiveColor.rgb; +#endif`,iu=`#ifdef USE_EMISSIVEMAP + uniform sampler2D emissiveMap; +#endif`,ru="gl_FragColor = linearToOutputTexel( gl_FragColor );",su=`vec4 LinearTransferOETF( in vec4 value ) { + return value; +} +vec4 sRGBTransferEOTF( in vec4 value ) { + return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a ); +} +vec4 sRGBTransferOETF( in vec4 value ) { + return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); +}`,au=`#ifdef USE_ENVMAP + #ifdef ENV_WORLDPOS + vec3 cameraToFrag; + if ( isOrthographic ) { + cameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); + } else { + cameraToFrag = normalize( vWorldPosition - cameraPosition ); + } + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + #ifdef ENVMAP_MODE_REFLECTION + vec3 reflectVec = reflect( cameraToFrag, worldNormal ); + #else + vec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio ); + #endif + #else + vec3 reflectVec = vReflect; + #endif + #ifdef ENVMAP_TYPE_CUBE + vec4 envColor = textureCube( envMap, envMapRotation * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) ); + #else + vec4 envColor = vec4( 0.0 ); + #endif + #ifdef ENVMAP_BLENDING_MULTIPLY + outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity ); + #elif defined( ENVMAP_BLENDING_MIX ) + outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity ); + #elif defined( ENVMAP_BLENDING_ADD ) + outgoingLight += envColor.xyz * specularStrength * reflectivity; + #endif +#endif`,ou=`#ifdef USE_ENVMAP + uniform float envMapIntensity; + uniform float flipEnvMap; + uniform mat3 envMapRotation; + #ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; + #else + uniform sampler2D envMap; + #endif + +#endif`,cu=`#ifdef USE_ENVMAP + uniform float reflectivity; + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) + #define ENV_WORLDPOS + #endif + #ifdef ENV_WORLDPOS + varying vec3 vWorldPosition; + uniform float refractionRatio; + #else + varying vec3 vReflect; + #endif +#endif`,lu=`#ifdef USE_ENVMAP + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) + #define ENV_WORLDPOS + #endif + #ifdef ENV_WORLDPOS + + varying vec3 vWorldPosition; + #else + varying vec3 vReflect; + uniform float refractionRatio; + #endif +#endif`,uu=`#ifdef USE_ENVMAP + #ifdef ENV_WORLDPOS + vWorldPosition = worldPosition.xyz; + #else + vec3 cameraToVertex; + if ( isOrthographic ) { + cameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); + } else { + cameraToVertex = normalize( worldPosition.xyz - cameraPosition ); + } + vec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); + #ifdef ENVMAP_MODE_REFLECTION + vReflect = reflect( cameraToVertex, worldNormal ); + #else + vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); + #endif + #endif +#endif`,hu=`#ifdef USE_FOG + vFogDepth = - mvPosition.z; +#endif`,du=`#ifdef USE_FOG + varying float vFogDepth; +#endif`,fu=`#ifdef USE_FOG + #ifdef FOG_EXP2 + float fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth ); + #else + float fogFactor = smoothstep( fogNear, fogFar, vFogDepth ); + #endif + gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor ); +#endif`,pu=`#ifdef USE_FOG + uniform vec3 fogColor; + varying float vFogDepth; + #ifdef FOG_EXP2 + uniform float fogDensity; + #else + uniform float fogNear; + uniform float fogFar; + #endif +#endif`,mu=`#ifdef USE_GRADIENTMAP + uniform sampler2D gradientMap; +#endif +vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { + float dotNL = dot( normal, lightDirection ); + vec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 ); + #ifdef USE_GRADIENTMAP + return vec3( texture2D( gradientMap, coord ).r ); + #else + vec2 fw = fwidth( coord ) * 0.5; + return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) ); + #endif +}`,gu=`#ifdef USE_LIGHTMAP + uniform sampler2D lightMap; + uniform float lightMapIntensity; +#endif`,_u=`LambertMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularStrength = specularStrength;`,vu=`varying vec3 vViewPosition; +struct LambertMaterial { + vec3 diffuseColor; + float specularStrength; +}; +void RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Lambert +#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,xu=`uniform bool receiveShadow; +uniform vec3 ambientLightColor; +#if defined( USE_LIGHT_PROBES ) + uniform vec3 lightProbe[ 9 ]; +#endif +vec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) { + float x = normal.x, y = normal.y, z = normal.z; + vec3 result = shCoefficients[ 0 ] * 0.886227; + result += shCoefficients[ 1 ] * 2.0 * 0.511664 * y; + result += shCoefficients[ 2 ] * 2.0 * 0.511664 * z; + result += shCoefficients[ 3 ] * 2.0 * 0.511664 * x; + result += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y; + result += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z; + result += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 ); + result += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z; + result += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y ); + return result; +} +vec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) { + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + vec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe ); + return irradiance; +} +vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) { + vec3 irradiance = ambientLightColor; + return irradiance; +} +float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) { + float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 ); + if ( cutoffDistance > 0.0 ) { + distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) ); + } + return distanceFalloff; +} +float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) { + return smoothstep( coneCosine, penumbraCosine, angleCosine ); +} +#if NUM_DIR_LIGHTS > 0 + struct DirectionalLight { + vec3 direction; + vec3 color; + }; + uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; + void getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) { + light.color = directionalLight.color; + light.direction = directionalLight.direction; + light.visible = true; + } +#endif +#if NUM_POINT_LIGHTS > 0 + struct PointLight { + vec3 position; + vec3 color; + float distance; + float decay; + }; + uniform PointLight pointLights[ NUM_POINT_LIGHTS ]; + void getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = pointLight.position - geometryPosition; + light.direction = normalize( lVector ); + float lightDistance = length( lVector ); + light.color = pointLight.color; + light.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay ); + light.visible = ( light.color != vec3( 0.0 ) ); + } +#endif +#if NUM_SPOT_LIGHTS > 0 + struct SpotLight { + vec3 position; + vec3 direction; + vec3 color; + float distance; + float decay; + float coneCos; + float penumbraCos; + }; + uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ]; + void getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = spotLight.position - geometryPosition; + light.direction = normalize( lVector ); + float angleCos = dot( light.direction, spotLight.direction ); + float spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos ); + if ( spotAttenuation > 0.0 ) { + float lightDistance = length( lVector ); + light.color = spotLight.color * spotAttenuation; + light.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay ); + light.visible = ( light.color != vec3( 0.0 ) ); + } else { + light.color = vec3( 0.0 ); + light.visible = false; + } + } +#endif +#if NUM_RECT_AREA_LIGHTS > 0 + struct RectAreaLight { + vec3 color; + vec3 position; + vec3 halfWidth; + vec3 halfHeight; + }; + uniform sampler2D ltc_1; uniform sampler2D ltc_2; + uniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ]; +#endif +#if NUM_HEMI_LIGHTS > 0 + struct HemisphereLight { + vec3 direction; + vec3 skyColor; + vec3 groundColor; + }; + uniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ]; + vec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) { + float dotNL = dot( normal, hemiLight.direction ); + float hemiDiffuseWeight = 0.5 * dotNL + 0.5; + vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight ); + return irradiance; + } +#endif`,Mu=`#ifdef USE_ENVMAP + vec3 getIBLIrradiance( const in vec3 normal ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, envMapRotation * worldNormal, 1.0 ); + return PI * envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + vec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 reflectVec = reflect( - viewDir, normal ); + reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) ); + reflectVec = inverseTransformDirection( reflectVec, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, envMapRotation * reflectVec, roughness ); + return envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + #ifdef USE_ANISOTROPY + vec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 bentNormal = cross( bitangent, viewDir ); + bentNormal = normalize( cross( bentNormal, bitangent ) ); + bentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) ); + return getIBLRadiance( viewDir, bentNormal, roughness ); + #else + return vec3( 0.0 ); + #endif + } + #endif +#endif`,Su=`ToonMaterial material; +material.diffuseColor = diffuseColor.rgb;`,Eu=`varying vec3 vViewPosition; +struct ToonMaterial { + vec3 diffuseColor; +}; +void RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + vec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Toon +#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,yu=`BlinnPhongMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularColor = specular; +material.specularShininess = shininess; +material.specularStrength = specularStrength;`,Tu=`varying vec3 vViewPosition; +struct BlinnPhongMaterial { + vec3 diffuseColor; + vec3 specularColor; + float specularShininess; + float specularStrength; +}; +void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); + reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength; +} +void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_BlinnPhong +#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,Au=`PhysicalMaterial material; +material.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor ); +vec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) ); +float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z ); +material.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness; +material.roughness = min( material.roughness, 1.0 ); +#ifdef IOR + material.ior = ior; + #ifdef USE_SPECULAR + float specularIntensityFactor = specularIntensity; + vec3 specularColorFactor = specularColor; + #ifdef USE_SPECULAR_COLORMAP + specularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb; + #endif + #ifdef USE_SPECULAR_INTENSITYMAP + specularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a; + #endif + material.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor ); + #else + float specularIntensityFactor = 1.0; + vec3 specularColorFactor = vec3( 1.0 ); + material.specularF90 = 1.0; + #endif + material.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor ); +#else + material.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor ); + material.specularF90 = 1.0; +#endif +#ifdef USE_CLEARCOAT + material.clearcoat = clearcoat; + material.clearcoatRoughness = clearcoatRoughness; + material.clearcoatF0 = vec3( 0.04 ); + material.clearcoatF90 = 1.0; + #ifdef USE_CLEARCOATMAP + material.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x; + #endif + #ifdef USE_CLEARCOAT_ROUGHNESSMAP + material.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y; + #endif + material.clearcoat = saturate( material.clearcoat ); material.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 ); + material.clearcoatRoughness += geometryRoughness; + material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 ); +#endif +#ifdef USE_DISPERSION + material.dispersion = dispersion; +#endif +#ifdef USE_IRIDESCENCE + material.iridescence = iridescence; + material.iridescenceIOR = iridescenceIOR; + #ifdef USE_IRIDESCENCEMAP + material.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r; + #endif + #ifdef USE_IRIDESCENCE_THICKNESSMAP + material.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum; + #else + material.iridescenceThickness = iridescenceThicknessMaximum; + #endif +#endif +#ifdef USE_SHEEN + material.sheenColor = sheenColor; + #ifdef USE_SHEEN_COLORMAP + material.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb; + #endif + material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 ); + #ifdef USE_SHEEN_ROUGHNESSMAP + material.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a; + #endif +#endif +#ifdef USE_ANISOTROPY + #ifdef USE_ANISOTROPYMAP + mat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x ); + vec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb; + vec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b; + #else + vec2 anisotropyV = anisotropyVector; + #endif + material.anisotropy = length( anisotropyV ); + if( material.anisotropy == 0.0 ) { + anisotropyV = vec2( 1.0, 0.0 ); + } else { + anisotropyV /= material.anisotropy; + material.anisotropy = saturate( material.anisotropy ); + } + material.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) ); + material.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y; + material.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y; +#endif`,bu=`struct PhysicalMaterial { + vec3 diffuseColor; + float roughness; + vec3 specularColor; + float specularF90; + float dispersion; + #ifdef USE_CLEARCOAT + float clearcoat; + float clearcoatRoughness; + vec3 clearcoatF0; + float clearcoatF90; + #endif + #ifdef USE_IRIDESCENCE + float iridescence; + float iridescenceIOR; + float iridescenceThickness; + vec3 iridescenceFresnel; + vec3 iridescenceF0; + #endif + #ifdef USE_SHEEN + vec3 sheenColor; + float sheenRoughness; + #endif + #ifdef IOR + float ior; + #endif + #ifdef USE_TRANSMISSION + float transmission; + float transmissionAlpha; + float thickness; + float attenuationDistance; + vec3 attenuationColor; + #endif + #ifdef USE_ANISOTROPY + float anisotropy; + float alphaT; + vec3 anisotropyT; + vec3 anisotropyB; + #endif +}; +vec3 clearcoatSpecularDirect = vec3( 0.0 ); +vec3 clearcoatSpecularIndirect = vec3( 0.0 ); +vec3 sheenSpecularDirect = vec3( 0.0 ); +vec3 sheenSpecularIndirect = vec3(0.0 ); +vec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) { + float x = clamp( 1.0 - dotVH, 0.0, 1.0 ); + float x2 = x * x; + float x5 = clamp( x * x2 * x2, 0.0, 0.9999 ); + return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 ); +} +float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) { + float a2 = pow2( alpha ); + float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); + float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); + return 0.5 / max( gv + gl, EPSILON ); +} +float D_GGX( const in float alpha, const in float dotNH ) { + float a2 = pow2( alpha ); + float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; + return RECIPROCAL_PI * a2 / pow2( denom ); +} +#ifdef USE_ANISOTROPY + float V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) { + float gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) ); + float gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) ); + float v = 0.5 / ( gv + gl ); + return saturate(v); + } + float D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) { + float a2 = alphaT * alphaB; + highp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH ); + highp float v2 = dot( v, v ); + float w2 = a2 / v2; + return RECIPROCAL_PI * a2 * pow2 ( w2 ); + } +#endif +#ifdef USE_CLEARCOAT + vec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) { + vec3 f0 = material.clearcoatF0; + float f90 = material.clearcoatF90; + float roughness = material.clearcoatRoughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + return F * ( V * D ); + } +#endif +vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) { + vec3 f0 = material.specularColor; + float f90 = material.specularF90; + float roughness = material.roughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + #ifdef USE_IRIDESCENCE + F = mix( F, material.iridescenceFresnel, material.iridescence ); + #endif + #ifdef USE_ANISOTROPY + float dotTL = dot( material.anisotropyT, lightDir ); + float dotTV = dot( material.anisotropyT, viewDir ); + float dotTH = dot( material.anisotropyT, halfDir ); + float dotBL = dot( material.anisotropyB, lightDir ); + float dotBV = dot( material.anisotropyB, viewDir ); + float dotBH = dot( material.anisotropyB, halfDir ); + float V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL ); + float D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH ); + #else + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + #endif + return F * ( V * D ); +} +vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) { + const float LUT_SIZE = 64.0; + const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; + const float LUT_BIAS = 0.5 / LUT_SIZE; + float dotNV = saturate( dot( N, V ) ); + vec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) ); + uv = uv * LUT_SCALE + LUT_BIAS; + return uv; +} +float LTC_ClippedSphereFormFactor( const in vec3 f ) { + float l = length( f ); + return max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 ); +} +vec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) { + float x = dot( v1, v2 ); + float y = abs( x ); + float a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y; + float b = 3.4175940 + ( 4.1616724 + y ) * y; + float v = a / b; + float theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v; + return cross( v1, v2 ) * theta_sintheta; +} +vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) { + vec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ]; + vec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ]; + vec3 lightNormal = cross( v1, v2 ); + if( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 ); + vec3 T1, T2; + T1 = normalize( V - N * dot( V, N ) ); + T2 = - cross( N, T1 ); + mat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) ); + vec3 coords[ 4 ]; + coords[ 0 ] = mat * ( rectCoords[ 0 ] - P ); + coords[ 1 ] = mat * ( rectCoords[ 1 ] - P ); + coords[ 2 ] = mat * ( rectCoords[ 2 ] - P ); + coords[ 3 ] = mat * ( rectCoords[ 3 ] - P ); + coords[ 0 ] = normalize( coords[ 0 ] ); + coords[ 1 ] = normalize( coords[ 1 ] ); + coords[ 2 ] = normalize( coords[ 2 ] ); + coords[ 3 ] = normalize( coords[ 3 ] ); + vec3 vectorFormFactor = vec3( 0.0 ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] ); + float result = LTC_ClippedSphereFormFactor( vectorFormFactor ); + return vec3( result ); +} +#if defined( USE_SHEEN ) +float D_Charlie( float roughness, float dotNH ) { + float alpha = pow2( roughness ); + float invAlpha = 1.0 / alpha; + float cos2h = dotNH * dotNH; + float sin2h = max( 1.0 - cos2h, 0.0078125 ); + return ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI ); +} +float V_Neubelt( float dotNV, float dotNL ) { + return saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) ); +} +vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) { + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float D = D_Charlie( sheenRoughness, dotNH ); + float V = V_Neubelt( dotNV, dotNL ); + return sheenColor * ( D * V ); +} +#endif +float IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { + float dotNV = saturate( dot( normal, viewDir ) ); + float r2 = roughness * roughness; + float a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95; + float b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72; + float DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) ); + return saturate( DG * RECIPROCAL_PI ); +} +vec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { + float dotNV = saturate( dot( normal, viewDir ) ); + const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); + const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); + vec4 r = roughness * c0 + c1; + float a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y; + vec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw; + return fab; +} +vec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) { + vec2 fab = DFGApprox( normal, viewDir, roughness ); + return specularColor * fab.x + specularF90 * fab.y; +} +#ifdef USE_IRIDESCENCE +void computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { +#else +void computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) { +#endif + vec2 fab = DFGApprox( normal, viewDir, roughness ); + #ifdef USE_IRIDESCENCE + vec3 Fr = mix( specularColor, iridescenceF0, iridescence ); + #else + vec3 Fr = specularColor; + #endif + vec3 FssEss = Fr * fab.x + specularF90 * fab.y; + float Ess = fab.x + fab.y; + float Ems = 1.0 - Ess; + vec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619; vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg ); + singleScatter += FssEss; + multiScatter += Fms * Ems; +} +#if NUM_RECT_AREA_LIGHTS > 0 + void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + vec3 normal = geometryNormal; + vec3 viewDir = geometryViewDir; + vec3 position = geometryPosition; + vec3 lightPos = rectAreaLight.position; + vec3 halfWidth = rectAreaLight.halfWidth; + vec3 halfHeight = rectAreaLight.halfHeight; + vec3 lightColor = rectAreaLight.color; + float roughness = material.roughness; + vec3 rectCoords[ 4 ]; + rectCoords[ 0 ] = lightPos + halfWidth - halfHeight; rectCoords[ 1 ] = lightPos - halfWidth - halfHeight; + rectCoords[ 2 ] = lightPos - halfWidth + halfHeight; + rectCoords[ 3 ] = lightPos + halfWidth + halfHeight; + vec2 uv = LTC_Uv( normal, viewDir, roughness ); + vec4 t1 = texture2D( ltc_1, uv ); + vec4 t2 = texture2D( ltc_2, uv ); + mat3 mInv = mat3( + vec3( t1.x, 0, t1.y ), + vec3( 0, 1, 0 ), + vec3( t1.z, 0, t1.w ) + ); + vec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y ); + reflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords ); + reflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords ); + } +#endif +void RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + #ifdef USE_CLEARCOAT + float dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) ); + vec3 ccIrradiance = dotNLcc * directLight.color; + clearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material ); + #endif + #ifdef USE_SHEEN + sheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness ); + #endif + reflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material ); + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { + #ifdef USE_CLEARCOAT + clearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness ); + #endif + #ifdef USE_SHEEN + sheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ); + #endif + vec3 singleScattering = vec3( 0.0 ); + vec3 multiScattering = vec3( 0.0 ); + vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI; + #ifdef USE_IRIDESCENCE + computeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering ); + #else + computeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering ); + #endif + vec3 totalScattering = singleScattering + multiScattering; + vec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) ); + reflectedLight.indirectSpecular += radiance * singleScattering; + reflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance; + reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance; +} +#define RE_Direct RE_Direct_Physical +#define RE_Direct_RectArea RE_Direct_RectArea_Physical +#define RE_IndirectDiffuse RE_IndirectDiffuse_Physical +#define RE_IndirectSpecular RE_IndirectSpecular_Physical +float computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) { + return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); +}`,wu=` +vec3 geometryPosition = - vViewPosition; +vec3 geometryNormal = normal; +vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); +vec3 geometryClearcoatNormal = vec3( 0.0 ); +#ifdef USE_CLEARCOAT + geometryClearcoatNormal = clearcoatNormal; +#endif +#ifdef USE_IRIDESCENCE + float dotNVi = saturate( dot( normal, geometryViewDir ) ); + if ( material.iridescenceThickness == 0.0 ) { + material.iridescence = 0.0; + } else { + material.iridescence = saturate( material.iridescence ); + } + if ( material.iridescence > 0.0 ) { + material.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor ); + material.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi ); + } +#endif +IncidentLight directLight; +#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct ) + PointLight pointLight; + #if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0 + PointLightShadow pointLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) { + pointLight = pointLights[ i ]; + getPointLightInfo( pointLight, geometryPosition, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS ) + pointLightShadow = pointLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowIntensity, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct ) + SpotLight spotLight; + vec4 spotColor; + vec3 spotLightCoord; + bool inSpotLightMap; + #if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0 + SpotLightShadow spotLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) { + spotLight = spotLights[ i ]; + getSpotLightInfo( spotLight, geometryPosition, directLight ); + #if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX + #elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + #define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS + #else + #define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #endif + #if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS ) + spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w; + inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) ); + spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy ); + directLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color; + #endif + #undef SPOT_LIGHT_MAP_INDEX + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + spotLightShadow = spotLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct ) + DirectionalLight directionalLight; + #if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0 + DirectionalLightShadow directionalLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { + directionalLight = directionalLights[ i ]; + getDirectionalLightInfo( directionalLight, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS ) + directionalLightShadow = directionalLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowIntensity, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea ) + RectAreaLight rectAreaLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) { + rectAreaLight = rectAreaLights[ i ]; + RE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if defined( RE_IndirectDiffuse ) + vec3 iblIrradiance = vec3( 0.0 ); + vec3 irradiance = getAmbientLightIrradiance( ambientLightColor ); + #if defined( USE_LIGHT_PROBES ) + irradiance += getLightProbeIrradiance( lightProbe, geometryNormal ); + #endif + #if ( NUM_HEMI_LIGHTS > 0 ) + #pragma unroll_loop_start + for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) { + irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal ); + } + #pragma unroll_loop_end + #endif +#endif +#if defined( RE_IndirectSpecular ) + vec3 radiance = vec3( 0.0 ); + vec3 clearcoatRadiance = vec3( 0.0 ); +#endif`,Ru=`#if defined( RE_IndirectDiffuse ) + #ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; + irradiance += lightMapIrradiance; + #endif + #if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV ) + iblIrradiance += getIBLIrradiance( geometryNormal ); + #endif +#endif +#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular ) + #ifdef USE_ANISOTROPY + radiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy ); + #else + radiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness ); + #endif + #ifdef USE_CLEARCOAT + clearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness ); + #endif +#endif`,Cu=`#if defined( RE_IndirectDiffuse ) + RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif +#if defined( RE_IndirectSpecular ) + RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif`,Pu=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) + gl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5; +#endif`,Du=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) + uniform float logDepthBufFC; + varying float vFragDepth; + varying float vIsPerspective; +#endif`,Lu=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER + varying float vFragDepth; + varying float vIsPerspective; +#endif`,Iu=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER + vFragDepth = 1.0 + gl_Position.w; + vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) ); +#endif`,Uu=`#ifdef USE_MAP + vec4 sampledDiffuseColor = texture2D( map, vMapUv ); + #ifdef DECODE_VIDEO_TEXTURE + sampledDiffuseColor = sRGBTransferEOTF( sampledDiffuseColor ); + #endif + diffuseColor *= sampledDiffuseColor; +#endif`,Nu=`#ifdef USE_MAP + uniform sampler2D map; +#endif`,Fu=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + #if defined( USE_POINTS_UV ) + vec2 uv = vUv; + #else + vec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy; + #endif +#endif +#ifdef USE_MAP + diffuseColor *= texture2D( map, uv ); +#endif +#ifdef USE_ALPHAMAP + diffuseColor.a *= texture2D( alphaMap, uv ).g; +#endif`,Ou=`#if defined( USE_POINTS_UV ) + varying vec2 vUv; +#else + #if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + uniform mat3 uvTransform; + #endif +#endif +#ifdef USE_MAP + uniform sampler2D map; +#endif +#ifdef USE_ALPHAMAP + uniform sampler2D alphaMap; +#endif`,Bu=`float metalnessFactor = metalness; +#ifdef USE_METALNESSMAP + vec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv ); + metalnessFactor *= texelMetalness.b; +#endif`,zu=`#ifdef USE_METALNESSMAP + uniform sampler2D metalnessMap; +#endif`,Hu=`#ifdef USE_INSTANCING_MORPH + float morphTargetInfluences[ MORPHTARGETS_COUNT ]; + float morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + morphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r; + } +#endif`,Gu=`#if defined( USE_MORPHCOLORS ) + vColor *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + #if defined( USE_COLOR_ALPHA ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ]; + #elif defined( USE_COLOR ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]; + #endif + } +#endif`,Vu=`#ifdef USE_MORPHNORMALS + objectNormal *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ]; + } +#endif`,ku=`#ifdef USE_MORPHTARGETS + #ifndef USE_INSTANCING_MORPH + uniform float morphTargetBaseInfluence; + uniform float morphTargetInfluences[ MORPHTARGETS_COUNT ]; + #endif + uniform sampler2DArray morphTargetsTexture; + uniform ivec2 morphTargetsTextureSize; + vec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) { + int texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset; + int y = texelIndex / morphTargetsTextureSize.x; + int x = texelIndex - y * morphTargetsTextureSize.x; + ivec3 morphUV = ivec3( x, y, morphTargetIndex ); + return texelFetch( morphTargetsTexture, morphUV, 0 ); + } +#endif`,Wu=`#ifdef USE_MORPHTARGETS + transformed *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ]; + } +#endif`,Xu=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; +#ifdef FLAT_SHADED + vec3 fdx = dFdx( vViewPosition ); + vec3 fdy = dFdy( vViewPosition ); + vec3 normal = normalize( cross( fdx, fdy ) ); +#else + vec3 normal = normalize( vNormal ); + #ifdef DOUBLE_SIDED + normal *= faceDirection; + #endif +#endif +#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) + #ifdef USE_TANGENT + mat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn = getTangentFrame( - vViewPosition, normal, + #if defined( USE_NORMALMAP ) + vNormalMapUv + #elif defined( USE_CLEARCOAT_NORMALMAP ) + vClearcoatNormalMapUv + #else + vUv + #endif + ); + #endif + #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) + tbn[0] *= faceDirection; + tbn[1] *= faceDirection; + #endif +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + #ifdef USE_TANGENT + mat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv ); + #endif + #if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED ) + tbn2[0] *= faceDirection; + tbn2[1] *= faceDirection; + #endif +#endif +vec3 nonPerturbedNormal = normal;`,qu=`#ifdef USE_NORMALMAP_OBJECTSPACE + normal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; + #ifdef FLIP_SIDED + normal = - normal; + #endif + #ifdef DOUBLE_SIDED + normal = normal * faceDirection; + #endif + normal = normalize( normalMatrix * normal ); +#elif defined( USE_NORMALMAP_TANGENTSPACE ) + vec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; + mapN.xy *= normalScale; + normal = normalize( tbn * mapN ); +#elif defined( USE_BUMPMAP ) + normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); +#endif`,Yu=`#ifndef FLAT_SHADED + varying vec3 vNormal; + #ifdef USE_TANGENT + varying vec3 vTangent; + varying vec3 vBitangent; + #endif +#endif`,$u=`#ifndef FLAT_SHADED + varying vec3 vNormal; + #ifdef USE_TANGENT + varying vec3 vTangent; + varying vec3 vBitangent; + #endif +#endif`,Ku=`#ifndef FLAT_SHADED + vNormal = normalize( transformedNormal ); + #ifdef USE_TANGENT + vTangent = normalize( transformedTangent ); + vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); + #endif +#endif`,Zu=`#ifdef USE_NORMALMAP + uniform sampler2D normalMap; + uniform vec2 normalScale; +#endif +#ifdef USE_NORMALMAP_OBJECTSPACE + uniform mat3 normalMatrix; +#endif +#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) ) + mat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) { + vec3 q0 = dFdx( eye_pos.xyz ); + vec3 q1 = dFdy( eye_pos.xyz ); + vec2 st0 = dFdx( uv.st ); + vec2 st1 = dFdy( uv.st ); + vec3 N = surf_norm; + vec3 q1perp = cross( q1, N ); + vec3 q0perp = cross( N, q0 ); + vec3 T = q1perp * st0.x + q0perp * st1.x; + vec3 B = q1perp * st0.y + q0perp * st1.y; + float det = max( dot( T, T ), dot( B, B ) ); + float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det ); + return mat3( T * scale, B * scale, N ); + } +#endif`,ju=`#ifdef USE_CLEARCOAT + vec3 clearcoatNormal = nonPerturbedNormal; +#endif`,Ju=`#ifdef USE_CLEARCOAT_NORMALMAP + vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0; + clearcoatMapN.xy *= clearcoatNormalScale; + clearcoatNormal = normalize( tbn2 * clearcoatMapN ); +#endif`,Qu=`#ifdef USE_CLEARCOATMAP + uniform sampler2D clearcoatMap; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform sampler2D clearcoatNormalMap; + uniform vec2 clearcoatNormalScale; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform sampler2D clearcoatRoughnessMap; +#endif`,eh=`#ifdef USE_IRIDESCENCEMAP + uniform sampler2D iridescenceMap; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform sampler2D iridescenceThicknessMap; +#endif`,th=`#ifdef OPAQUE +diffuseColor.a = 1.0; +#endif +#ifdef USE_TRANSMISSION +diffuseColor.a *= material.transmissionAlpha; +#endif +gl_FragColor = vec4( outgoingLight, diffuseColor.a );`,nh=`vec3 packNormalToRGB( const in vec3 normal ) { + return normalize( normal ) * 0.5 + 0.5; +} +vec3 unpackRGBToNormal( const in vec3 rgb ) { + return 2.0 * rgb.xyz - 1.0; +} +const float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;const float ShiftRight8 = 1. / 256.; +const float Inv255 = 1. / 255.; +const vec4 PackFactors = vec4( 1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0 ); +const vec2 UnpackFactors2 = vec2( UnpackDownscale, 1.0 / PackFactors.g ); +const vec3 UnpackFactors3 = vec3( UnpackDownscale / PackFactors.rg, 1.0 / PackFactors.b ); +const vec4 UnpackFactors4 = vec4( UnpackDownscale / PackFactors.rgb, 1.0 / PackFactors.a ); +vec4 packDepthToRGBA( const in float v ) { + if( v <= 0.0 ) + return vec4( 0., 0., 0., 0. ); + if( v >= 1.0 ) + return vec4( 1., 1., 1., 1. ); + float vuf; + float af = modf( v * PackFactors.a, vuf ); + float bf = modf( vuf * ShiftRight8, vuf ); + float gf = modf( vuf * ShiftRight8, vuf ); + return vec4( vuf * Inv255, gf * PackUpscale, bf * PackUpscale, af ); +} +vec3 packDepthToRGB( const in float v ) { + if( v <= 0.0 ) + return vec3( 0., 0., 0. ); + if( v >= 1.0 ) + return vec3( 1., 1., 1. ); + float vuf; + float bf = modf( v * PackFactors.b, vuf ); + float gf = modf( vuf * ShiftRight8, vuf ); + return vec3( vuf * Inv255, gf * PackUpscale, bf ); +} +vec2 packDepthToRG( const in float v ) { + if( v <= 0.0 ) + return vec2( 0., 0. ); + if( v >= 1.0 ) + return vec2( 1., 1. ); + float vuf; + float gf = modf( v * 256., vuf ); + return vec2( vuf * Inv255, gf ); +} +float unpackRGBAToDepth( const in vec4 v ) { + return dot( v, UnpackFactors4 ); +} +float unpackRGBToDepth( const in vec3 v ) { + return dot( v, UnpackFactors3 ); +} +float unpackRGToDepth( const in vec2 v ) { + return v.r * UnpackFactors2.r + v.g * UnpackFactors2.g; +} +vec4 pack2HalfToRGBA( const in vec2 v ) { + vec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) ); + return vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w ); +} +vec2 unpackRGBATo2Half( const in vec4 v ) { + return vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) ); +} +float viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) { + return ( viewZ + near ) / ( near - far ); +} +float orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) { + return depth * ( near - far ) - near; +} +float viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) { + return ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ ); +} +float perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) { + return ( near * far ) / ( ( far - near ) * depth - far ); +}`,ih=`#ifdef PREMULTIPLIED_ALPHA + gl_FragColor.rgb *= gl_FragColor.a; +#endif`,rh=`vec4 mvPosition = vec4( transformed, 1.0 ); +#ifdef USE_BATCHING + mvPosition = batchingMatrix * mvPosition; +#endif +#ifdef USE_INSTANCING + mvPosition = instanceMatrix * mvPosition; +#endif +mvPosition = modelViewMatrix * mvPosition; +gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING + gl_FragColor.rgb = dithering( gl_FragColor.rgb ); +#endif`,ah=`#ifdef DITHERING + vec3 dithering( vec3 color ) { + float grid_position = rand( gl_FragCoord.xy ); + vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 ); + dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position ); + return color + dither_shift_RGB; + } +#endif`,oh=`float roughnessFactor = roughness; +#ifdef USE_ROUGHNESSMAP + vec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv ); + roughnessFactor *= texelRoughness.g; +#endif`,ch=`#ifdef USE_ROUGHNESSMAP + uniform sampler2D roughnessMap; +#endif`,lh=`#if NUM_SPOT_LIGHT_COORDS > 0 + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#if NUM_SPOT_LIGHT_MAPS > 0 + uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ]; +#endif +#ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ]; + varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; + struct DirectionalLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ]; + struct SpotLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ]; + varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; + struct PointLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + float shadowCameraNear; + float shadowCameraFar; + }; + uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; + #endif + float texture2DCompare( sampler2D depths, vec2 uv, float compare ) { + float depth = unpackRGBAToDepth( texture2D( depths, uv ) ); + #ifdef USE_REVERSED_DEPTH_BUFFER + return step( depth, compare ); + #else + return step( compare, depth ); + #endif + } + vec2 texture2DDistribution( sampler2D shadow, vec2 uv ) { + return unpackRGBATo2Half( texture2D( shadow, uv ) ); + } + float VSMShadow( sampler2D shadow, vec2 uv, float compare ) { + float occlusion = 1.0; + vec2 distribution = texture2DDistribution( shadow, uv ); + #ifdef USE_REVERSED_DEPTH_BUFFER + float hard_shadow = step( distribution.x, compare ); + #else + float hard_shadow = step( compare, distribution.x ); + #endif + if ( hard_shadow != 1.0 ) { + float distance = compare - distribution.x; + float variance = max( 0.00000, distribution.y * distribution.y ); + float softness_probability = variance / (variance + distance * distance ); softness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 ); occlusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 ); + } + return occlusion; + } + float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) { + float shadow = 1.0; + shadowCoord.xyz /= shadowCoord.w; + shadowCoord.z += shadowBias; + bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0; + bool frustumTest = inFrustum && shadowCoord.z <= 1.0; + if ( frustumTest ) { + #if defined( SHADOWMAP_TYPE_PCF ) + vec2 texelSize = vec2( 1.0 ) / shadowMapSize; + float dx0 = - texelSize.x * shadowRadius; + float dy0 = - texelSize.y * shadowRadius; + float dx1 = + texelSize.x * shadowRadius; + float dy1 = + texelSize.y * shadowRadius; + float dx2 = dx0 / 2.0; + float dy2 = dy0 / 2.0; + float dx3 = dx1 / 2.0; + float dy3 = dy1 / 2.0; + shadow = ( + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) + + texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z ) + ) * ( 1.0 / 17.0 ); + #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) + vec2 texelSize = vec2( 1.0 ) / shadowMapSize; + float dx = texelSize.x; + float dy = texelSize.y; + vec2 uv = shadowCoord.xy; + vec2 f = fract( uv * shadowMapSize + 0.5 ); + uv -= f * texelSize; + shadow = ( + texture2DCompare( shadowMap, uv, shadowCoord.z ) + + texture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) + + texture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) + + texture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) + + mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ), + f.x ) + + mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ), + f.x ) + + mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ), + f.y ) + + mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ), + f.y ) + + mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ), + f.x ), + mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), + texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ), + f.x ), + f.y ) + ) * ( 1.0 / 9.0 ); + #elif defined( SHADOWMAP_TYPE_VSM ) + shadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z ); + #else + shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ); + #endif + } + return mix( 1.0, shadow, shadowIntensity ); + } + vec2 cubeToUV( vec3 v, float texelSizeY ) { + vec3 absV = abs( v ); + float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) ); + absV *= scaleToCube; + v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY ); + vec2 planar = v.xy; + float almostATexel = 1.5 * texelSizeY; + float almostOne = 1.0 - almostATexel; + if ( absV.z >= almostOne ) { + if ( v.z > 0.0 ) + planar.x = 4.0 - v.x; + } else if ( absV.x >= almostOne ) { + float signX = sign( v.x ); + planar.x = v.z * signX + 2.0 * signX; + } else if ( absV.y >= almostOne ) { + float signY = sign( v.y ); + planar.x = v.x + 2.0 * signY + 2.0; + planar.y = v.z * signY - 2.0; + } + return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 ); + } + float getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) { + float shadow = 1.0; + vec3 lightToPosition = shadowCoord.xyz; + + float lightToPositionLength = length( lightToPosition ); + if ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) { + float dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear ); dp += shadowBias; + vec3 bd3D = normalize( lightToPosition ); + vec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) ); + #if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM ) + vec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y; + shadow = ( + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) + + texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp ) + ) * ( 1.0 / 9.0 ); + #else + shadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ); + #endif + } + return mix( 1.0, shadow, shadowIntensity ); + } +#endif`,uh=`#if NUM_SPOT_LIGHT_COORDS > 0 + uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ]; + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ]; + varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; + struct DirectionalLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + struct SpotLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ]; + varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; + struct PointLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + float shadowCameraNear; + float shadowCameraFar; + }; + uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; + #endif +#endif`,hh=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) + vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); + vec4 shadowWorldPosition; +#endif +#if defined( USE_SHADOWMAP ) + #if NUM_DIR_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 ); + vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 ); + vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif +#endif +#if NUM_SPOT_LIGHT_COORDS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) { + shadowWorldPosition = worldPosition; + #if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + shadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias; + #endif + vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end +#endif`,dh=`float getShadowMask() { + float shadow = 1.0; + #ifdef USE_SHADOWMAP + #if NUM_DIR_LIGHT_SHADOWS > 0 + DirectionalLightShadow directionalLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + directionalLight = directionalLightShadows[ i ]; + shadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowIntensity, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + SpotLightShadow spotLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) { + spotLight = spotLightShadows[ i ]; + shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowIntensity, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + PointLightShadow pointLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + pointLight = pointLightShadows[ i ]; + shadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowIntensity, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0; + } + #pragma unroll_loop_end + #endif + #endif + return shadow; +}`,fh=`#ifdef USE_SKINNING + mat4 boneMatX = getBoneMatrix( skinIndex.x ); + mat4 boneMatY = getBoneMatrix( skinIndex.y ); + mat4 boneMatZ = getBoneMatrix( skinIndex.z ); + mat4 boneMatW = getBoneMatrix( skinIndex.w ); +#endif`,ph=`#ifdef USE_SKINNING + uniform mat4 bindMatrix; + uniform mat4 bindMatrixInverse; + uniform highp sampler2D boneTexture; + mat4 getBoneMatrix( const in float i ) { + int size = textureSize( boneTexture, 0 ).x; + int j = int( i ) * 4; + int x = j % size; + int y = j / size; + vec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 ); + vec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 ); + vec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 ); + vec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 ); + return mat4( v1, v2, v3, v4 ); + } +#endif`,mh=`#ifdef USE_SKINNING + vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); + vec4 skinned = vec4( 0.0 ); + skinned += boneMatX * skinVertex * skinWeight.x; + skinned += boneMatY * skinVertex * skinWeight.y; + skinned += boneMatZ * skinVertex * skinWeight.z; + skinned += boneMatW * skinVertex * skinWeight.w; + transformed = ( bindMatrixInverse * skinned ).xyz; +#endif`,gh=`#ifdef USE_SKINNING + mat4 skinMatrix = mat4( 0.0 ); + skinMatrix += skinWeight.x * boneMatX; + skinMatrix += skinWeight.y * boneMatY; + skinMatrix += skinWeight.z * boneMatZ; + skinMatrix += skinWeight.w * boneMatW; + skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix; + objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz; + #ifdef USE_TANGENT + objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; + #endif +#endif`,_h=`float specularStrength; +#ifdef USE_SPECULARMAP + vec4 texelSpecular = texture2D( specularMap, vSpecularMapUv ); + specularStrength = texelSpecular.r; +#else + specularStrength = 1.0; +#endif`,vh=`#ifdef USE_SPECULARMAP + uniform sampler2D specularMap; +#endif`,xh=`#if defined( TONE_MAPPING ) + gl_FragColor.rgb = toneMapping( gl_FragColor.rgb ); +#endif`,Mh=`#ifndef saturate +#define saturate( a ) clamp( a, 0.0, 1.0 ) +#endif +uniform float toneMappingExposure; +vec3 LinearToneMapping( vec3 color ) { + return saturate( toneMappingExposure * color ); +} +vec3 ReinhardToneMapping( vec3 color ) { + color *= toneMappingExposure; + return saturate( color / ( vec3( 1.0 ) + color ) ); +} +vec3 CineonToneMapping( vec3 color ) { + color *= toneMappingExposure; + color = max( vec3( 0.0 ), color - 0.004 ); + return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) ); +} +vec3 RRTAndODTFit( vec3 v ) { + vec3 a = v * ( v + 0.0245786 ) - 0.000090537; + vec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081; + return a / b; +} +vec3 ACESFilmicToneMapping( vec3 color ) { + const mat3 ACESInputMat = mat3( + vec3( 0.59719, 0.07600, 0.02840 ), vec3( 0.35458, 0.90834, 0.13383 ), + vec3( 0.04823, 0.01566, 0.83777 ) + ); + const mat3 ACESOutputMat = mat3( + vec3( 1.60475, -0.10208, -0.00327 ), vec3( -0.53108, 1.10813, -0.07276 ), + vec3( -0.07367, -0.00605, 1.07602 ) + ); + color *= toneMappingExposure / 0.6; + color = ACESInputMat * color; + color = RRTAndODTFit( color ); + color = ACESOutputMat * color; + return saturate( color ); +} +const mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3( + vec3( 1.6605, - 0.1246, - 0.0182 ), + vec3( - 0.5876, 1.1329, - 0.1006 ), + vec3( - 0.0728, - 0.0083, 1.1187 ) +); +const mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3( + vec3( 0.6274, 0.0691, 0.0164 ), + vec3( 0.3293, 0.9195, 0.0880 ), + vec3( 0.0433, 0.0113, 0.8956 ) +); +vec3 agxDefaultContrastApprox( vec3 x ) { + vec3 x2 = x * x; + vec3 x4 = x2 * x2; + return + 15.5 * x4 * x2 + - 40.14 * x4 * x + + 31.96 * x4 + - 6.868 * x2 * x + + 0.4298 * x2 + + 0.1191 * x + - 0.00232; +} +vec3 AgXToneMapping( vec3 color ) { + const mat3 AgXInsetMatrix = mat3( + vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ), + vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ), + vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 ) + ); + const mat3 AgXOutsetMatrix = mat3( + vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ), + vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ), + vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 ) + ); + const float AgxMinEv = - 12.47393; const float AgxMaxEv = 4.026069; + color *= toneMappingExposure; + color = LINEAR_SRGB_TO_LINEAR_REC2020 * color; + color = AgXInsetMatrix * color; + color = max( color, 1e-10 ); color = log2( color ); + color = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv ); + color = clamp( color, 0.0, 1.0 ); + color = agxDefaultContrastApprox( color ); + color = AgXOutsetMatrix * color; + color = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) ); + color = LINEAR_REC2020_TO_LINEAR_SRGB * color; + color = clamp( color, 0.0, 1.0 ); + return color; +} +vec3 NeutralToneMapping( vec3 color ) { + const float StartCompression = 0.8 - 0.04; + const float Desaturation = 0.15; + color *= toneMappingExposure; + float x = min( color.r, min( color.g, color.b ) ); + float offset = x < 0.08 ? x - 6.25 * x * x : 0.04; + color -= offset; + float peak = max( color.r, max( color.g, color.b ) ); + if ( peak < StartCompression ) return color; + float d = 1. - StartCompression; + float newPeak = 1. - d * d / ( peak + d - StartCompression ); + color *= newPeak / peak; + float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. ); + return mix( color, vec3( newPeak ), g ); +} +vec3 CustomToneMapping( vec3 color ) { return color; }`,Sh=`#ifdef USE_TRANSMISSION + material.transmission = transmission; + material.transmissionAlpha = 1.0; + material.thickness = thickness; + material.attenuationDistance = attenuationDistance; + material.attenuationColor = attenuationColor; + #ifdef USE_TRANSMISSIONMAP + material.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r; + #endif + #ifdef USE_THICKNESSMAP + material.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g; + #endif + vec3 pos = vWorldPosition; + vec3 v = normalize( cameraPosition - pos ); + vec3 n = inverseTransformDirection( normal, viewMatrix ); + vec4 transmitted = getIBLVolumeRefraction( + n, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90, + pos, modelMatrix, viewMatrix, projectionMatrix, material.dispersion, material.ior, material.thickness, + material.attenuationColor, material.attenuationDistance ); + material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission ); + totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission ); +#endif`,Eh=`#ifdef USE_TRANSMISSION + uniform float transmission; + uniform float thickness; + uniform float attenuationDistance; + uniform vec3 attenuationColor; + #ifdef USE_TRANSMISSIONMAP + uniform sampler2D transmissionMap; + #endif + #ifdef USE_THICKNESSMAP + uniform sampler2D thicknessMap; + #endif + uniform vec2 transmissionSamplerSize; + uniform sampler2D transmissionSamplerMap; + uniform mat4 modelMatrix; + uniform mat4 projectionMatrix; + varying vec3 vWorldPosition; + float w0( float a ) { + return ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 ); + } + float w1( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 ); + } + float w2( float a ){ + return ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 ); + } + float w3( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * a ); + } + float g0( float a ) { + return w0( a ) + w1( a ); + } + float g1( float a ) { + return w2( a ) + w3( a ); + } + float h0( float a ) { + return - 1.0 + w1( a ) / ( w0( a ) + w1( a ) ); + } + float h1( float a ) { + return 1.0 + w3( a ) / ( w2( a ) + w3( a ) ); + } + vec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) { + uv = uv * texelSize.zw + 0.5; + vec2 iuv = floor( uv ); + vec2 fuv = fract( uv ); + float g0x = g0( fuv.x ); + float g1x = g1( fuv.x ); + float h0x = h0( fuv.x ); + float h1x = h1( fuv.x ); + float h0y = h0( fuv.y ); + float h1y = h1( fuv.y ); + vec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + vec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + return g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) + + g1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) ); + } + vec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) { + vec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) ); + vec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) ); + vec2 fLodSizeInv = 1.0 / fLodSize; + vec2 cLodSizeInv = 1.0 / cLodSize; + vec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) ); + vec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) ); + return mix( fSample, cSample, fract( lod ) ); + } + vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) { + vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior ); + vec3 modelScale; + modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) ); + modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) ); + modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) ); + return normalize( refractionVector ) * thickness * modelScale; + } + float applyIorToRoughness( const in float roughness, const in float ior ) { + return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 ); + } + vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) { + float lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior ); + return textureBicubic( transmissionSamplerMap, fragCoord.xy, lod ); + } + vec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) { + if ( isinf( attenuationDistance ) ) { + return vec3( 1.0 ); + } else { + vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance; + vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); return transmittance; + } + } + vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor, + const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix, + const in mat4 viewMatrix, const in mat4 projMatrix, const in float dispersion, const in float ior, const in float thickness, + const in vec3 attenuationColor, const in float attenuationDistance ) { + vec4 transmittedLight; + vec3 transmittance; + #ifdef USE_DISPERSION + float halfSpread = ( ior - 1.0 ) * 0.025 * dispersion; + vec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread ); + for ( int i = 0; i < 3; i ++ ) { + vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix ); + vec3 refractedRayExit = position + transmissionRay; + vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); + vec2 refractionCoords = ndcPos.xy / ndcPos.w; + refractionCoords += 1.0; + refractionCoords /= 2.0; + vec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] ); + transmittedLight[ i ] = transmissionSample[ i ]; + transmittedLight.a += transmissionSample.a; + transmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ]; + } + transmittedLight.a /= 3.0; + #else + vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); + vec3 refractedRayExit = position + transmissionRay; + vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); + vec2 refractionCoords = ndcPos.xy / ndcPos.w; + refractionCoords += 1.0; + refractionCoords /= 2.0; + transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); + transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ); + #endif + vec3 attenuatedColor = transmittance * transmittedLight.rgb; + vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness ); + float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; + return vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor ); + } +#endif`,yh=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + varying vec2 vNormalMapUv; +#endif +#ifdef USE_EMISSIVEMAP + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_SPECULARMAP + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`,Th=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + uniform mat3 mapTransform; + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + uniform mat3 alphaMapTransform; + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + uniform mat3 lightMapTransform; + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + uniform mat3 aoMapTransform; + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + uniform mat3 bumpMapTransform; + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + uniform mat3 normalMapTransform; + varying vec2 vNormalMapUv; +#endif +#ifdef USE_DISPLACEMENTMAP + uniform mat3 displacementMapTransform; + varying vec2 vDisplacementMapUv; +#endif +#ifdef USE_EMISSIVEMAP + uniform mat3 emissiveMapTransform; + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + uniform mat3 metalnessMapTransform; + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + uniform mat3 roughnessMapTransform; + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + uniform mat3 anisotropyMapTransform; + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + uniform mat3 clearcoatMapTransform; + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform mat3 clearcoatNormalMapTransform; + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform mat3 clearcoatRoughnessMapTransform; + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + uniform mat3 sheenColorMapTransform; + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + uniform mat3 sheenRoughnessMapTransform; + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + uniform mat3 iridescenceMapTransform; + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform mat3 iridescenceThicknessMapTransform; + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SPECULARMAP + uniform mat3 specularMapTransform; + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + uniform mat3 specularColorMapTransform; + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + uniform mat3 specularIntensityMapTransform; + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`,Ah=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + vUv = vec3( uv, 1 ).xy; +#endif +#ifdef USE_MAP + vMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ALPHAMAP + vAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_LIGHTMAP + vLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_AOMAP + vAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_BUMPMAP + vBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_NORMALMAP + vNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_DISPLACEMENTMAP + vDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_EMISSIVEMAP + vEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_METALNESSMAP + vMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ROUGHNESSMAP + vRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ANISOTROPYMAP + vAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOATMAP + vClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + vClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + vClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCEMAP + vIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + vIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_COLORMAP + vSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + vSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULARMAP + vSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_COLORMAP + vSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + vSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_TRANSMISSIONMAP + vTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_THICKNESSMAP + vThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy; +#endif`,bh=`#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 + vec4 worldPosition = vec4( transformed, 1.0 ); + #ifdef USE_BATCHING + worldPosition = batchingMatrix * worldPosition; + #endif + #ifdef USE_INSTANCING + worldPosition = instanceMatrix * worldPosition; + #endif + worldPosition = modelMatrix * worldPosition; +#endif`;const wh=`varying vec2 vUv; +uniform mat3 uvTransform; +void main() { + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + gl_Position = vec4( position.xy, 1.0, 1.0 ); +}`,Rh=`uniform sampler2D t2D; +uniform float backgroundIntensity; +varying vec2 vUv; +void main() { + vec4 texColor = texture2D( t2D, vUv ); + #ifdef DECODE_VIDEO_TEXTURE + texColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`,Ch=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`,Ph=`#ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; +#elif defined( ENVMAP_TYPE_CUBE_UV ) + uniform sampler2D envMap; +#endif +uniform float flipEnvMap; +uniform float backgroundBlurriness; +uniform float backgroundIntensity; +uniform mat3 backgroundRotation; +varying vec3 vWorldDirection; +#include +void main() { + #ifdef ENVMAP_TYPE_CUBE + vec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) ); + #elif defined( ENVMAP_TYPE_CUBE_UV ) + vec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness ); + #else + vec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`,Dh=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`,Lh=`uniform samplerCube tCube; +uniform float tFlip; +uniform float opacity; +varying vec3 vWorldDirection; +void main() { + vec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) ); + gl_FragColor = texColor; + gl_FragColor.a *= opacity; + #include + #include +}`,Ih=`#include +#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + #include + #include + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vHighPrecisionZW = gl_Position.zw; +}`,Uh=`#if DEPTH_PACKING == 3200 + uniform float opacity; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + vec4 diffuseColor = vec4( 1.0 ); + #include + #if DEPTH_PACKING == 3200 + diffuseColor.a = opacity; + #endif + #include + #include + #include + #include + #include + #ifdef USE_REVERSED_DEPTH_BUFFER + float fragCoordZ = vHighPrecisionZW[ 0 ] / vHighPrecisionZW[ 1 ]; + #else + float fragCoordZ = 0.5 * vHighPrecisionZW[ 0 ] / vHighPrecisionZW[ 1 ] + 0.5; + #endif + #if DEPTH_PACKING == 3200 + gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity ); + #elif DEPTH_PACKING == 3201 + gl_FragColor = packDepthToRGBA( fragCoordZ ); + #elif DEPTH_PACKING == 3202 + gl_FragColor = vec4( packDepthToRGB( fragCoordZ ), 1.0 ); + #elif DEPTH_PACKING == 3203 + gl_FragColor = vec4( packDepthToRG( fragCoordZ ), 0.0, 1.0 ); + #endif +}`,Nh=`#define DISTANCE +varying vec3 vWorldPosition; +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vWorldPosition = worldPosition.xyz; +}`,Fh=`#define DISTANCE +uniform vec3 referencePosition; +uniform float nearDistance; +uniform float farDistance; +varying vec3 vWorldPosition; +#include +#include +#include +#include +#include +#include +#include +#include +void main () { + vec4 diffuseColor = vec4( 1.0 ); + #include + #include + #include + #include + #include + float dist = length( vWorldPosition - referencePosition ); + dist = ( dist - nearDistance ) / ( farDistance - nearDistance ); + dist = saturate( dist ); + gl_FragColor = packDepthToRGBA( dist ); +}`,Oh=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include +}`,Bh=`uniform sampler2D tEquirect; +varying vec3 vWorldDirection; +#include +void main() { + vec3 direction = normalize( vWorldDirection ); + vec2 sampleUV = equirectUv( direction ); + gl_FragColor = texture2D( tEquirect, sampleUV ); + #include + #include +}`,zh=`uniform float scale; +attribute float lineDistance; +varying float vLineDistance; +#include +#include +#include +#include +#include +#include +#include +void main() { + vLineDistance = scale * lineDistance; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,Hh=`uniform vec3 diffuse; +uniform float opacity; +uniform float dashSize; +uniform float totalSize; +varying float vLineDistance; +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + if ( mod( vLineDistance, totalSize ) > dashSize ) { + discard; + } + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include + #include +}`,Gh=`#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #if defined ( USE_ENVMAP ) || defined ( USE_SKINNING ) + #include + #include + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,Vh=`uniform vec3 diffuse; +uniform float opacity; +#ifndef FLAT_SHADED + varying vec3 vNormal; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + #include + #include + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + #ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI; + #else + reflectedLight.indirectDiffuse += vec3( 1.0 ); + #endif + #include + reflectedLight.indirectDiffuse *= diffuseColor.rgb; + vec3 outgoingLight = reflectedLight.indirectDiffuse; + #include + #include + #include + #include + #include + #include + #include +}`,kh=`#define LAMBERT +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include + #include +}`,Wh=`#define LAMBERT +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include + #include +}`,Xh=`#define MATCAP +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; +}`,qh=`#define MATCAP +uniform vec3 diffuse; +uniform float opacity; +uniform sampler2D matcap; +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 viewDir = normalize( vViewPosition ); + vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) ); + vec3 y = cross( viewDir, x ); + vec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5; + #ifdef USE_MATCAP + vec4 matcapColor = texture2D( matcap, uv ); + #else + vec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 ); + #endif + vec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb; + #include + #include + #include + #include + #include + #include +}`,Yh=`#define NORMAL +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + varying vec3 vViewPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + vViewPosition = - mvPosition.xyz; +#endif +}`,$h=`#define NORMAL +uniform float opacity; +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + varying vec3 vViewPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity ); + #include + #include + #include + #include + gl_FragColor = vec4( packNormalToRGB( normal ), diffuseColor.a ); + #ifdef OPAQUE + gl_FragColor.a = 1.0; + #endif +}`,Kh=`#define PHONG +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include + #include +}`,Zh=`#define PHONG +uniform vec3 diffuse; +uniform vec3 emissive; +uniform vec3 specular; +uniform float shininess; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include + #include +}`,jh=`#define STANDARD +varying vec3 vViewPosition; +#ifdef USE_TRANSMISSION + varying vec3 vWorldPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include +#ifdef USE_TRANSMISSION + vWorldPosition = worldPosition.xyz; +#endif +}`,Jh=`#define STANDARD +#ifdef PHYSICAL + #define IOR + #define USE_SPECULAR +#endif +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float roughness; +uniform float metalness; +uniform float opacity; +#ifdef IOR + uniform float ior; +#endif +#ifdef USE_SPECULAR + uniform float specularIntensity; + uniform vec3 specularColor; + #ifdef USE_SPECULAR_COLORMAP + uniform sampler2D specularColorMap; + #endif + #ifdef USE_SPECULAR_INTENSITYMAP + uniform sampler2D specularIntensityMap; + #endif +#endif +#ifdef USE_CLEARCOAT + uniform float clearcoat; + uniform float clearcoatRoughness; +#endif +#ifdef USE_DISPERSION + uniform float dispersion; +#endif +#ifdef USE_IRIDESCENCE + uniform float iridescence; + uniform float iridescenceIOR; + uniform float iridescenceThicknessMinimum; + uniform float iridescenceThicknessMaximum; +#endif +#ifdef USE_SHEEN + uniform vec3 sheenColor; + uniform float sheenRoughness; + #ifdef USE_SHEEN_COLORMAP + uniform sampler2D sheenColorMap; + #endif + #ifdef USE_SHEEN_ROUGHNESSMAP + uniform sampler2D sheenRoughnessMap; + #endif +#endif +#ifdef USE_ANISOTROPY + uniform vec2 anisotropyVector; + #ifdef USE_ANISOTROPYMAP + uniform sampler2D anisotropyMap; + #endif +#endif +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse; + vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular; + #include + vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance; + #ifdef USE_SHEEN + float sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor ); + outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect; + #endif + #ifdef USE_CLEARCOAT + float dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) ); + vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc ); + outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat; + #endif + #include + #include + #include + #include + #include + #include +}`,Qh=`#define TOON +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include +}`,ed=`#define TOON +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include +}`,td=`uniform float size; +uniform float scale; +#include +#include +#include +#include +#include +#include +#ifdef USE_POINTS_UV + varying vec2 vUv; + uniform mat3 uvTransform; +#endif +void main() { + #ifdef USE_POINTS_UV + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + #endif + #include + #include + #include + #include + #include + #include + gl_PointSize = size; + #ifdef USE_SIZEATTENUATION + bool isPerspective = isPerspectiveMatrix( projectionMatrix ); + if ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z ); + #endif + #include + #include + #include + #include +}`,nd=`uniform vec3 diffuse; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include + #include +}`,id=`#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,rd=`uniform vec3 color; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + gl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) ); + #include + #include + #include +}`,sd=`uniform float rotation; +uniform vec2 center; +#include +#include +#include +#include +#include +void main() { + #include + vec4 mvPosition = modelViewMatrix[ 3 ]; + vec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) ); + #ifndef USE_SIZEATTENUATION + bool isPerspective = isPerspectiveMatrix( projectionMatrix ); + if ( isPerspective ) scale *= - mvPosition.z; + #endif + vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale; + vec2 rotatedPosition; + rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y; + rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y; + mvPosition.xy += rotatedPosition; + gl_Position = projectionMatrix * mvPosition; + #include + #include + #include +}`,ad=`uniform vec3 diffuse; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include +}`,Ne={alphahash_fragment:Rl,alphahash_pars_fragment:Cl,alphamap_fragment:Pl,alphamap_pars_fragment:Dl,alphatest_fragment:Ll,alphatest_pars_fragment:Il,aomap_fragment:Ul,aomap_pars_fragment:Nl,batching_pars_vertex:Fl,batching_vertex:Ol,begin_vertex:Bl,beginnormal_vertex:zl,bsdfs:Hl,iridescence_fragment:Gl,bumpmap_pars_fragment:Vl,clipping_planes_fragment:kl,clipping_planes_pars_fragment:Wl,clipping_planes_pars_vertex:Xl,clipping_planes_vertex:ql,color_fragment:Yl,color_pars_fragment:$l,color_pars_vertex:Kl,color_vertex:Zl,common:jl,cube_uv_reflection_fragment:Jl,defaultnormal_vertex:Ql,displacementmap_pars_vertex:eu,displacementmap_vertex:tu,emissivemap_fragment:nu,emissivemap_pars_fragment:iu,colorspace_fragment:ru,colorspace_pars_fragment:su,envmap_fragment:au,envmap_common_pars_fragment:ou,envmap_pars_fragment:cu,envmap_pars_vertex:lu,envmap_physical_pars_fragment:Mu,envmap_vertex:uu,fog_vertex:hu,fog_pars_vertex:du,fog_fragment:fu,fog_pars_fragment:pu,gradientmap_pars_fragment:mu,lightmap_pars_fragment:gu,lights_lambert_fragment:_u,lights_lambert_pars_fragment:vu,lights_pars_begin:xu,lights_toon_fragment:Su,lights_toon_pars_fragment:Eu,lights_phong_fragment:yu,lights_phong_pars_fragment:Tu,lights_physical_fragment:Au,lights_physical_pars_fragment:bu,lights_fragment_begin:wu,lights_fragment_maps:Ru,lights_fragment_end:Cu,logdepthbuf_fragment:Pu,logdepthbuf_pars_fragment:Du,logdepthbuf_pars_vertex:Lu,logdepthbuf_vertex:Iu,map_fragment:Uu,map_pars_fragment:Nu,map_particle_fragment:Fu,map_particle_pars_fragment:Ou,metalnessmap_fragment:Bu,metalnessmap_pars_fragment:zu,morphinstance_vertex:Hu,morphcolor_vertex:Gu,morphnormal_vertex:Vu,morphtarget_pars_vertex:ku,morphtarget_vertex:Wu,normal_fragment_begin:Xu,normal_fragment_maps:qu,normal_pars_fragment:Yu,normal_pars_vertex:$u,normal_vertex:Ku,normalmap_pars_fragment:Zu,clearcoat_normal_fragment_begin:ju,clearcoat_normal_fragment_maps:Ju,clearcoat_pars_fragment:Qu,iridescence_pars_fragment:eh,opaque_fragment:th,packing:nh,premultiplied_alpha_fragment:ih,project_vertex:rh,dithering_fragment:sh,dithering_pars_fragment:ah,roughnessmap_fragment:oh,roughnessmap_pars_fragment:ch,shadowmap_pars_fragment:lh,shadowmap_pars_vertex:uh,shadowmap_vertex:hh,shadowmask_pars_fragment:dh,skinbase_vertex:fh,skinning_pars_vertex:ph,skinning_vertex:mh,skinnormal_vertex:gh,specularmap_fragment:_h,specularmap_pars_fragment:vh,tonemapping_fragment:xh,tonemapping_pars_fragment:Mh,transmission_fragment:Sh,transmission_pars_fragment:Eh,uv_pars_fragment:yh,uv_pars_vertex:Th,uv_vertex:Ah,worldpos_vertex:bh,background_vert:wh,background_frag:Rh,backgroundCube_vert:Ch,backgroundCube_frag:Ph,cube_vert:Dh,cube_frag:Lh,depth_vert:Ih,depth_frag:Uh,distanceRGBA_vert:Nh,distanceRGBA_frag:Fh,equirect_vert:Oh,equirect_frag:Bh,linedashed_vert:zh,linedashed_frag:Hh,meshbasic_vert:Gh,meshbasic_frag:Vh,meshlambert_vert:kh,meshlambert_frag:Wh,meshmatcap_vert:Xh,meshmatcap_frag:qh,meshnormal_vert:Yh,meshnormal_frag:$h,meshphong_vert:Kh,meshphong_frag:Zh,meshphysical_vert:jh,meshphysical_frag:Jh,meshtoon_vert:Qh,meshtoon_frag:ed,points_vert:td,points_frag:nd,shadow_vert:id,shadow_frag:rd,sprite_vert:sd,sprite_frag:ad},re={common:{diffuse:{value:new Fe(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new Ie},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new Ie}},envmap:{envMap:{value:null},envMapRotation:{value:new Ie},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new Ie}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new Ie}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new Ie},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new Ie},normalScale:{value:new Ge(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new Ie},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new Ie}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new Ie}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new Ie}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Fe(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new Fe(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0},uvTransform:{value:new Ie}},sprite:{diffuse:{value:new Fe(16777215)},opacity:{value:1},center:{value:new Ge(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new Ie},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0}}},Vt={basic:{uniforms:xt([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.fog]),vertexShader:Ne.meshbasic_vert,fragmentShader:Ne.meshbasic_frag},lambert:{uniforms:xt([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.fog,re.lights,{emissive:{value:new Fe(0)}}]),vertexShader:Ne.meshlambert_vert,fragmentShader:Ne.meshlambert_frag},phong:{uniforms:xt([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.fog,re.lights,{emissive:{value:new Fe(0)},specular:{value:new Fe(1118481)},shininess:{value:30}}]),vertexShader:Ne.meshphong_vert,fragmentShader:Ne.meshphong_frag},standard:{uniforms:xt([re.common,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.roughnessmap,re.metalnessmap,re.fog,re.lights,{emissive:{value:new Fe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:Ne.meshphysical_vert,fragmentShader:Ne.meshphysical_frag},toon:{uniforms:xt([re.common,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.gradientmap,re.fog,re.lights,{emissive:{value:new Fe(0)}}]),vertexShader:Ne.meshtoon_vert,fragmentShader:Ne.meshtoon_frag},matcap:{uniforms:xt([re.common,re.bumpmap,re.normalmap,re.displacementmap,re.fog,{matcap:{value:null}}]),vertexShader:Ne.meshmatcap_vert,fragmentShader:Ne.meshmatcap_frag},points:{uniforms:xt([re.points,re.fog]),vertexShader:Ne.points_vert,fragmentShader:Ne.points_frag},dashed:{uniforms:xt([re.common,re.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:Ne.linedashed_vert,fragmentShader:Ne.linedashed_frag},depth:{uniforms:xt([re.common,re.displacementmap]),vertexShader:Ne.depth_vert,fragmentShader:Ne.depth_frag},normal:{uniforms:xt([re.common,re.bumpmap,re.normalmap,re.displacementmap,{opacity:{value:1}}]),vertexShader:Ne.meshnormal_vert,fragmentShader:Ne.meshnormal_frag},sprite:{uniforms:xt([re.sprite,re.fog]),vertexShader:Ne.sprite_vert,fragmentShader:Ne.sprite_frag},background:{uniforms:{uvTransform:{value:new Ie},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:Ne.background_vert,fragmentShader:Ne.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new Ie}},vertexShader:Ne.backgroundCube_vert,fragmentShader:Ne.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:Ne.cube_vert,fragmentShader:Ne.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:Ne.equirect_vert,fragmentShader:Ne.equirect_frag},distanceRGBA:{uniforms:xt([re.common,re.displacementmap,{referencePosition:{value:new N},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:Ne.distanceRGBA_vert,fragmentShader:Ne.distanceRGBA_frag},shadow:{uniforms:xt([re.lights,re.fog,{color:{value:new Fe(0)},opacity:{value:1}}]),vertexShader:Ne.shadow_vert,fragmentShader:Ne.shadow_frag}};Vt.physical={uniforms:xt([Vt.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new Ie},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new Ie},clearcoatNormalScale:{value:new Ge(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new Ie},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new Ie},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new Ie},sheen:{value:0},sheenColor:{value:new Fe(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new Ie},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new Ie},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new Ie},transmissionSamplerSize:{value:new Ge},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new Ie},attenuationDistance:{value:0},attenuationColor:{value:new Fe(0)},specularColor:{value:new Fe(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new Ie},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new Ie},anisotropyVector:{value:new Ge},anisotropyMap:{value:null},anisotropyMapTransform:{value:new Ie}}]),vertexShader:Ne.meshphysical_vert,fragmentShader:Ne.meshphysical_frag};const Zi={r:0,b:0,g:0},En=new $t,od=new it;function cd(i,e,t,n,r,s,a){const o=new Fe(0);let l=s===!0?0:1,c,d,h=null,f=0,m=null;function _(A){let E=A.isScene===!0?A.background:null;return E&&E.isTexture&&(E=(A.backgroundBlurriness>0?t:e).get(E)),E}function x(A){let E=!1;const C=_(A);C===null?u(o,l):C&&C.isColor&&(u(C,1),E=!0);const R=i.xr.getEnvironmentBlendMode();R==="additive"?n.buffers.color.setClear(0,0,0,1,a):R==="alpha-blend"&&n.buffers.color.setClear(0,0,0,0,a),(i.autoClear||E)&&(n.buffers.depth.setTest(!0),n.buffers.depth.setMask(!0),n.buffers.color.setMask(!0),i.clear(i.autoClearColor,i.autoClearDepth,i.autoClearStencil))}function p(A,E){const C=_(E);C&&(C.isCubeTexture||C.mapping===dr)?(d===void 0&&(d=new Et(new yi(1,1,1),new mn({name:"BackgroundCubeMaterial",uniforms:ei(Vt.backgroundCube.uniforms),vertexShader:Vt.backgroundCube.vertexShader,fragmentShader:Vt.backgroundCube.fragmentShader,side:yt,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),d.geometry.deleteAttribute("normal"),d.geometry.deleteAttribute("uv"),d.onBeforeRender=function(R,w,U){this.matrixWorld.copyPosition(U.matrixWorld)},Object.defineProperty(d.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),r.update(d)),En.copy(E.backgroundRotation),En.x*=-1,En.y*=-1,En.z*=-1,C.isCubeTexture&&C.isRenderTargetTexture===!1&&(En.y*=-1,En.z*=-1),d.material.uniforms.envMap.value=C,d.material.uniforms.flipEnvMap.value=C.isCubeTexture&&C.isRenderTargetTexture===!1?-1:1,d.material.uniforms.backgroundBlurriness.value=E.backgroundBlurriness,d.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,d.material.uniforms.backgroundRotation.value.setFromMatrix4(od.makeRotationFromEuler(En)),d.material.toneMapped=ke.getTransfer(C.colorSpace)!==Ye,(h!==C||f!==C.version||m!==i.toneMapping)&&(d.material.needsUpdate=!0,h=C,f=C.version,m=i.toneMapping),d.layers.enableAll(),A.unshift(d,d.geometry,d.material,0,0,null)):C&&C.isTexture&&(c===void 0&&(c=new Et(new Ti(2,2),new mn({name:"BackgroundMaterial",uniforms:ei(Vt.background.uniforms),vertexShader:Vt.background.vertexShader,fragmentShader:Vt.background.fragmentShader,side:pn,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),c.geometry.deleteAttribute("normal"),Object.defineProperty(c.material,"map",{get:function(){return this.uniforms.t2D.value}}),r.update(c)),c.material.uniforms.t2D.value=C,c.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,c.material.toneMapped=ke.getTransfer(C.colorSpace)!==Ye,C.matrixAutoUpdate===!0&&C.updateMatrix(),c.material.uniforms.uvTransform.value.copy(C.matrix),(h!==C||f!==C.version||m!==i.toneMapping)&&(c.material.needsUpdate=!0,h=C,f=C.version,m=i.toneMapping),c.layers.enableAll(),A.unshift(c,c.geometry,c.material,0,0,null))}function u(A,E){A.getRGB(Zi,Lo(i)),n.buffers.color.setClear(Zi.r,Zi.g,Zi.b,E,a)}function b(){d!==void 0&&(d.geometry.dispose(),d.material.dispose(),d=void 0),c!==void 0&&(c.geometry.dispose(),c.material.dispose(),c=void 0)}return{getClearColor:function(){return o},setClearColor:function(A,E=1){o.set(A),l=E,u(o,l)},getClearAlpha:function(){return l},setClearAlpha:function(A){l=A,u(o,l)},render:x,addToRenderList:p,dispose:b}}function ld(i,e){const t=i.getParameter(i.MAX_VERTEX_ATTRIBS),n={},r=f(null);let s=r,a=!1;function o(M,P,O,H,q){let W=!1;const X=h(H,O,P);s!==X&&(s=X,c(s.object)),W=m(M,H,O,q),W&&_(M,H,O,q),q!==null&&e.update(q,i.ELEMENT_ARRAY_BUFFER),(W||a)&&(a=!1,E(M,P,O,H),q!==null&&i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,e.get(q).buffer))}function l(){return i.createVertexArray()}function c(M){return i.bindVertexArray(M)}function d(M){return i.deleteVertexArray(M)}function h(M,P,O){const H=O.wireframe===!0;let q=n[M.id];q===void 0&&(q={},n[M.id]=q);let W=q[P.id];W===void 0&&(W={},q[P.id]=W);let X=W[H];return X===void 0&&(X=f(l()),W[H]=X),X}function f(M){const P=[],O=[],H=[];for(let q=0;q=0){const le=q[G];let Ee=W[G];if(Ee===void 0&&(G==="instanceMatrix"&&M.instanceMatrix&&(Ee=M.instanceMatrix),G==="instanceColor"&&M.instanceColor&&(Ee=M.instanceColor)),le===void 0||le.attribute!==Ee||Ee&&le.data!==Ee.data)return!0;X++}return s.attributesNum!==X||s.index!==H}function _(M,P,O,H){const q={},W=P.attributes;let X=0;const Z=O.getAttributes();for(const G in Z)if(Z[G].location>=0){let le=W[G];le===void 0&&(G==="instanceMatrix"&&M.instanceMatrix&&(le=M.instanceMatrix),G==="instanceColor"&&M.instanceColor&&(le=M.instanceColor));const Ee={};Ee.attribute=le,le&&le.data&&(Ee.data=le.data),q[G]=Ee,X++}s.attributes=q,s.attributesNum=X,s.index=H}function x(){const M=s.newAttributes;for(let P=0,O=M.length;P=0){let se=q[Z];if(se===void 0&&(Z==="instanceMatrix"&&M.instanceMatrix&&(se=M.instanceMatrix),Z==="instanceColor"&&M.instanceColor&&(se=M.instanceColor)),se!==void 0){const le=se.normalized,Ee=se.itemSize,Oe=e.get(se);if(Oe===void 0)continue;const Ke=Oe.buffer,Je=Oe.type,We=Oe.bytesPerElement,Y=Je===i.INT||Je===i.UNSIGNED_INT||se.gpuType===Vs;if(se.isInterleavedBufferAttribute){const j=se.data,de=j.stride,Ce=se.offset;if(j.isInstancedInterleavedBuffer){for(let Se=0;Se0&&i.getShaderPrecisionFormat(i.FRAGMENT_SHADER,i.HIGH_FLOAT).precision>0)return"highp";w="mediump"}return w==="mediump"&&i.getShaderPrecisionFormat(i.VERTEX_SHADER,i.MEDIUM_FLOAT).precision>0&&i.getShaderPrecisionFormat(i.FRAGMENT_SHADER,i.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let c=t.precision!==void 0?t.precision:"highp";const d=l(c);d!==c&&(console.warn("THREE.WebGLRenderer:",c,"not supported, using",d,"instead."),c=d);const h=t.logarithmicDepthBuffer===!0,f=t.reversedDepthBuffer===!0&&e.has("EXT_clip_control"),m=i.getParameter(i.MAX_TEXTURE_IMAGE_UNITS),_=i.getParameter(i.MAX_VERTEX_TEXTURE_IMAGE_UNITS),x=i.getParameter(i.MAX_TEXTURE_SIZE),p=i.getParameter(i.MAX_CUBE_MAP_TEXTURE_SIZE),u=i.getParameter(i.MAX_VERTEX_ATTRIBS),b=i.getParameter(i.MAX_VERTEX_UNIFORM_VECTORS),A=i.getParameter(i.MAX_VARYING_VECTORS),E=i.getParameter(i.MAX_FRAGMENT_UNIFORM_VECTORS),C=_>0,R=i.getParameter(i.MAX_SAMPLES);return{isWebGL2:!0,getMaxAnisotropy:s,getMaxPrecision:l,textureFormatReadable:a,textureTypeReadable:o,precision:c,logarithmicDepthBuffer:h,reversedDepthBuffer:f,maxTextures:m,maxVertexTextures:_,maxTextureSize:x,maxCubemapSize:p,maxAttributes:u,maxVertexUniforms:b,maxVaryings:A,maxFragmentUniforms:E,vertexTextures:C,maxSamples:R}}function dd(i){const e=this;let t=null,n=0,r=!1,s=!1;const a=new Tn,o=new Ie,l={value:null,needsUpdate:!1};this.uniform=l,this.numPlanes=0,this.numIntersection=0,this.init=function(h,f){const m=h.length!==0||f||n!==0||r;return r=f,n=h.length,m},this.beginShadows=function(){s=!0,d(null)},this.endShadows=function(){s=!1},this.setGlobalState=function(h,f){t=d(h,f,0)},this.setState=function(h,f,m){const _=h.clippingPlanes,x=h.clipIntersection,p=h.clipShadows,u=i.get(h);if(!r||_===null||_.length===0||s&&!p)s?d(null):c();else{const b=s?0:n,A=b*4;let E=u.clippingState||null;l.value=E,E=d(_,f,A,m);for(let C=0;C!==A;++C)E[C]=t[C];u.clippingState=E,this.numIntersection=x?this.numPlanes:0,this.numPlanes+=b}};function c(){l.value!==t&&(l.value=t,l.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function d(h,f,m,_){const x=h!==null?h.length:0;let p=null;if(x!==0){if(p=l.value,_!==!0||p===null){const u=m+x*4,b=f.matrixWorldInverse;o.getNormalMatrix(b),(p===null||p.length0){const c=new cl(l.height);return c.fromEquirectangularTexture(i,a),e.set(a,c),a.addEventListener("dispose",r),t(c.texture,a.mapping)}else return null}}return a}function r(a){const o=a.target;o.removeEventListener("dispose",r);const l=e.get(o);l!==void 0&&(e.delete(o),l.dispose())}function s(){e=new WeakMap}return{get:n,dispose:s}}const Yn=4,Ga=[.125,.215,.35,.446,.526,.582],wn=20,Wr=new Bo,Va=new Fe;let Xr=null,qr=0,Yr=0,$r=!1;const An=(1+Math.sqrt(5))/2,qn=1/An,ka=[new N(-An,qn,0),new N(An,qn,0),new N(-qn,0,An),new N(qn,0,An),new N(0,An,-qn),new N(0,An,qn),new N(-1,1,-1),new N(1,1,-1),new N(-1,1,1),new N(1,1,1)],pd=new N;class Wa{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(e,t=0,n=.1,r=100,s={}){const{size:a=256,position:o=pd}=s;Xr=this._renderer.getRenderTarget(),qr=this._renderer.getActiveCubeFace(),Yr=this._renderer.getActiveMipmapLevel(),$r=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(a);const l=this._allocateTargets();return l.depthBuffer=!0,this._sceneToCubeUV(e,n,r,l,o),t>0&&this._blur(l,0,0,t),this._applyPMREM(l),this._cleanup(l),l}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=Ya(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=qa(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),this._cubemapMaterial!==null&&this._cubemapMaterial.dispose(),this._equirectMaterial!==null&&this._equirectMaterial.dispose()}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){this._blurMaterial!==null&&this._blurMaterial.dispose(),this._pingPongRenderTarget!==null&&this._pingPongRenderTarget.dispose();for(let e=0;e2?C:0,C,C),h.setRenderTarget(r),u&&h.render(p,l),h.render(e,l)}p.geometry.dispose(),p.material.dispose(),h.toneMapping=m,h.autoClear=f,e.background=b}_textureToCubeUV(e,t){const n=this._renderer,r=e.mapping===jn||e.mapping===Jn;r?(this._cubemapMaterial===null&&(this._cubemapMaterial=Ya()),this._cubemapMaterial.uniforms.flipEnvMap.value=e.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=qa());const s=r?this._cubemapMaterial:this._equirectMaterial,a=new Et(this._lodPlanes[0],s),o=s.uniforms;o.envMap.value=e;const l=this._cubeSize;ji(t,0,0,3*l,2*l),n.setRenderTarget(t),n.render(a,Wr)}_applyPMREM(e){const t=this._renderer,n=t.autoClear;t.autoClear=!1;const r=this._lodPlanes.length;for(let s=1;swn&&console.warn(`sigmaRadians, ${s}, is too large and will clip, as it requested ${p} samples when the maximum is set to ${wn}`);const u=[];let b=0;for(let w=0;wA-Yn?r-A+Yn:0),R=4*(this._cubeSize-E);ji(t,C,R,3*E,2*E),l.setRenderTarget(t),l.render(h,Wr)}}function md(i){const e=[],t=[],n=[];let r=i;const s=i-Yn+1+Ga.length;for(let a=0;ai-Yn?l=Ga[a-i+Yn-1]:a===0&&(l=0),n.push(l);const c=1/(o-2),d=-c,h=1+c,f=[d,d,h,d,h,h,d,d,h,h,d,h],m=6,_=6,x=3,p=2,u=1,b=new Float32Array(x*_*m),A=new Float32Array(p*_*m),E=new Float32Array(u*_*m);for(let R=0;R2?0:-1,S=[w,U,0,w+2/3,U,0,w+2/3,U+1,0,w,U,0,w+2/3,U+1,0,w,U+1,0];b.set(S,x*_*R),A.set(f,p*_*R);const M=[R,R,R,R,R,R];E.set(M,u*_*R)}const C=new Nt;C.setAttribute("position",new qt(b,x)),C.setAttribute("uv",new qt(A,p)),C.setAttribute("faceIndex",new qt(E,u)),e.push(C),r>Yn&&r--}return{lodPlanes:e,sizeLods:t,sigmas:n}}function Xa(i,e,t){const n=new Dn(i,e,t);return n.texture.mapping=dr,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function ji(i,e,t,n,r){i.viewport.set(e,t,n,r),i.scissor.set(e,t,n,r)}function gd(i,e,t){const n=new Float32Array(wn),r=new N(0,1,0);return new mn({name:"SphericalGaussianBlur",defines:{n:wn,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP:`${i}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:r}},vertexShader:ta(),fragmentShader:` + + precision mediump float; + precision mediump int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + uniform int samples; + uniform float weights[ n ]; + uniform bool latitudinal; + uniform float dTheta; + uniform float mipInt; + uniform vec3 poleAxis; + + #define ENVMAP_TYPE_CUBE_UV + #include + + vec3 getSample( float theta, vec3 axis ) { + + float cosTheta = cos( theta ); + // Rodrigues' axis-angle rotation + vec3 sampleDirection = vOutputDirection * cosTheta + + cross( axis, vOutputDirection ) * sin( theta ) + + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); + + return bilinearCubeUV( envMap, sampleDirection, mipInt ); + + } + + void main() { + + vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); + + if ( all( equal( axis, vec3( 0.0 ) ) ) ) { + + axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); + + } + + axis = normalize( axis ); + + gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); + + for ( int i = 1; i < n; i++ ) { + + if ( i >= samples ) { + + break; + + } + + float theta = dTheta * float( i ); + gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); + gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); + + } + + } + `,blending:dn,depthTest:!1,depthWrite:!1})}function qa(){return new mn({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:ta(),fragmentShader:` + + precision mediump float; + precision mediump int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + + #include + + void main() { + + vec3 outputDirection = normalize( vOutputDirection ); + vec2 uv = equirectUv( outputDirection ); + + gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); + + } + `,blending:dn,depthTest:!1,depthWrite:!1})}function Ya(){return new mn({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:ta(),fragmentShader:` + + precision mediump float; + precision mediump int; + + uniform float flipEnvMap; + + varying vec3 vOutputDirection; + + uniform samplerCube envMap; + + void main() { + + gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); + + } + `,blending:dn,depthTest:!1,depthWrite:!1})}function ta(){return` + + precision mediump float; + precision mediump int; + + attribute float faceIndex; + + varying vec3 vOutputDirection; + + // RH coordinate system; PMREM face-indexing convention + vec3 getDirection( vec2 uv, float face ) { + + uv = 2.0 * uv - 1.0; + + vec3 direction = vec3( uv, 1.0 ); + + if ( face == 0.0 ) { + + direction = direction.zyx; // ( 1, v, u ) pos x + + } else if ( face == 1.0 ) { + + direction = direction.xzy; + direction.xz *= -1.0; // ( -u, 1, -v ) pos y + + } else if ( face == 2.0 ) { + + direction.x *= -1.0; // ( -u, v, 1 ) pos z + + } else if ( face == 3.0 ) { + + direction = direction.zyx; + direction.xz *= -1.0; // ( -1, v, -u ) neg x + + } else if ( face == 4.0 ) { + + direction = direction.xzy; + direction.xy *= -1.0; // ( -u, -1, v ) neg y + + } else if ( face == 5.0 ) { + + direction.z *= -1.0; // ( u, v, -1 ) neg z + + } + + return direction; + + } + + void main() { + + vOutputDirection = getDirection( uv, faceIndex ); + gl_Position = vec4( position, 1.0 ); + + } + `}function _d(i){let e=new WeakMap,t=null;function n(o){if(o&&o.isTexture){const l=o.mapping,c=l===ss||l===as,d=l===jn||l===Jn;if(c||d){let h=e.get(o);const f=h!==void 0?h.texture.pmremVersion:0;if(o.isRenderTargetTexture&&o.pmremVersion!==f)return t===null&&(t=new Wa(i)),h=c?t.fromEquirectangular(o,h):t.fromCubemap(o,h),h.texture.pmremVersion=o.pmremVersion,e.set(o,h),h.texture;if(h!==void 0)return h.texture;{const m=o.image;return c&&m&&m.height>0||d&&m&&r(m)?(t===null&&(t=new Wa(i)),h=c?t.fromEquirectangular(o):t.fromCubemap(o),h.texture.pmremVersion=o.pmremVersion,e.set(o,h),o.addEventListener("dispose",s),h.texture):null}}}return o}function r(o){let l=0;const c=6;for(let d=0;de.maxTextureSize&&(R=Math.ceil(C/e.maxTextureSize),C=e.maxTextureSize);const w=new Float32Array(C*R*4*h),U=new Ro(w,C,R,h);U.type=nn,U.needsUpdate=!0;const S=E*4;for(let P=0;P0)return i;const r=e*t;let s=Ka[r];if(s===void 0&&(s=new Float32Array(r),Ka[r]=s),e!==0){n.toArray(s,0);for(let a=1,o=0;a!==e;++a)o+=t,i[a].toArray(s,o)}return s}function lt(i,e){if(i.length!==e.length)return!1;for(let t=0,n=i.length;t":" "} ${o}: ${t[a]}`)}return n.join(` +`)}const no=new Ie;function vf(i){ke._getMatrix(no,ke.workingColorSpace,i);const e=`mat3( ${no.elements.map(t=>t.toFixed(4))} )`;switch(ke.getTransfer(i)){case sr:return[e,"LinearTransferOETF"];case Ye:return[e,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space: ",i),[e,"LinearTransferOETF"]}}function io(i,e,t){const n=i.getShaderParameter(e,i.COMPILE_STATUS),s=(i.getShaderInfoLog(e)||"").trim();if(n&&s==="")return"";const a=/ERROR: 0:(\d+)/.exec(s);if(a){const o=parseInt(a[1]);return t.toUpperCase()+` + +`+s+` + +`+_f(i.getShaderSource(e),o)}else return s}function xf(i,e){const t=vf(e);return[`vec4 ${i}( vec4 value ) {`,` return ${t[1]}( vec4( value.rgb * ${t[0]}, value.a ) );`,"}"].join(` +`)}function Mf(i,e){let t;switch(e){case xc:t="Linear";break;case Mc:t="Reinhard";break;case Sc:t="Cineon";break;case Ec:t="ACESFilmic";break;case Tc:t="AgX";break;case Ac:t="Neutral";break;case yc:t="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",e),t="Linear"}return"vec3 "+i+"( vec3 color ) { return "+t+"ToneMapping( color ); }"}const Ji=new N;function Sf(){ke.getLuminanceCoefficients(Ji);const i=Ji.x.toFixed(4),e=Ji.y.toFixed(4),t=Ji.z.toFixed(4);return["float luminance( const in vec3 rgb ) {",` const vec3 weights = vec3( ${i}, ${e}, ${t} );`," return dot( weights, rgb );","}"].join(` +`)}function Ef(i){return[i.extensionClipCullDistance?"#extension GL_ANGLE_clip_cull_distance : require":"",i.extensionMultiDraw?"#extension GL_ANGLE_multi_draw : require":""].filter(di).join(` +`)}function yf(i){const e=[];for(const t in i){const n=i[t];n!==!1&&e.push("#define "+t+" "+n)}return e.join(` +`)}function Tf(i,e){const t={},n=i.getProgramParameter(e,i.ACTIVE_ATTRIBUTES);for(let r=0;r/gm;function Hs(i){return i.replace(Af,wf)}const bf=new Map;function wf(i,e){let t=Ne[e];if(t===void 0){const n=bf.get(e);if(n!==void 0)t=Ne[n],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,n);else throw new Error("Can not resolve #include <"+e+">")}return Hs(t)}const Rf=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function ao(i){return i.replace(Rf,Cf)}function Cf(i,e,t,n){let r="";for(let s=parseInt(e);s0&&(p+=` +`),u=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_].filter(di).join(` +`),u.length>0&&(u+=` +`)):(p=[oo(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_,t.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",t.batching?"#define USE_BATCHING":"",t.batchingColor?"#define USE_BATCHING_COLOR":"",t.instancing?"#define USE_INSTANCING":"",t.instancingColor?"#define USE_INSTANCING_COLOR":"",t.instancingMorph?"#define USE_INSTANCING_MORPH":"",t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+d:"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.displacementMap?"#define USE_DISPLACEMENTMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.mapUv?"#define MAP_UV "+t.mapUv:"",t.alphaMapUv?"#define ALPHAMAP_UV "+t.alphaMapUv:"",t.lightMapUv?"#define LIGHTMAP_UV "+t.lightMapUv:"",t.aoMapUv?"#define AOMAP_UV "+t.aoMapUv:"",t.emissiveMapUv?"#define EMISSIVEMAP_UV "+t.emissiveMapUv:"",t.bumpMapUv?"#define BUMPMAP_UV "+t.bumpMapUv:"",t.normalMapUv?"#define NORMALMAP_UV "+t.normalMapUv:"",t.displacementMapUv?"#define DISPLACEMENTMAP_UV "+t.displacementMapUv:"",t.metalnessMapUv?"#define METALNESSMAP_UV "+t.metalnessMapUv:"",t.roughnessMapUv?"#define ROUGHNESSMAP_UV "+t.roughnessMapUv:"",t.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+t.anisotropyMapUv:"",t.clearcoatMapUv?"#define CLEARCOATMAP_UV "+t.clearcoatMapUv:"",t.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+t.clearcoatNormalMapUv:"",t.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+t.clearcoatRoughnessMapUv:"",t.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+t.iridescenceMapUv:"",t.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+t.iridescenceThicknessMapUv:"",t.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+t.sheenColorMapUv:"",t.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+t.sheenRoughnessMapUv:"",t.specularMapUv?"#define SPECULARMAP_UV "+t.specularMapUv:"",t.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+t.specularColorMapUv:"",t.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+t.specularIntensityMapUv:"",t.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+t.transmissionMapUv:"",t.thicknessMapUv?"#define THICKNESSMAP_UV "+t.thicknessMapUv:"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.flatShading?"#define FLAT_SHADED":"",t.skinning?"#define USE_SKINNING":"",t.morphTargets?"#define USE_MORPHTARGETS":"",t.morphNormals&&t.flatShading===!1?"#define USE_MORPHNORMALS":"",t.morphColors?"#define USE_MORPHCOLORS":"",t.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+t.morphTextureStride:"",t.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+t.morphTargetsCount:"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.sizeAttenuation?"#define USE_SIZEATTENUATION":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR"," attribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH"," uniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1"," attribute vec2 uv1;","#endif","#ifdef USE_UV2"," attribute vec2 uv2;","#endif","#ifdef USE_UV3"," attribute vec2 uv3;","#endif","#ifdef USE_TANGENT"," attribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )"," attribute vec4 color;","#elif defined( USE_COLOR )"," attribute vec3 color;","#endif","#ifdef USE_SKINNING"," attribute vec4 skinIndex;"," attribute vec4 skinWeight;","#endif",` +`].filter(di).join(` +`),u=[oo(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_,t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",t.map?"#define USE_MAP":"",t.matcap?"#define USE_MATCAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+c:"",t.envMap?"#define "+d:"",t.envMap?"#define "+h:"",f?"#define CUBEUV_TEXEL_WIDTH "+f.texelWidth:"",f?"#define CUBEUV_TEXEL_HEIGHT "+f.texelHeight:"",f?"#define CUBEUV_MAX_MIP "+f.maxMip+".0":"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoat?"#define USE_CLEARCOAT":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.dispersion?"#define USE_DISPERSION":"",t.iridescence?"#define USE_IRIDESCENCE":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaTest?"#define USE_ALPHATEST":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.sheen?"#define USE_SHEEN":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors||t.instancingColor||t.batchingColor?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.gradientMap?"#define USE_GRADIENTMAP":"",t.flatShading?"#define FLAT_SHADED":"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",t.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",t.toneMapping!==fn?"#define TONE_MAPPING":"",t.toneMapping!==fn?Ne.tonemapping_pars_fragment:"",t.toneMapping!==fn?Mf("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",Ne.colorspace_pars_fragment,xf("linearToOutputTexel",t.outputColorSpace),Sf(),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"",` +`].filter(di).join(` +`)),a=Hs(a),a=ro(a,t),a=so(a,t),o=Hs(o),o=ro(o,t),o=so(o,t),a=ao(a),o=ao(o),t.isRawShaderMaterial!==!0&&(b=`#version 300 es +`,p=[m,"#define attribute in","#define varying out","#define texture2D texture"].join(` +`)+` +`+p,u=["#define varying in",t.glslVersion===pa?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion===pa?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join(` +`)+` +`+u);const A=b+p+a,E=b+u+o,C=to(r,r.VERTEX_SHADER,A),R=to(r,r.FRAGMENT_SHADER,E);r.attachShader(x,C),r.attachShader(x,R),t.index0AttributeName!==void 0?r.bindAttribLocation(x,0,t.index0AttributeName):t.morphTargets===!0&&r.bindAttribLocation(x,0,"position"),r.linkProgram(x);function w(P){if(i.debug.checkShaderErrors){const O=r.getProgramInfoLog(x)||"",H=r.getShaderInfoLog(C)||"",q=r.getShaderInfoLog(R)||"",W=O.trim(),X=H.trim(),Z=q.trim();let G=!0,se=!0;if(r.getProgramParameter(x,r.LINK_STATUS)===!1)if(G=!1,typeof i.debug.onShaderError=="function")i.debug.onShaderError(r,x,C,R);else{const le=io(r,C,"vertex"),Ee=io(r,R,"fragment");console.error("THREE.WebGLProgram: Shader Error "+r.getError()+" - VALIDATE_STATUS "+r.getProgramParameter(x,r.VALIDATE_STATUS)+` + +Material Name: `+P.name+` +Material Type: `+P.type+` + +Program Info Log: `+W+` +`+le+` +`+Ee)}else W!==""?console.warn("THREE.WebGLProgram: Program Info Log:",W):(X===""||Z==="")&&(se=!1);se&&(P.diagnostics={runnable:G,programLog:W,vertexShader:{log:X,prefix:p},fragmentShader:{log:Z,prefix:u}})}r.deleteShader(C),r.deleteShader(R),U=new rr(r,x),S=Tf(r,x)}let U;this.getUniforms=function(){return U===void 0&&w(this),U};let S;this.getAttributes=function(){return S===void 0&&w(this),S};let M=t.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return M===!1&&(M=r.getProgramParameter(x,mf)),M},this.destroy=function(){n.releaseStatesOfProgram(this),r.deleteProgram(x),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=gf++,this.cacheKey=e,this.usedTimes=1,this.program=x,this.vertexShader=C,this.fragmentShader=R,this}let Ff=0;class Of{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(e){const t=e.vertexShader,n=e.fragmentShader,r=this._getShaderStage(t),s=this._getShaderStage(n),a=this._getShaderCacheForMaterial(e);return a.has(r)===!1&&(a.add(r),r.usedTimes++),a.has(s)===!1&&(a.add(s),s.usedTimes++),this}remove(e){const t=this.materialCache.get(e);for(const n of t)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(e),this}getVertexShaderID(e){return this._getShaderStage(e.vertexShader).id}getFragmentShaderID(e){return this._getShaderStage(e.fragmentShader).id}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(e){const t=this.materialCache;let n=t.get(e);return n===void 0&&(n=new Set,t.set(e,n)),n}_getShaderStage(e){const t=this.shaderCache;let n=t.get(e);return n===void 0&&(n=new Bf(e),t.set(e,n)),n}}class Bf{constructor(e){this.id=Ff++,this.code=e,this.usedTimes=0}}function zf(i,e,t,n,r,s,a){const o=new Zs,l=new Of,c=new Set,d=[],h=r.logarithmicDepthBuffer,f=r.vertexTextures;let m=r.precision;const _={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function x(S){return c.add(S),S===0?"uv":`uv${S}`}function p(S,M,P,O,H){const q=O.fog,W=H.geometry,X=S.isMeshStandardMaterial?O.environment:null,Z=(S.isMeshStandardMaterial?t:e).get(S.envMap||X),G=Z&&Z.mapping===dr?Z.image.height:null,se=_[S.type];S.precision!==null&&(m=r.getMaxPrecision(S.precision),m!==S.precision&&console.warn("THREE.WebGLProgram.getParameters:",S.precision,"not supported, using",m,"instead."));const le=W.morphAttributes.position||W.morphAttributes.normal||W.morphAttributes.color,Ee=le!==void 0?le.length:0;let Oe=0;W.morphAttributes.position!==void 0&&(Oe=1),W.morphAttributes.normal!==void 0&&(Oe=2),W.morphAttributes.color!==void 0&&(Oe=3);let Ke,Je,We,Y;if(se){const Xe=Vt[se];Ke=Xe.vertexShader,Je=Xe.fragmentShader}else Ke=S.vertexShader,Je=S.fragmentShader,l.update(S),We=l.getVertexShaderID(S),Y=l.getFragmentShaderID(S);const j=i.getRenderTarget(),de=i.state.buffers.depth.getReversed(),Ce=H.isInstancedMesh===!0,Se=H.isBatchedMesh===!0,He=!!S.map,mt=!!S.matcap,T=!!Z,Qe=!!S.aoMap,De=!!S.lightMap,we=!!S.bumpMap,me=!!S.normalMap,et=!!S.displacementMap,ge=!!S.emissiveMap,Ue=!!S.metalnessMap,ht=!!S.roughnessMap,at=S.anisotropy>0,y=S.clearcoat>0,g=S.dispersion>0,F=S.iridescence>0,k=S.sheen>0,K=S.transmission>0,V=at&&!!S.anisotropyMap,Me=y&&!!S.clearcoatMap,ne=y&&!!S.clearcoatNormalMap,_e=y&&!!S.clearcoatRoughnessMap,ve=F&&!!S.iridescenceMap,ee=F&&!!S.iridescenceThicknessMap,ce=k&&!!S.sheenColorMap,be=k&&!!S.sheenRoughnessMap,xe=!!S.specularMap,ae=!!S.specularColorMap,Le=!!S.specularIntensityMap,D=K&&!!S.transmissionMap,te=K&&!!S.thicknessMap,ie=!!S.gradientMap,he=!!S.alphaMap,J=S.alphaTest>0,$=!!S.alphaHash,pe=!!S.extensions;let Pe=fn;S.toneMapped&&(j===null||j.isXRRenderTarget===!0)&&(Pe=i.toneMapping);const Ze={shaderID:se,shaderType:S.type,shaderName:S.name,vertexShader:Ke,fragmentShader:Je,defines:S.defines,customVertexShaderID:We,customFragmentShaderID:Y,isRawShaderMaterial:S.isRawShaderMaterial===!0,glslVersion:S.glslVersion,precision:m,batching:Se,batchingColor:Se&&H._colorsTexture!==null,instancing:Ce,instancingColor:Ce&&H.instanceColor!==null,instancingMorph:Ce&&H.morphTexture!==null,supportsVertexTextures:f,outputColorSpace:j===null?i.outputColorSpace:j.isXRRenderTarget===!0?j.texture.colorSpace:Qn,alphaToCoverage:!!S.alphaToCoverage,map:He,matcap:mt,envMap:T,envMapMode:T&&Z.mapping,envMapCubeUVHeight:G,aoMap:Qe,lightMap:De,bumpMap:we,normalMap:me,displacementMap:f&&et,emissiveMap:ge,normalMapObjectSpace:me&&S.normalMapType===Cc,normalMapTangentSpace:me&&S.normalMapType===Ao,metalnessMap:Ue,roughnessMap:ht,anisotropy:at,anisotropyMap:V,clearcoat:y,clearcoatMap:Me,clearcoatNormalMap:ne,clearcoatRoughnessMap:_e,dispersion:g,iridescence:F,iridescenceMap:ve,iridescenceThicknessMap:ee,sheen:k,sheenColorMap:ce,sheenRoughnessMap:be,specularMap:xe,specularColorMap:ae,specularIntensityMap:Le,transmission:K,transmissionMap:D,thicknessMap:te,gradientMap:ie,opaque:S.transparent===!1&&S.blending===$n&&S.alphaToCoverage===!1,alphaMap:he,alphaTest:J,alphaHash:$,combine:S.combine,mapUv:He&&x(S.map.channel),aoMapUv:Qe&&x(S.aoMap.channel),lightMapUv:De&&x(S.lightMap.channel),bumpMapUv:we&&x(S.bumpMap.channel),normalMapUv:me&&x(S.normalMap.channel),displacementMapUv:et&&x(S.displacementMap.channel),emissiveMapUv:ge&&x(S.emissiveMap.channel),metalnessMapUv:Ue&&x(S.metalnessMap.channel),roughnessMapUv:ht&&x(S.roughnessMap.channel),anisotropyMapUv:V&&x(S.anisotropyMap.channel),clearcoatMapUv:Me&&x(S.clearcoatMap.channel),clearcoatNormalMapUv:ne&&x(S.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:_e&&x(S.clearcoatRoughnessMap.channel),iridescenceMapUv:ve&&x(S.iridescenceMap.channel),iridescenceThicknessMapUv:ee&&x(S.iridescenceThicknessMap.channel),sheenColorMapUv:ce&&x(S.sheenColorMap.channel),sheenRoughnessMapUv:be&&x(S.sheenRoughnessMap.channel),specularMapUv:xe&&x(S.specularMap.channel),specularColorMapUv:ae&&x(S.specularColorMap.channel),specularIntensityMapUv:Le&&x(S.specularIntensityMap.channel),transmissionMapUv:D&&x(S.transmissionMap.channel),thicknessMapUv:te&&x(S.thicknessMap.channel),alphaMapUv:he&&x(S.alphaMap.channel),vertexTangents:!!W.attributes.tangent&&(me||at),vertexColors:S.vertexColors,vertexAlphas:S.vertexColors===!0&&!!W.attributes.color&&W.attributes.color.itemSize===4,pointsUvs:H.isPoints===!0&&!!W.attributes.uv&&(He||he),fog:!!q,useFog:S.fog===!0,fogExp2:!!q&&q.isFogExp2,flatShading:S.flatShading===!0&&S.wireframe===!1,sizeAttenuation:S.sizeAttenuation===!0,logarithmicDepthBuffer:h,reversedDepthBuffer:de,skinning:H.isSkinnedMesh===!0,morphTargets:W.morphAttributes.position!==void 0,morphNormals:W.morphAttributes.normal!==void 0,morphColors:W.morphAttributes.color!==void 0,morphTargetsCount:Ee,morphTextureStride:Oe,numDirLights:M.directional.length,numPointLights:M.point.length,numSpotLights:M.spot.length,numSpotLightMaps:M.spotLightMap.length,numRectAreaLights:M.rectArea.length,numHemiLights:M.hemi.length,numDirLightShadows:M.directionalShadowMap.length,numPointLightShadows:M.pointShadowMap.length,numSpotLightShadows:M.spotShadowMap.length,numSpotLightShadowsWithMaps:M.numSpotLightShadowsWithMaps,numLightProbes:M.numLightProbes,numClippingPlanes:a.numPlanes,numClipIntersection:a.numIntersection,dithering:S.dithering,shadowMapEnabled:i.shadowMap.enabled&&P.length>0,shadowMapType:i.shadowMap.type,toneMapping:Pe,decodeVideoTexture:He&&S.map.isVideoTexture===!0&&ke.getTransfer(S.map.colorSpace)===Ye,decodeVideoTextureEmissive:ge&&S.emissiveMap.isVideoTexture===!0&&ke.getTransfer(S.emissiveMap.colorSpace)===Ye,premultipliedAlpha:S.premultipliedAlpha,doubleSided:S.side===kt,flipSided:S.side===yt,useDepthPacking:S.depthPacking>=0,depthPacking:S.depthPacking||0,index0AttributeName:S.index0AttributeName,extensionClipCullDistance:pe&&S.extensions.clipCullDistance===!0&&n.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(pe&&S.extensions.multiDraw===!0||Se)&&n.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:n.has("KHR_parallel_shader_compile"),customProgramCacheKey:S.customProgramCacheKey()};return Ze.vertexUv1s=c.has(1),Ze.vertexUv2s=c.has(2),Ze.vertexUv3s=c.has(3),c.clear(),Ze}function u(S){const M=[];if(S.shaderID?M.push(S.shaderID):(M.push(S.customVertexShaderID),M.push(S.customFragmentShaderID)),S.defines!==void 0)for(const P in S.defines)M.push(P),M.push(S.defines[P]);return S.isRawShaderMaterial===!1&&(b(M,S),A(M,S),M.push(i.outputColorSpace)),M.push(S.customProgramCacheKey),M.join()}function b(S,M){S.push(M.precision),S.push(M.outputColorSpace),S.push(M.envMapMode),S.push(M.envMapCubeUVHeight),S.push(M.mapUv),S.push(M.alphaMapUv),S.push(M.lightMapUv),S.push(M.aoMapUv),S.push(M.bumpMapUv),S.push(M.normalMapUv),S.push(M.displacementMapUv),S.push(M.emissiveMapUv),S.push(M.metalnessMapUv),S.push(M.roughnessMapUv),S.push(M.anisotropyMapUv),S.push(M.clearcoatMapUv),S.push(M.clearcoatNormalMapUv),S.push(M.clearcoatRoughnessMapUv),S.push(M.iridescenceMapUv),S.push(M.iridescenceThicknessMapUv),S.push(M.sheenColorMapUv),S.push(M.sheenRoughnessMapUv),S.push(M.specularMapUv),S.push(M.specularColorMapUv),S.push(M.specularIntensityMapUv),S.push(M.transmissionMapUv),S.push(M.thicknessMapUv),S.push(M.combine),S.push(M.fogExp2),S.push(M.sizeAttenuation),S.push(M.morphTargetsCount),S.push(M.morphAttributeCount),S.push(M.numDirLights),S.push(M.numPointLights),S.push(M.numSpotLights),S.push(M.numSpotLightMaps),S.push(M.numHemiLights),S.push(M.numRectAreaLights),S.push(M.numDirLightShadows),S.push(M.numPointLightShadows),S.push(M.numSpotLightShadows),S.push(M.numSpotLightShadowsWithMaps),S.push(M.numLightProbes),S.push(M.shadowMapType),S.push(M.toneMapping),S.push(M.numClippingPlanes),S.push(M.numClipIntersection),S.push(M.depthPacking)}function A(S,M){o.disableAll(),M.supportsVertexTextures&&o.enable(0),M.instancing&&o.enable(1),M.instancingColor&&o.enable(2),M.instancingMorph&&o.enable(3),M.matcap&&o.enable(4),M.envMap&&o.enable(5),M.normalMapObjectSpace&&o.enable(6),M.normalMapTangentSpace&&o.enable(7),M.clearcoat&&o.enable(8),M.iridescence&&o.enable(9),M.alphaTest&&o.enable(10),M.vertexColors&&o.enable(11),M.vertexAlphas&&o.enable(12),M.vertexUv1s&&o.enable(13),M.vertexUv2s&&o.enable(14),M.vertexUv3s&&o.enable(15),M.vertexTangents&&o.enable(16),M.anisotropy&&o.enable(17),M.alphaHash&&o.enable(18),M.batching&&o.enable(19),M.dispersion&&o.enable(20),M.batchingColor&&o.enable(21),M.gradientMap&&o.enable(22),S.push(o.mask),o.disableAll(),M.fog&&o.enable(0),M.useFog&&o.enable(1),M.flatShading&&o.enable(2),M.logarithmicDepthBuffer&&o.enable(3),M.reversedDepthBuffer&&o.enable(4),M.skinning&&o.enable(5),M.morphTargets&&o.enable(6),M.morphNormals&&o.enable(7),M.morphColors&&o.enable(8),M.premultipliedAlpha&&o.enable(9),M.shadowMapEnabled&&o.enable(10),M.doubleSided&&o.enable(11),M.flipSided&&o.enable(12),M.useDepthPacking&&o.enable(13),M.dithering&&o.enable(14),M.transmission&&o.enable(15),M.sheen&&o.enable(16),M.opaque&&o.enable(17),M.pointsUvs&&o.enable(18),M.decodeVideoTexture&&o.enable(19),M.decodeVideoTextureEmissive&&o.enable(20),M.alphaToCoverage&&o.enable(21),S.push(o.mask)}function E(S){const M=_[S.type];let P;if(M){const O=Vt[M];P=rl.clone(O.uniforms)}else P=S.uniforms;return P}function C(S,M){let P;for(let O=0,H=d.length;O0?n.push(u):m.transparent===!0?r.push(u):t.push(u)}function l(h,f,m,_,x,p){const u=a(h,f,m,_,x,p);m.transmission>0?n.unshift(u):m.transparent===!0?r.unshift(u):t.unshift(u)}function c(h,f){t.length>1&&t.sort(h||Gf),n.length>1&&n.sort(f||co),r.length>1&&r.sort(f||co)}function d(){for(let h=e,f=i.length;h=s.length?(a=new lo,s.push(a)):a=s[r],a}function t(){i=new WeakMap}return{get:e,dispose:t}}function kf(){const i={};return{get:function(e){if(i[e.id]!==void 0)return i[e.id];let t;switch(e.type){case"DirectionalLight":t={direction:new N,color:new Fe};break;case"SpotLight":t={position:new N,direction:new N,color:new Fe,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":t={position:new N,color:new Fe,distance:0,decay:0};break;case"HemisphereLight":t={direction:new N,skyColor:new Fe,groundColor:new Fe};break;case"RectAreaLight":t={color:new Fe,position:new N,halfWidth:new N,halfHeight:new N};break}return i[e.id]=t,t}}}function Wf(){const i={};return{get:function(e){if(i[e.id]!==void 0)return i[e.id];let t;switch(e.type){case"DirectionalLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge};break;case"SpotLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge};break;case"PointLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge,shadowCameraNear:1,shadowCameraFar:1e3};break}return i[e.id]=t,t}}}let Xf=0;function qf(i,e){return(e.castShadow?2:0)-(i.castShadow?2:0)+(e.map?1:0)-(i.map?1:0)}function Yf(i){const e=new kf,t=Wf(),n={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let c=0;c<9;c++)n.probe.push(new N);const r=new N,s=new it,a=new it;function o(c){let d=0,h=0,f=0;for(let S=0;S<9;S++)n.probe[S].set(0,0,0);let m=0,_=0,x=0,p=0,u=0,b=0,A=0,E=0,C=0,R=0,w=0;c.sort(qf);for(let S=0,M=c.length;S0&&(i.has("OES_texture_float_linear")===!0?(n.rectAreaLTC1=re.LTC_FLOAT_1,n.rectAreaLTC2=re.LTC_FLOAT_2):(n.rectAreaLTC1=re.LTC_HALF_1,n.rectAreaLTC2=re.LTC_HALF_2)),n.ambient[0]=d,n.ambient[1]=h,n.ambient[2]=f;const U=n.hash;(U.directionalLength!==m||U.pointLength!==_||U.spotLength!==x||U.rectAreaLength!==p||U.hemiLength!==u||U.numDirectionalShadows!==b||U.numPointShadows!==A||U.numSpotShadows!==E||U.numSpotMaps!==C||U.numLightProbes!==w)&&(n.directional.length=m,n.spot.length=x,n.rectArea.length=p,n.point.length=_,n.hemi.length=u,n.directionalShadow.length=b,n.directionalShadowMap.length=b,n.pointShadow.length=A,n.pointShadowMap.length=A,n.spotShadow.length=E,n.spotShadowMap.length=E,n.directionalShadowMatrix.length=b,n.pointShadowMatrix.length=A,n.spotLightMatrix.length=E+C-R,n.spotLightMap.length=C,n.numSpotLightShadowsWithMaps=R,n.numLightProbes=w,U.directionalLength=m,U.pointLength=_,U.spotLength=x,U.rectAreaLength=p,U.hemiLength=u,U.numDirectionalShadows=b,U.numPointShadows=A,U.numSpotShadows=E,U.numSpotMaps=C,U.numLightProbes=w,n.version=Xf++)}function l(c,d){let h=0,f=0,m=0,_=0,x=0;const p=d.matrixWorldInverse;for(let u=0,b=c.length;u=a.length?(o=new uo(i),a.push(o)):o=a[s],o}function n(){e=new WeakMap}return{get:t,dispose:n}}const Kf=`void main() { + gl_Position = vec4( position, 1.0 ); +}`,Zf=`uniform sampler2D shadow_pass; +uniform vec2 resolution; +uniform float radius; +#include +void main() { + const float samples = float( VSM_SAMPLES ); + float mean = 0.0; + float squared_mean = 0.0; + float uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 ); + float uvStart = samples <= 1.0 ? 0.0 : - 1.0; + for ( float i = 0.0; i < samples; i ++ ) { + float uvOffset = uvStart + i * uvStride; + #ifdef HORIZONTAL_PASS + vec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) ); + mean += distribution.x; + squared_mean += distribution.y * distribution.y + distribution.x * distribution.x; + #else + float depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) ); + mean += depth; + squared_mean += depth * depth; + #endif + } + mean = mean / samples; + squared_mean = squared_mean / samples; + float std_dev = sqrt( squared_mean - mean * mean ); + gl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) ); +}`;function jf(i,e,t){let n=new js;const r=new Ge,s=new Ge,a=new st,o=new _l({depthPacking:Rc}),l=new vl,c={},d=t.maxTextureSize,h={[pn]:yt,[yt]:pn,[kt]:kt},f=new mn({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new Ge},radius:{value:4}},vertexShader:Kf,fragmentShader:Zf}),m=f.clone();m.defines.HORIZONTAL_PASS=1;const _=new Nt;_.setAttribute("position",new qt(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const x=new Et(_,f),p=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=po;let u=this.type;this.render=function(R,w,U){if(p.enabled===!1||p.autoUpdate===!1&&p.needsUpdate===!1||R.length===0)return;const S=i.getRenderTarget(),M=i.getActiveCubeFace(),P=i.getActiveMipmapLevel(),O=i.state;O.setBlending(dn),O.buffers.depth.getReversed()===!0?O.buffers.color.setClear(0,0,0,0):O.buffers.color.setClear(1,1,1,1),O.buffers.depth.setTest(!0),O.setScissorTest(!1);const H=u!==tn&&this.type===tn,q=u===tn&&this.type!==tn;for(let W=0,X=R.length;Wd||r.y>d)&&(r.x>d&&(s.x=Math.floor(d/se.x),r.x=s.x*se.x,G.mapSize.x=s.x),r.y>d&&(s.y=Math.floor(d/se.y),r.y=s.y*se.y,G.mapSize.y=s.y)),G.map===null||H===!0||q===!0){const Ee=this.type!==tn?{minFilter:Ht,magFilter:Ht}:{};G.map!==null&&G.map.dispose(),G.map=new Dn(r.x,r.y,Ee),G.map.texture.name=Z.name+".shadowMap",G.camera.updateProjectionMatrix()}i.setRenderTarget(G.map),i.clear();const le=G.getViewportCount();for(let Ee=0;Ee0||w.map&&w.alphaTest>0||w.alphaToCoverage===!0){const O=M.uuid,H=w.uuid;let q=c[O];q===void 0&&(q={},c[O]=q);let W=q[H];W===void 0&&(W=M.clone(),q[H]=W,w.addEventListener("dispose",C)),M=W}if(M.visible=w.visible,M.wireframe=w.wireframe,S===tn?M.side=w.shadowSide!==null?w.shadowSide:w.side:M.side=w.shadowSide!==null?w.shadowSide:h[w.side],M.alphaMap=w.alphaMap,M.alphaTest=w.alphaToCoverage===!0?.5:w.alphaTest,M.map=w.map,M.clipShadows=w.clipShadows,M.clippingPlanes=w.clippingPlanes,M.clipIntersection=w.clipIntersection,M.displacementMap=w.displacementMap,M.displacementScale=w.displacementScale,M.displacementBias=w.displacementBias,M.wireframeLinewidth=w.wireframeLinewidth,M.linewidth=w.linewidth,U.isPointLight===!0&&M.isMeshDistanceMaterial===!0){const O=i.properties.get(M);O.light=U}return M}function E(R,w,U,S,M){if(R.visible===!1)return;if(R.layers.test(w.layers)&&(R.isMesh||R.isLine||R.isPoints)&&(R.castShadow||R.receiveShadow&&M===tn)&&(!R.frustumCulled||n.intersectsObject(R))){R.modelViewMatrix.multiplyMatrices(U.matrixWorldInverse,R.matrixWorld);const H=e.update(R),q=R.material;if(Array.isArray(q)){const W=H.groups;for(let X=0,Z=W.length;X=1):G.indexOf("OpenGL ES")!==-1&&(Z=parseFloat(/^OpenGL ES (\d)/.exec(G)[1]),X=Z>=2);let se=null,le={};const Ee=i.getParameter(i.SCISSOR_BOX),Oe=i.getParameter(i.VIEWPORT),Ke=new st().fromArray(Ee),Je=new st().fromArray(Oe);function We(D,te,ie,he){const J=new Uint8Array(4),$=i.createTexture();i.bindTexture(D,$),i.texParameteri(D,i.TEXTURE_MIN_FILTER,i.NEAREST),i.texParameteri(D,i.TEXTURE_MAG_FILTER,i.NEAREST);for(let pe=0;pe"u"?!1:/OculusBrowser/g.test(navigator.userAgent),c=new Ge,d=new WeakMap;let h;const f=new WeakMap;let m=!1;try{m=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function _(y,g){return m?new OffscreenCanvas(y,g):or("canvas")}function x(y,g,F){let k=1;const K=at(y);if((K.width>F||K.height>F)&&(k=F/Math.max(K.width,K.height)),k<1)if(typeof HTMLImageElement<"u"&&y instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&y instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&y instanceof ImageBitmap||typeof VideoFrame<"u"&&y instanceof VideoFrame){const V=Math.floor(k*K.width),Me=Math.floor(k*K.height);h===void 0&&(h=_(V,Me));const ne=g?_(V,Me):h;return ne.width=V,ne.height=Me,ne.getContext("2d").drawImage(y,0,0,V,Me),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+K.width+"x"+K.height+") to ("+V+"x"+Me+")."),ne}else return"data"in y&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+K.width+"x"+K.height+")."),y;return y}function p(y){return y.generateMipmaps}function u(y){i.generateMipmap(y)}function b(y){return y.isWebGLCubeRenderTarget?i.TEXTURE_CUBE_MAP:y.isWebGL3DRenderTarget?i.TEXTURE_3D:y.isWebGLArrayRenderTarget||y.isCompressedArrayTexture?i.TEXTURE_2D_ARRAY:i.TEXTURE_2D}function A(y,g,F,k,K=!1){if(y!==null){if(i[y]!==void 0)return i[y];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+y+"'")}let V=g;if(g===i.RED&&(F===i.FLOAT&&(V=i.R32F),F===i.HALF_FLOAT&&(V=i.R16F),F===i.UNSIGNED_BYTE&&(V=i.R8)),g===i.RED_INTEGER&&(F===i.UNSIGNED_BYTE&&(V=i.R8UI),F===i.UNSIGNED_SHORT&&(V=i.R16UI),F===i.UNSIGNED_INT&&(V=i.R32UI),F===i.BYTE&&(V=i.R8I),F===i.SHORT&&(V=i.R16I),F===i.INT&&(V=i.R32I)),g===i.RG&&(F===i.FLOAT&&(V=i.RG32F),F===i.HALF_FLOAT&&(V=i.RG16F),F===i.UNSIGNED_BYTE&&(V=i.RG8)),g===i.RG_INTEGER&&(F===i.UNSIGNED_BYTE&&(V=i.RG8UI),F===i.UNSIGNED_SHORT&&(V=i.RG16UI),F===i.UNSIGNED_INT&&(V=i.RG32UI),F===i.BYTE&&(V=i.RG8I),F===i.SHORT&&(V=i.RG16I),F===i.INT&&(V=i.RG32I)),g===i.RGB_INTEGER&&(F===i.UNSIGNED_BYTE&&(V=i.RGB8UI),F===i.UNSIGNED_SHORT&&(V=i.RGB16UI),F===i.UNSIGNED_INT&&(V=i.RGB32UI),F===i.BYTE&&(V=i.RGB8I),F===i.SHORT&&(V=i.RGB16I),F===i.INT&&(V=i.RGB32I)),g===i.RGBA_INTEGER&&(F===i.UNSIGNED_BYTE&&(V=i.RGBA8UI),F===i.UNSIGNED_SHORT&&(V=i.RGBA16UI),F===i.UNSIGNED_INT&&(V=i.RGBA32UI),F===i.BYTE&&(V=i.RGBA8I),F===i.SHORT&&(V=i.RGBA16I),F===i.INT&&(V=i.RGBA32I)),g===i.RGB&&(F===i.UNSIGNED_INT_5_9_9_9_REV&&(V=i.RGB9_E5),F===i.UNSIGNED_INT_10F_11F_11F_REV&&(V=i.R11F_G11F_B10F)),g===i.RGBA){const Me=K?sr:ke.getTransfer(k);F===i.FLOAT&&(V=i.RGBA32F),F===i.HALF_FLOAT&&(V=i.RGBA16F),F===i.UNSIGNED_BYTE&&(V=Me===Ye?i.SRGB8_ALPHA8:i.RGBA8),F===i.UNSIGNED_SHORT_4_4_4_4&&(V=i.RGBA4),F===i.UNSIGNED_SHORT_5_5_5_1&&(V=i.RGB5_A1)}return(V===i.R16F||V===i.R32F||V===i.RG16F||V===i.RG32F||V===i.RGBA16F||V===i.RGBA32F)&&e.get("EXT_color_buffer_float"),V}function E(y,g){let F;return y?g===null||g===Pn||g===mi?F=i.DEPTH24_STENCIL8:g===nn?F=i.DEPTH32F_STENCIL8:g===pi&&(F=i.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):g===null||g===Pn||g===mi?F=i.DEPTH_COMPONENT24:g===nn?F=i.DEPTH_COMPONENT32F:g===pi&&(F=i.DEPTH_COMPONENT16),F}function C(y,g){return p(y)===!0||y.isFramebufferTexture&&y.minFilter!==Ht&&y.minFilter!==Wt?Math.log2(Math.max(g.width,g.height))+1:y.mipmaps!==void 0&&y.mipmaps.length>0?y.mipmaps.length:y.isCompressedTexture&&Array.isArray(y.image)?g.mipmaps.length:1}function R(y){const g=y.target;g.removeEventListener("dispose",R),U(g),g.isVideoTexture&&d.delete(g)}function w(y){const g=y.target;g.removeEventListener("dispose",w),M(g)}function U(y){const g=n.get(y);if(g.__webglInit===void 0)return;const F=y.source,k=f.get(F);if(k){const K=k[g.__cacheKey];K.usedTimes--,K.usedTimes===0&&S(y),Object.keys(k).length===0&&f.delete(F)}n.remove(y)}function S(y){const g=n.get(y);i.deleteTexture(g.__webglTexture);const F=y.source,k=f.get(F);delete k[g.__cacheKey],a.memory.textures--}function M(y){const g=n.get(y);if(y.depthTexture&&(y.depthTexture.dispose(),n.remove(y.depthTexture)),y.isWebGLCubeRenderTarget)for(let k=0;k<6;k++){if(Array.isArray(g.__webglFramebuffer[k]))for(let K=0;K=r.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+y+" texture units while this GPU supports only "+r.maxTextures),P+=1,y}function q(y){const g=[];return g.push(y.wrapS),g.push(y.wrapT),g.push(y.wrapR||0),g.push(y.magFilter),g.push(y.minFilter),g.push(y.anisotropy),g.push(y.internalFormat),g.push(y.format),g.push(y.type),g.push(y.generateMipmaps),g.push(y.premultiplyAlpha),g.push(y.flipY),g.push(y.unpackAlignment),g.push(y.colorSpace),g.join()}function W(y,g){const F=n.get(y);if(y.isVideoTexture&&Ue(y),y.isRenderTargetTexture===!1&&y.isExternalTexture!==!0&&y.version>0&&F.__version!==y.version){const k=y.image;if(k===null)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else if(k.complete===!1)console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete");else{Y(F,y,g);return}}else y.isExternalTexture&&(F.__webglTexture=y.sourceTexture?y.sourceTexture:null);t.bindTexture(i.TEXTURE_2D,F.__webglTexture,i.TEXTURE0+g)}function X(y,g){const F=n.get(y);if(y.isRenderTargetTexture===!1&&y.version>0&&F.__version!==y.version){Y(F,y,g);return}t.bindTexture(i.TEXTURE_2D_ARRAY,F.__webglTexture,i.TEXTURE0+g)}function Z(y,g){const F=n.get(y);if(y.isRenderTargetTexture===!1&&y.version>0&&F.__version!==y.version){Y(F,y,g);return}t.bindTexture(i.TEXTURE_3D,F.__webglTexture,i.TEXTURE0+g)}function G(y,g){const F=n.get(y);if(y.version>0&&F.__version!==y.version){j(F,y,g);return}t.bindTexture(i.TEXTURE_CUBE_MAP,F.__webglTexture,i.TEXTURE0+g)}const se={[os]:i.REPEAT,[Rn]:i.CLAMP_TO_EDGE,[cs]:i.MIRRORED_REPEAT},le={[Ht]:i.NEAREST,[bc]:i.NEAREST_MIPMAP_NEAREST,[wi]:i.NEAREST_MIPMAP_LINEAR,[Wt]:i.LINEAR,[_r]:i.LINEAR_MIPMAP_NEAREST,[Cn]:i.LINEAR_MIPMAP_LINEAR},Ee={[Pc]:i.NEVER,[Fc]:i.ALWAYS,[Dc]:i.LESS,[bo]:i.LEQUAL,[Lc]:i.EQUAL,[Nc]:i.GEQUAL,[Ic]:i.GREATER,[Uc]:i.NOTEQUAL};function Oe(y,g){if(g.type===nn&&e.has("OES_texture_float_linear")===!1&&(g.magFilter===Wt||g.magFilter===_r||g.magFilter===wi||g.magFilter===Cn||g.minFilter===Wt||g.minFilter===_r||g.minFilter===wi||g.minFilter===Cn)&&console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),i.texParameteri(y,i.TEXTURE_WRAP_S,se[g.wrapS]),i.texParameteri(y,i.TEXTURE_WRAP_T,se[g.wrapT]),(y===i.TEXTURE_3D||y===i.TEXTURE_2D_ARRAY)&&i.texParameteri(y,i.TEXTURE_WRAP_R,se[g.wrapR]),i.texParameteri(y,i.TEXTURE_MAG_FILTER,le[g.magFilter]),i.texParameteri(y,i.TEXTURE_MIN_FILTER,le[g.minFilter]),g.compareFunction&&(i.texParameteri(y,i.TEXTURE_COMPARE_MODE,i.COMPARE_REF_TO_TEXTURE),i.texParameteri(y,i.TEXTURE_COMPARE_FUNC,Ee[g.compareFunction])),e.has("EXT_texture_filter_anisotropic")===!0){if(g.magFilter===Ht||g.minFilter!==wi&&g.minFilter!==Cn||g.type===nn&&e.has("OES_texture_float_linear")===!1)return;if(g.anisotropy>1||n.get(g).__currentAnisotropy){const F=e.get("EXT_texture_filter_anisotropic");i.texParameterf(y,F.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(g.anisotropy,r.getMaxAnisotropy())),n.get(g).__currentAnisotropy=g.anisotropy}}}function Ke(y,g){let F=!1;y.__webglInit===void 0&&(y.__webglInit=!0,g.addEventListener("dispose",R));const k=g.source;let K=f.get(k);K===void 0&&(K={},f.set(k,K));const V=q(g);if(V!==y.__cacheKey){K[V]===void 0&&(K[V]={texture:i.createTexture(),usedTimes:0},a.memory.textures++,F=!0),K[V].usedTimes++;const Me=K[y.__cacheKey];Me!==void 0&&(K[y.__cacheKey].usedTimes--,Me.usedTimes===0&&S(g)),y.__cacheKey=V,y.__webglTexture=K[V].texture}return F}function Je(y,g,F){return Math.floor(Math.floor(y/F)/g)}function We(y,g,F,k){const V=y.updateRanges;if(V.length===0)t.texSubImage2D(i.TEXTURE_2D,0,0,0,g.width,g.height,F,k,g.data);else{V.sort((ee,ce)=>ee.start-ce.start);let Me=0;for(let ee=1;ee0){D&&te&&t.texStorage2D(i.TEXTURE_2D,he,xe,Le[0].width,Le[0].height);for(let J=0,$=Le.length;J<$;J++)ae=Le[J],D?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,ce,be,ae.data):t.texImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,ce,be,ae.data);g.generateMipmaps=!1}else D?(te&&t.texStorage2D(i.TEXTURE_2D,he,xe,ee.width,ee.height),ie&&We(g,ee,ce,be)):t.texImage2D(i.TEXTURE_2D,0,xe,ee.width,ee.height,0,ce,be,ee.data);else if(g.isCompressedTexture)if(g.isCompressedArrayTexture){D&&te&&t.texStorage3D(i.TEXTURE_2D_ARRAY,he,xe,Le[0].width,Le[0].height,ee.depth);for(let J=0,$=Le.length;J<$;J++)if(ae=Le[J],g.format!==zt)if(ce!==null)if(D){if(ie)if(g.layerUpdates.size>0){const pe=Ha(ae.width,ae.height,g.format,g.type);for(const Pe of g.layerUpdates){const Ze=ae.data.subarray(Pe*pe/ae.data.BYTES_PER_ELEMENT,(Pe+1)*pe/ae.data.BYTES_PER_ELEMENT);t.compressedTexSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,Pe,ae.width,ae.height,1,ce,Ze)}g.clearLayerUpdates()}else t.compressedTexSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,0,ae.width,ae.height,ee.depth,ce,ae.data)}else t.compressedTexImage3D(i.TEXTURE_2D_ARRAY,J,xe,ae.width,ae.height,ee.depth,0,ae.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else D?ie&&t.texSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,0,ae.width,ae.height,ee.depth,ce,be,ae.data):t.texImage3D(i.TEXTURE_2D_ARRAY,J,xe,ae.width,ae.height,ee.depth,0,ce,be,ae.data)}else{D&&te&&t.texStorage2D(i.TEXTURE_2D,he,xe,Le[0].width,Le[0].height);for(let J=0,$=Le.length;J<$;J++)ae=Le[J],g.format!==zt?ce!==null?D?ie&&t.compressedTexSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,ce,ae.data):t.compressedTexImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,ae.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):D?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,ce,be,ae.data):t.texImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,ce,be,ae.data)}else if(g.isDataArrayTexture)if(D){if(te&&t.texStorage3D(i.TEXTURE_2D_ARRAY,he,xe,ee.width,ee.height,ee.depth),ie)if(g.layerUpdates.size>0){const J=Ha(ee.width,ee.height,g.format,g.type);for(const $ of g.layerUpdates){const pe=ee.data.subarray($*J/ee.data.BYTES_PER_ELEMENT,($+1)*J/ee.data.BYTES_PER_ELEMENT);t.texSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,$,ee.width,ee.height,1,ce,be,pe)}g.clearLayerUpdates()}else t.texSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,0,ee.width,ee.height,ee.depth,ce,be,ee.data)}else t.texImage3D(i.TEXTURE_2D_ARRAY,0,xe,ee.width,ee.height,ee.depth,0,ce,be,ee.data);else if(g.isData3DTexture)D?(te&&t.texStorage3D(i.TEXTURE_3D,he,xe,ee.width,ee.height,ee.depth),ie&&t.texSubImage3D(i.TEXTURE_3D,0,0,0,0,ee.width,ee.height,ee.depth,ce,be,ee.data)):t.texImage3D(i.TEXTURE_3D,0,xe,ee.width,ee.height,ee.depth,0,ce,be,ee.data);else if(g.isFramebufferTexture){if(te)if(D)t.texStorage2D(i.TEXTURE_2D,he,xe,ee.width,ee.height);else{let J=ee.width,$=ee.height;for(let pe=0;pe>=1,$>>=1}}else if(Le.length>0){if(D&&te){const J=at(Le[0]);t.texStorage2D(i.TEXTURE_2D,he,xe,J.width,J.height)}for(let J=0,$=Le.length;J<$;J++)ae=Le[J],D?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,ce,be,ae):t.texImage2D(i.TEXTURE_2D,J,xe,ce,be,ae);g.generateMipmaps=!1}else if(D){if(te){const J=at(ee);t.texStorage2D(i.TEXTURE_2D,he,xe,J.width,J.height)}ie&&t.texSubImage2D(i.TEXTURE_2D,0,0,0,ce,be,ee)}else t.texImage2D(i.TEXTURE_2D,0,xe,ce,be,ee);p(g)&&u(k),Me.__version=V.version,g.onUpdate&&g.onUpdate(g)}y.__version=g.version}function j(y,g,F){if(g.image.length!==6)return;const k=Ke(y,g),K=g.source;t.bindTexture(i.TEXTURE_CUBE_MAP,y.__webglTexture,i.TEXTURE0+F);const V=n.get(K);if(K.version!==V.__version||k===!0){t.activeTexture(i.TEXTURE0+F);const Me=ke.getPrimaries(ke.workingColorSpace),ne=g.colorSpace===hn?null:ke.getPrimaries(g.colorSpace),_e=g.colorSpace===hn||Me===ne?i.NONE:i.BROWSER_DEFAULT_WEBGL;i.pixelStorei(i.UNPACK_FLIP_Y_WEBGL,g.flipY),i.pixelStorei(i.UNPACK_PREMULTIPLY_ALPHA_WEBGL,g.premultiplyAlpha),i.pixelStorei(i.UNPACK_ALIGNMENT,g.unpackAlignment),i.pixelStorei(i.UNPACK_COLORSPACE_CONVERSION_WEBGL,_e);const ve=g.isCompressedTexture||g.image[0].isCompressedTexture,ee=g.image[0]&&g.image[0].isDataTexture,ce=[];for(let $=0;$<6;$++)!ve&&!ee?ce[$]=x(g.image[$],!0,r.maxCubemapSize):ce[$]=ee?g.image[$].image:g.image[$],ce[$]=ht(g,ce[$]);const be=ce[0],xe=s.convert(g.format,g.colorSpace),ae=s.convert(g.type),Le=A(g.internalFormat,xe,ae,g.colorSpace),D=g.isVideoTexture!==!0,te=V.__version===void 0||k===!0,ie=K.dataReady;let he=C(g,be);Oe(i.TEXTURE_CUBE_MAP,g);let J;if(ve){D&&te&&t.texStorage2D(i.TEXTURE_CUBE_MAP,he,Le,be.width,be.height);for(let $=0;$<6;$++){J=ce[$].mipmaps;for(let pe=0;pe0&&he++;const $=at(ce[0]);t.texStorage2D(i.TEXTURE_CUBE_MAP,he,Le,$.width,$.height)}for(let $=0;$<6;$++)if(ee){D?ie&&t.texSubImage2D(i.TEXTURE_CUBE_MAP_POSITIVE_X+$,0,0,0,ce[$].width,ce[$].height,xe,ae,ce[$].data):t.texImage2D(i.TEXTURE_CUBE_MAP_POSITIVE_X+$,0,Le,ce[$].width,ce[$].height,0,xe,ae,ce[$].data);for(let pe=0;pe>V),be=Math.max(1,g.height>>V);K===i.TEXTURE_3D||K===i.TEXTURE_2D_ARRAY?t.texImage3D(K,V,_e,ce,be,g.depth,0,Me,ne,null):t.texImage2D(K,V,_e,ce,be,0,Me,ne,null)}t.bindFramebuffer(i.FRAMEBUFFER,y),ge(g)?o.framebufferTexture2DMultisampleEXT(i.FRAMEBUFFER,k,K,ee.__webglTexture,0,et(g)):(K===i.TEXTURE_2D||K>=i.TEXTURE_CUBE_MAP_POSITIVE_X&&K<=i.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&i.framebufferTexture2D(i.FRAMEBUFFER,k,K,ee.__webglTexture,V),t.bindFramebuffer(i.FRAMEBUFFER,null)}function Ce(y,g,F){if(i.bindRenderbuffer(i.RENDERBUFFER,y),g.depthBuffer){const k=g.depthTexture,K=k&&k.isDepthTexture?k.type:null,V=E(g.stencilBuffer,K),Me=g.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,ne=et(g);ge(g)?o.renderbufferStorageMultisampleEXT(i.RENDERBUFFER,ne,V,g.width,g.height):F?i.renderbufferStorageMultisample(i.RENDERBUFFER,ne,V,g.width,g.height):i.renderbufferStorage(i.RENDERBUFFER,V,g.width,g.height),i.framebufferRenderbuffer(i.FRAMEBUFFER,Me,i.RENDERBUFFER,y)}else{const k=g.textures;for(let K=0;K{delete g.__boundDepthTexture,delete g.__depthDisposeCallback,k.removeEventListener("dispose",K)};k.addEventListener("dispose",K),g.__depthDisposeCallback=K}g.__boundDepthTexture=k}if(y.depthTexture&&!g.__autoAllocateDepthBuffer){if(F)throw new Error("target.depthTexture not supported in Cube render targets");const k=y.texture.mipmaps;k&&k.length>0?Se(g.__webglFramebuffer[0],y):Se(g.__webglFramebuffer,y)}else if(F){g.__webglDepthbuffer=[];for(let k=0;k<6;k++)if(t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer[k]),g.__webglDepthbuffer[k]===void 0)g.__webglDepthbuffer[k]=i.createRenderbuffer(),Ce(g.__webglDepthbuffer[k],y,!1);else{const K=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,V=g.__webglDepthbuffer[k];i.bindRenderbuffer(i.RENDERBUFFER,V),i.framebufferRenderbuffer(i.FRAMEBUFFER,K,i.RENDERBUFFER,V)}}else{const k=y.texture.mipmaps;if(k&&k.length>0?t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer[0]):t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer),g.__webglDepthbuffer===void 0)g.__webglDepthbuffer=i.createRenderbuffer(),Ce(g.__webglDepthbuffer,y,!1);else{const K=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,V=g.__webglDepthbuffer;i.bindRenderbuffer(i.RENDERBUFFER,V),i.framebufferRenderbuffer(i.FRAMEBUFFER,K,i.RENDERBUFFER,V)}}t.bindFramebuffer(i.FRAMEBUFFER,null)}function mt(y,g,F){const k=n.get(y);g!==void 0&&de(k.__webglFramebuffer,y,y.texture,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,0),F!==void 0&&He(y)}function T(y){const g=y.texture,F=n.get(y),k=n.get(g);y.addEventListener("dispose",w);const K=y.textures,V=y.isWebGLCubeRenderTarget===!0,Me=K.length>1;if(Me||(k.__webglTexture===void 0&&(k.__webglTexture=i.createTexture()),k.__version=g.version,a.memory.textures++),V){F.__webglFramebuffer=[];for(let ne=0;ne<6;ne++)if(g.mipmaps&&g.mipmaps.length>0){F.__webglFramebuffer[ne]=[];for(let _e=0;_e0){F.__webglFramebuffer=[];for(let ne=0;ne0&&ge(y)===!1){F.__webglMultisampledFramebuffer=i.createFramebuffer(),F.__webglColorRenderbuffer=[],t.bindFramebuffer(i.FRAMEBUFFER,F.__webglMultisampledFramebuffer);for(let ne=0;ne0)for(let _e=0;_e0)for(let _e=0;_e0){if(ge(y)===!1){const g=y.textures,F=y.width,k=y.height;let K=i.COLOR_BUFFER_BIT;const V=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,Me=n.get(y),ne=g.length>1;if(ne)for(let ve=0;ve0?t.bindFramebuffer(i.DRAW_FRAMEBUFFER,Me.__webglFramebuffer[0]):t.bindFramebuffer(i.DRAW_FRAMEBUFFER,Me.__webglFramebuffer);for(let ve=0;ve0&&e.has("WEBGL_multisampled_render_to_texture")===!0&&g.__useRenderToTexture!==!1}function Ue(y){const g=a.render.frame;d.get(y)!==g&&(d.set(y,g),y.update())}function ht(y,g){const F=y.colorSpace,k=y.format,K=y.type;return y.isCompressedTexture===!0||y.isVideoTexture===!0||F!==Qn&&F!==hn&&(ke.getTransfer(F)===Ye?(k!==zt||K!==Yt)&&console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",F)),g}function at(y){return typeof HTMLImageElement<"u"&&y instanceof HTMLImageElement?(c.width=y.naturalWidth||y.width,c.height=y.naturalHeight||y.height):typeof VideoFrame<"u"&&y instanceof VideoFrame?(c.width=y.displayWidth,c.height=y.displayHeight):(c.width=y.width,c.height=y.height),c}this.allocateTextureUnit=H,this.resetTextureUnits=O,this.setTexture2D=W,this.setTexture2DArray=X,this.setTexture3D=Z,this.setTextureCube=G,this.rebindTextures=mt,this.setupRenderTarget=T,this.updateRenderTargetMipmap=Qe,this.updateMultisampleRenderTarget=me,this.setupDepthRenderbuffer=He,this.setupFrameBufferTexture=de,this.useMultisampledRTT=ge}function tp(i,e){function t(n,r=hn){let s;const a=ke.getTransfer(r);if(n===Yt)return i.UNSIGNED_BYTE;if(n===ks)return i.UNSIGNED_SHORT_4_4_4_4;if(n===Ws)return i.UNSIGNED_SHORT_5_5_5_1;if(n===xo)return i.UNSIGNED_INT_5_9_9_9_REV;if(n===Mo)return i.UNSIGNED_INT_10F_11F_11F_REV;if(n===_o)return i.BYTE;if(n===vo)return i.SHORT;if(n===pi)return i.UNSIGNED_SHORT;if(n===Vs)return i.INT;if(n===Pn)return i.UNSIGNED_INT;if(n===nn)return i.FLOAT;if(n===xi)return i.HALF_FLOAT;if(n===So)return i.ALPHA;if(n===Eo)return i.RGB;if(n===zt)return i.RGBA;if(n===gi)return i.DEPTH_COMPONENT;if(n===_i)return i.DEPTH_STENCIL;if(n===yo)return i.RED;if(n===Xs)return i.RED_INTEGER;if(n===To)return i.RG;if(n===qs)return i.RG_INTEGER;if(n===Ys)return i.RGBA_INTEGER;if(n===Qi||n===er||n===tr||n===nr)if(a===Ye)if(s=e.get("WEBGL_compressed_texture_s3tc_srgb"),s!==null){if(n===Qi)return s.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(n===er)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(n===tr)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(n===nr)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(s=e.get("WEBGL_compressed_texture_s3tc"),s!==null){if(n===Qi)return s.COMPRESSED_RGB_S3TC_DXT1_EXT;if(n===er)return s.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(n===tr)return s.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(n===nr)return s.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(n===ls||n===us||n===hs||n===ds)if(s=e.get("WEBGL_compressed_texture_pvrtc"),s!==null){if(n===ls)return s.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(n===us)return s.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(n===hs)return s.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(n===ds)return s.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(n===fs||n===ps||n===ms)if(s=e.get("WEBGL_compressed_texture_etc"),s!==null){if(n===fs||n===ps)return a===Ye?s.COMPRESSED_SRGB8_ETC2:s.COMPRESSED_RGB8_ETC2;if(n===ms)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:s.COMPRESSED_RGBA8_ETC2_EAC}else return null;if(n===gs||n===_s||n===vs||n===xs||n===Ms||n===Ss||n===Es||n===ys||n===Ts||n===As||n===bs||n===ws||n===Rs||n===Cs)if(s=e.get("WEBGL_compressed_texture_astc"),s!==null){if(n===gs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:s.COMPRESSED_RGBA_ASTC_4x4_KHR;if(n===_s)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:s.COMPRESSED_RGBA_ASTC_5x4_KHR;if(n===vs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:s.COMPRESSED_RGBA_ASTC_5x5_KHR;if(n===xs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:s.COMPRESSED_RGBA_ASTC_6x5_KHR;if(n===Ms)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:s.COMPRESSED_RGBA_ASTC_6x6_KHR;if(n===Ss)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:s.COMPRESSED_RGBA_ASTC_8x5_KHR;if(n===Es)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:s.COMPRESSED_RGBA_ASTC_8x6_KHR;if(n===ys)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:s.COMPRESSED_RGBA_ASTC_8x8_KHR;if(n===Ts)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:s.COMPRESSED_RGBA_ASTC_10x5_KHR;if(n===As)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:s.COMPRESSED_RGBA_ASTC_10x6_KHR;if(n===bs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:s.COMPRESSED_RGBA_ASTC_10x8_KHR;if(n===ws)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:s.COMPRESSED_RGBA_ASTC_10x10_KHR;if(n===Rs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:s.COMPRESSED_RGBA_ASTC_12x10_KHR;if(n===Cs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:s.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(n===Ps||n===Ds||n===Ls)if(s=e.get("EXT_texture_compression_bptc"),s!==null){if(n===Ps)return a===Ye?s.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:s.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(n===Ds)return s.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(n===Ls)return s.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(n===Is||n===Us||n===Ns||n===Fs)if(s=e.get("EXT_texture_compression_rgtc"),s!==null){if(n===Is)return s.COMPRESSED_RED_RGTC1_EXT;if(n===Us)return s.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(n===Ns)return s.COMPRESSED_RED_GREEN_RGTC2_EXT;if(n===Fs)return s.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return n===mi?i.UNSIGNED_INT_24_8:i[n]!==void 0?i[n]:null}return{convert:t}}const np=` +void main() { + + gl_Position = vec4( position, 1.0 ); + +}`,ip=` +uniform sampler2DArray depthColor; +uniform float depthWidth; +uniform float depthHeight; + +void main() { + + vec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight ); + + if ( coord.x >= 1.0 ) { + + gl_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r; + + } else { + + gl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r; + + } + +}`;class rp{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t){if(this.texture===null){const n=new Oo(e.texture);(e.depthNear!==t.depthNear||e.depthFar!==t.depthFar)&&(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=n}}getMesh(e){if(this.texture!==null&&this.mesh===null){const t=e.cameras[0].viewport,n=new mn({vertexShader:np,fragmentShader:ip,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new Et(new Ti(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class sp extends ti{constructor(e,t){super();const n=this;let r=null,s=1,a=null,o="local-floor",l=1,c=null,d=null,h=null,f=null,m=null,_=null;const x=typeof XRWebGLBinding<"u",p=new rp,u={},b=t.getContextAttributes();let A=null,E=null;const C=[],R=[],w=new Ge;let U=null;const S=new It;S.viewport=new st;const M=new It;M.viewport=new st;const P=[S,M],O=new Tl;let H=null,q=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(Y){let j=C[Y];return j===void 0&&(j=new zr,C[Y]=j),j.getTargetRaySpace()},this.getControllerGrip=function(Y){let j=C[Y];return j===void 0&&(j=new zr,C[Y]=j),j.getGripSpace()},this.getHand=function(Y){let j=C[Y];return j===void 0&&(j=new zr,C[Y]=j),j.getHandSpace()};function W(Y){const j=R.indexOf(Y.inputSource);if(j===-1)return;const de=C[j];de!==void 0&&(de.update(Y.inputSource,Y.frame,c||a),de.dispatchEvent({type:Y.type,data:Y.inputSource}))}function X(){r.removeEventListener("select",W),r.removeEventListener("selectstart",W),r.removeEventListener("selectend",W),r.removeEventListener("squeeze",W),r.removeEventListener("squeezestart",W),r.removeEventListener("squeezeend",W),r.removeEventListener("end",X),r.removeEventListener("inputsourceschange",Z);for(let Y=0;Y=0&&(R[Ce]=null,C[Ce].disconnect(de))}for(let j=0;j=R.length){R.push(de),Ce=He;break}else if(R[He]===null){R[He]=de,Ce=He;break}if(Ce===-1)break}const Se=C[Ce];Se&&Se.connect(de)}}const G=new N,se=new N;function le(Y,j,de){G.setFromMatrixPosition(j.matrixWorld),se.setFromMatrixPosition(de.matrixWorld);const Ce=G.distanceTo(se),Se=j.projectionMatrix.elements,He=de.projectionMatrix.elements,mt=Se[14]/(Se[10]-1),T=Se[14]/(Se[10]+1),Qe=(Se[9]+1)/Se[5],De=(Se[9]-1)/Se[5],we=(Se[8]-1)/Se[0],me=(He[8]+1)/He[0],et=mt*we,ge=mt*me,Ue=Ce/(-we+me),ht=Ue*-we;if(j.matrixWorld.decompose(Y.position,Y.quaternion,Y.scale),Y.translateX(ht),Y.translateZ(Ue),Y.matrixWorld.compose(Y.position,Y.quaternion,Y.scale),Y.matrixWorldInverse.copy(Y.matrixWorld).invert(),Se[10]===-1)Y.projectionMatrix.copy(j.projectionMatrix),Y.projectionMatrixInverse.copy(j.projectionMatrixInverse);else{const at=mt+Ue,y=T+Ue,g=et-ht,F=ge+(Ce-ht),k=Qe*T/y*at,K=De*T/y*at;Y.projectionMatrix.makePerspective(g,F,k,K,at,y),Y.projectionMatrixInverse.copy(Y.projectionMatrix).invert()}}function Ee(Y,j){j===null?Y.matrixWorld.copy(Y.matrix):Y.matrixWorld.multiplyMatrices(j.matrixWorld,Y.matrix),Y.matrixWorldInverse.copy(Y.matrixWorld).invert()}this.updateCamera=function(Y){if(r===null)return;let j=Y.near,de=Y.far;p.texture!==null&&(p.depthNear>0&&(j=p.depthNear),p.depthFar>0&&(de=p.depthFar)),O.near=M.near=S.near=j,O.far=M.far=S.far=de,(H!==O.near||q!==O.far)&&(r.updateRenderState({depthNear:O.near,depthFar:O.far}),H=O.near,q=O.far),O.layers.mask=Y.layers.mask|6,S.layers.mask=O.layers.mask&3,M.layers.mask=O.layers.mask&5;const Ce=Y.parent,Se=O.cameras;Ee(O,Ce);for(let He=0;He0&&(p.alphaTest.value=u.alphaTest);const b=e.get(u),A=b.envMap,E=b.envMapRotation;A&&(p.envMap.value=A,yn.copy(E),yn.x*=-1,yn.y*=-1,yn.z*=-1,A.isCubeTexture&&A.isRenderTargetTexture===!1&&(yn.y*=-1,yn.z*=-1),p.envMapRotation.value.setFromMatrix4(ap.makeRotationFromEuler(yn)),p.flipEnvMap.value=A.isCubeTexture&&A.isRenderTargetTexture===!1?-1:1,p.reflectivity.value=u.reflectivity,p.ior.value=u.ior,p.refractionRatio.value=u.refractionRatio),u.lightMap&&(p.lightMap.value=u.lightMap,p.lightMapIntensity.value=u.lightMapIntensity,t(u.lightMap,p.lightMapTransform)),u.aoMap&&(p.aoMap.value=u.aoMap,p.aoMapIntensity.value=u.aoMapIntensity,t(u.aoMap,p.aoMapTransform))}function a(p,u){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,u.map&&(p.map.value=u.map,t(u.map,p.mapTransform))}function o(p,u){p.dashSize.value=u.dashSize,p.totalSize.value=u.dashSize+u.gapSize,p.scale.value=u.scale}function l(p,u,b,A){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,p.size.value=u.size*b,p.scale.value=A*.5,u.map&&(p.map.value=u.map,t(u.map,p.uvTransform)),u.alphaMap&&(p.alphaMap.value=u.alphaMap,t(u.alphaMap,p.alphaMapTransform)),u.alphaTest>0&&(p.alphaTest.value=u.alphaTest)}function c(p,u){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,p.rotation.value=u.rotation,u.map&&(p.map.value=u.map,t(u.map,p.mapTransform)),u.alphaMap&&(p.alphaMap.value=u.alphaMap,t(u.alphaMap,p.alphaMapTransform)),u.alphaTest>0&&(p.alphaTest.value=u.alphaTest)}function d(p,u){p.specular.value.copy(u.specular),p.shininess.value=Math.max(u.shininess,1e-4)}function h(p,u){u.gradientMap&&(p.gradientMap.value=u.gradientMap)}function f(p,u){p.metalness.value=u.metalness,u.metalnessMap&&(p.metalnessMap.value=u.metalnessMap,t(u.metalnessMap,p.metalnessMapTransform)),p.roughness.value=u.roughness,u.roughnessMap&&(p.roughnessMap.value=u.roughnessMap,t(u.roughnessMap,p.roughnessMapTransform)),u.envMap&&(p.envMapIntensity.value=u.envMapIntensity)}function m(p,u,b){p.ior.value=u.ior,u.sheen>0&&(p.sheenColor.value.copy(u.sheenColor).multiplyScalar(u.sheen),p.sheenRoughness.value=u.sheenRoughness,u.sheenColorMap&&(p.sheenColorMap.value=u.sheenColorMap,t(u.sheenColorMap,p.sheenColorMapTransform)),u.sheenRoughnessMap&&(p.sheenRoughnessMap.value=u.sheenRoughnessMap,t(u.sheenRoughnessMap,p.sheenRoughnessMapTransform))),u.clearcoat>0&&(p.clearcoat.value=u.clearcoat,p.clearcoatRoughness.value=u.clearcoatRoughness,u.clearcoatMap&&(p.clearcoatMap.value=u.clearcoatMap,t(u.clearcoatMap,p.clearcoatMapTransform)),u.clearcoatRoughnessMap&&(p.clearcoatRoughnessMap.value=u.clearcoatRoughnessMap,t(u.clearcoatRoughnessMap,p.clearcoatRoughnessMapTransform)),u.clearcoatNormalMap&&(p.clearcoatNormalMap.value=u.clearcoatNormalMap,t(u.clearcoatNormalMap,p.clearcoatNormalMapTransform),p.clearcoatNormalScale.value.copy(u.clearcoatNormalScale),u.side===yt&&p.clearcoatNormalScale.value.negate())),u.dispersion>0&&(p.dispersion.value=u.dispersion),u.iridescence>0&&(p.iridescence.value=u.iridescence,p.iridescenceIOR.value=u.iridescenceIOR,p.iridescenceThicknessMinimum.value=u.iridescenceThicknessRange[0],p.iridescenceThicknessMaximum.value=u.iridescenceThicknessRange[1],u.iridescenceMap&&(p.iridescenceMap.value=u.iridescenceMap,t(u.iridescenceMap,p.iridescenceMapTransform)),u.iridescenceThicknessMap&&(p.iridescenceThicknessMap.value=u.iridescenceThicknessMap,t(u.iridescenceThicknessMap,p.iridescenceThicknessMapTransform))),u.transmission>0&&(p.transmission.value=u.transmission,p.transmissionSamplerMap.value=b.texture,p.transmissionSamplerSize.value.set(b.width,b.height),u.transmissionMap&&(p.transmissionMap.value=u.transmissionMap,t(u.transmissionMap,p.transmissionMapTransform)),p.thickness.value=u.thickness,u.thicknessMap&&(p.thicknessMap.value=u.thicknessMap,t(u.thicknessMap,p.thicknessMapTransform)),p.attenuationDistance.value=u.attenuationDistance,p.attenuationColor.value.copy(u.attenuationColor)),u.anisotropy>0&&(p.anisotropyVector.value.set(u.anisotropy*Math.cos(u.anisotropyRotation),u.anisotropy*Math.sin(u.anisotropyRotation)),u.anisotropyMap&&(p.anisotropyMap.value=u.anisotropyMap,t(u.anisotropyMap,p.anisotropyMapTransform))),p.specularIntensity.value=u.specularIntensity,p.specularColor.value.copy(u.specularColor),u.specularColorMap&&(p.specularColorMap.value=u.specularColorMap,t(u.specularColorMap,p.specularColorMapTransform)),u.specularIntensityMap&&(p.specularIntensityMap.value=u.specularIntensityMap,t(u.specularIntensityMap,p.specularIntensityMapTransform))}function _(p,u){u.matcap&&(p.matcap.value=u.matcap)}function x(p,u){const b=e.get(u).light;p.referencePosition.value.setFromMatrixPosition(b.matrixWorld),p.nearDistance.value=b.shadow.camera.near,p.farDistance.value=b.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:r}}function cp(i,e,t,n){let r={},s={},a=[];const o=i.getParameter(i.MAX_UNIFORM_BUFFER_BINDINGS);function l(b,A){const E=A.program;n.uniformBlockBinding(b,E)}function c(b,A){let E=r[b.id];E===void 0&&(_(b),E=d(b),r[b.id]=E,b.addEventListener("dispose",p));const C=A.program;n.updateUBOMapping(b,C);const R=e.render.frame;s[b.id]!==R&&(f(b),s[b.id]=R)}function d(b){const A=h();b.__bindingPointIndex=A;const E=i.createBuffer(),C=b.__size,R=b.usage;return i.bindBuffer(i.UNIFORM_BUFFER,E),i.bufferData(i.UNIFORM_BUFFER,C,R),i.bindBuffer(i.UNIFORM_BUFFER,null),i.bindBufferBase(i.UNIFORM_BUFFER,A,E),E}function h(){for(let b=0;b0&&(E+=C-R),b.__size=E,b.__cache={},this}function x(b){const A={boundary:0,storage:0};return typeof b=="number"||typeof b=="boolean"?(A.boundary=4,A.storage=4):b.isVector2?(A.boundary=8,A.storage=8):b.isVector3||b.isColor?(A.boundary=16,A.storage=12):b.isVector4?(A.boundary=16,A.storage=16):b.isMatrix3?(A.boundary=48,A.storage=48):b.isMatrix4?(A.boundary=64,A.storage=64):b.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",b),A}function p(b){const A=b.target;A.removeEventListener("dispose",p);const E=a.indexOf(A.__bindingPointIndex);a.splice(E,1),i.deleteBuffer(r[A.id]),delete r[A.id],delete s[A.id]}function u(){for(const b in r)i.deleteBuffer(r[b]);a=[],r={},s={}}return{bind:l,update:c,dispose:u}}class lp{constructor(e={}){const{canvas:t=Bc(),context:n=null,depth:r=!0,stencil:s=!1,alpha:a=!1,antialias:o=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:d="default",failIfMajorPerformanceCaveat:h=!1,reversedDepthBuffer:f=!1}=e;this.isWebGLRenderer=!0;let m;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");m=n.getContextAttributes().alpha}else m=a;const _=new Uint32Array(4),x=new Int32Array(4);let p=null,u=null;const b=[],A=[];this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.toneMapping=fn,this.toneMappingExposure=1,this.transmissionResolutionScale=1;const E=this;let C=!1;this._outputColorSpace=Lt;let R=0,w=0,U=null,S=-1,M=null;const P=new st,O=new st;let H=null;const q=new Fe(0);let W=0,X=t.width,Z=t.height,G=1,se=null,le=null;const Ee=new st(0,0,X,Z),Oe=new st(0,0,X,Z);let Ke=!1;const Je=new js;let We=!1,Y=!1;const j=new it,de=new N,Ce=new st,Se={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let He=!1;function mt(){return U===null?G:1}let T=n;function Qe(v,L){return t.getContext(v,L)}try{const v={alpha:!0,depth:r,stencil:s,antialias:o,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:d,failIfMajorPerformanceCaveat:h};if("setAttribute"in t&&t.setAttribute("data-engine",`three.js r${Gs}`),t.addEventListener("webglcontextlost",ie,!1),t.addEventListener("webglcontextrestored",he,!1),t.addEventListener("webglcontextcreationerror",J,!1),T===null){const L="webgl2";if(T=Qe(L,v),T===null)throw Qe(L)?new Error("Error creating WebGL context with your selected attributes."):new Error("Error creating WebGL context.")}}catch(v){throw console.error("THREE.WebGLRenderer: "+v.message),v}let De,we,me,et,ge,Ue,ht,at,y,g,F,k,K,V,Me,ne,_e,ve,ee,ce,be,xe,ae,Le;function D(){De=new vd(T),De.init(),xe=new tp(T,De),we=new hd(T,De,e,xe),me=new Qf(T,De),we.reversedDepthBuffer&&f&&me.buffers.depth.setReversed(!0),et=new Sd(T),ge=new Hf,Ue=new ep(T,De,me,ge,we,xe,et),ht=new fd(E),at=new _d(E),y=new wl(T),ae=new ld(T,y),g=new xd(T,y,et,ae),F=new yd(T,g,y,et),ee=new Ed(T,we,Ue),ne=new dd(ge),k=new zf(E,ht,at,De,we,ae,ne),K=new op(E,ge),V=new Vf,Me=new $f(De),ve=new cd(E,ht,at,me,F,m,l),_e=new jf(E,F,we),Le=new cp(T,et,we,me),ce=new ud(T,De,et),be=new Md(T,De,et),et.programs=k.programs,E.capabilities=we,E.extensions=De,E.properties=ge,E.renderLists=V,E.shadowMap=_e,E.state=me,E.info=et}D();const te=new sp(E,T);this.xr=te,this.getContext=function(){return T},this.getContextAttributes=function(){return T.getContextAttributes()},this.forceContextLoss=function(){const v=De.get("WEBGL_lose_context");v&&v.loseContext()},this.forceContextRestore=function(){const v=De.get("WEBGL_lose_context");v&&v.restoreContext()},this.getPixelRatio=function(){return G},this.setPixelRatio=function(v){v!==void 0&&(G=v,this.setSize(X,Z,!1))},this.getSize=function(v){return v.set(X,Z)},this.setSize=function(v,L,B=!0){if(te.isPresenting){console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting.");return}X=v,Z=L,t.width=Math.floor(v*G),t.height=Math.floor(L*G),B===!0&&(t.style.width=v+"px",t.style.height=L+"px"),this.setViewport(0,0,v,L)},this.getDrawingBufferSize=function(v){return v.set(X*G,Z*G).floor()},this.setDrawingBufferSize=function(v,L,B){X=v,Z=L,G=B,t.width=Math.floor(v*B),t.height=Math.floor(L*B),this.setViewport(0,0,v,L)},this.getCurrentViewport=function(v){return v.copy(P)},this.getViewport=function(v){return v.copy(Ee)},this.setViewport=function(v,L,B,z){v.isVector4?Ee.set(v.x,v.y,v.z,v.w):Ee.set(v,L,B,z),me.viewport(P.copy(Ee).multiplyScalar(G).round())},this.getScissor=function(v){return v.copy(Oe)},this.setScissor=function(v,L,B,z){v.isVector4?Oe.set(v.x,v.y,v.z,v.w):Oe.set(v,L,B,z),me.scissor(O.copy(Oe).multiplyScalar(G).round())},this.getScissorTest=function(){return Ke},this.setScissorTest=function(v){me.setScissorTest(Ke=v)},this.setOpaqueSort=function(v){se=v},this.setTransparentSort=function(v){le=v},this.getClearColor=function(v){return v.copy(ve.getClearColor())},this.setClearColor=function(){ve.setClearColor(...arguments)},this.getClearAlpha=function(){return ve.getClearAlpha()},this.setClearAlpha=function(){ve.setClearAlpha(...arguments)},this.clear=function(v=!0,L=!0,B=!0){let z=0;if(v){let I=!1;if(U!==null){const Q=U.texture.format;I=Q===Ys||Q===qs||Q===Xs}if(I){const Q=U.texture.type,oe=Q===Yt||Q===Pn||Q===pi||Q===mi||Q===ks||Q===Ws,fe=ve.getClearColor(),ue=ve.getClearAlpha(),Ae=fe.r,Re=fe.g,ye=fe.b;oe?(_[0]=Ae,_[1]=Re,_[2]=ye,_[3]=ue,T.clearBufferuiv(T.COLOR,0,_)):(x[0]=Ae,x[1]=Re,x[2]=ye,x[3]=ue,T.clearBufferiv(T.COLOR,0,x))}else z|=T.COLOR_BUFFER_BIT}L&&(z|=T.DEPTH_BUFFER_BIT),B&&(z|=T.STENCIL_BUFFER_BIT,this.state.buffers.stencil.setMask(4294967295)),T.clear(z)},this.clearColor=function(){this.clear(!0,!1,!1)},this.clearDepth=function(){this.clear(!1,!0,!1)},this.clearStencil=function(){this.clear(!1,!1,!0)},this.dispose=function(){t.removeEventListener("webglcontextlost",ie,!1),t.removeEventListener("webglcontextrestored",he,!1),t.removeEventListener("webglcontextcreationerror",J,!1),ve.dispose(),V.dispose(),Me.dispose(),ge.dispose(),ht.dispose(),at.dispose(),F.dispose(),ae.dispose(),Le.dispose(),k.dispose(),te.dispose(),te.removeEventListener("sessionstart",Gt),te.removeEventListener("sessionend",na),gn.stop()};function ie(v){v.preventDefault(),console.log("THREE.WebGLRenderer: Context Lost."),C=!0}function he(){console.log("THREE.WebGLRenderer: Context Restored."),C=!1;const v=et.autoReset,L=_e.enabled,B=_e.autoUpdate,z=_e.needsUpdate,I=_e.type;D(),et.autoReset=v,_e.enabled=L,_e.autoUpdate=B,_e.needsUpdate=z,_e.type=I}function J(v){console.error("THREE.WebGLRenderer: A WebGL context could not be created. Reason: ",v.statusMessage)}function $(v){const L=v.target;L.removeEventListener("dispose",$),pe(L)}function pe(v){Pe(v),ge.remove(v)}function Pe(v){const L=ge.get(v).programs;L!==void 0&&(L.forEach(function(B){k.releaseProgram(B)}),v.isShaderMaterial&&k.releaseShaderCache(v))}this.renderBufferDirect=function(v,L,B,z,I,Q){L===null&&(L=Se);const oe=I.isMesh&&I.matrixWorld.determinant()<0,fe=Wo(v,L,B,z,I);me.setMaterial(z,oe);let ue=B.index,Ae=1;if(z.wireframe===!0){if(ue=g.getWireframeAttribute(B),ue===void 0)return;Ae=2}const Re=B.drawRange,ye=B.attributes.position;let Be=Re.start*Ae,qe=(Re.start+Re.count)*Ae;Q!==null&&(Be=Math.max(Be,Q.start*Ae),qe=Math.min(qe,(Q.start+Q.count)*Ae)),ue!==null?(Be=Math.max(Be,0),qe=Math.min(qe,ue.count)):ye!=null&&(Be=Math.max(Be,0),qe=Math.min(qe,ye.count));const rt=qe-Be;if(rt<0||rt===1/0)return;ae.setup(I,z,fe,B,ue);let je,$e=ce;if(ue!==null&&(je=y.get(ue),$e=be,$e.setIndex(je)),I.isMesh)z.wireframe===!0?(me.setLineWidth(z.wireframeLinewidth*mt()),$e.setMode(T.LINES)):$e.setMode(T.TRIANGLES);else if(I.isLine){let Te=z.linewidth;Te===void 0&&(Te=1),me.setLineWidth(Te*mt()),I.isLineSegments?$e.setMode(T.LINES):I.isLineLoop?$e.setMode(T.LINE_LOOP):$e.setMode(T.LINE_STRIP)}else I.isPoints?$e.setMode(T.POINTS):I.isSprite&&$e.setMode(T.TRIANGLES);if(I.isBatchedMesh)if(I._multiDrawInstances!==null)vi("THREE.WebGLRenderer: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection."),$e.renderMultiDrawInstances(I._multiDrawStarts,I._multiDrawCounts,I._multiDrawCount,I._multiDrawInstances);else if(De.get("WEBGL_multi_draw"))$e.renderMultiDraw(I._multiDrawStarts,I._multiDrawCounts,I._multiDrawCount);else{const Te=I._multiDrawStarts,tt=I._multiDrawCounts,Ve=I._multiDrawCount,At=ue?y.get(ue).bytesPerElement:1,Ln=ge.get(z).currentProgram.getUniforms();for(let bt=0;bt{function Q(){if(z.forEach(function(oe){ge.get(oe).currentProgram.isReady()&&z.delete(oe)}),z.size===0){I(v);return}setTimeout(Q,10)}De.get("KHR_parallel_shader_compile")!==null?Q():setTimeout(Q,10)})};let Xe=null;function Kt(v){Xe&&Xe(v)}function Gt(){gn.stop()}function na(){gn.start()}const gn=new zo;gn.setAnimationLoop(Kt),typeof self<"u"&&gn.setContext(self),this.setAnimationLoop=function(v){Xe=v,te.setAnimationLoop(v),v===null?gn.stop():gn.start()},te.addEventListener("sessionstart",Gt),te.addEventListener("sessionend",na),this.render=function(v,L){if(L!==void 0&&L.isCamera!==!0){console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(C===!0)return;if(v.matrixWorldAutoUpdate===!0&&v.updateMatrixWorld(),L.parent===null&&L.matrixWorldAutoUpdate===!0&&L.updateMatrixWorld(),te.enabled===!0&&te.isPresenting===!0&&(te.cameraAutoUpdate===!0&&te.updateCamera(L),L=te.getCamera()),v.isScene===!0&&v.onBeforeRender(E,v,L,U),u=Me.get(v,A.length),u.init(L),A.push(u),j.multiplyMatrices(L.projectionMatrix,L.matrixWorldInverse),Je.setFromProjectionMatrix(j,Xt,L.reversedDepth),Y=this.localClippingEnabled,We=ne.init(this.clippingPlanes,Y),p=V.get(v,b.length),p.init(),b.push(p),te.enabled===!0&&te.isPresenting===!0){const Q=E.xr.getDepthSensingMesh();Q!==null&&mr(Q,L,-1/0,E.sortObjects)}mr(v,L,0,E.sortObjects),p.finish(),E.sortObjects===!0&&p.sort(se,le),He=te.enabled===!1||te.isPresenting===!1||te.hasDepthSensing()===!1,He&&ve.addToRenderList(p,v),this.info.render.frame++,We===!0&&ne.beginShadows();const B=u.state.shadowsArray;_e.render(B,v,L),We===!0&&ne.endShadows(),this.info.autoReset===!0&&this.info.reset();const z=p.opaque,I=p.transmissive;if(u.setupLights(),L.isArrayCamera){const Q=L.cameras;if(I.length>0)for(let oe=0,fe=Q.length;oe0&&ra(z,I,v,L),He&&ve.render(v),ia(p,v,L);U!==null&&w===0&&(Ue.updateMultisampleRenderTarget(U),Ue.updateRenderTargetMipmap(U)),v.isScene===!0&&v.onAfterRender(E,v,L),ae.resetDefaultState(),S=-1,M=null,A.pop(),A.length>0?(u=A[A.length-1],We===!0&&ne.setGlobalState(E.clippingPlanes,u.state.camera)):u=null,b.pop(),b.length>0?p=b[b.length-1]:p=null};function mr(v,L,B,z){if(v.visible===!1)return;if(v.layers.test(L.layers)){if(v.isGroup)B=v.renderOrder;else if(v.isLOD)v.autoUpdate===!0&&v.update(L);else if(v.isLight)u.pushLight(v),v.castShadow&&u.pushShadow(v);else if(v.isSprite){if(!v.frustumCulled||Je.intersectsSprite(v)){z&&Ce.setFromMatrixPosition(v.matrixWorld).applyMatrix4(j);const oe=F.update(v),fe=v.material;fe.visible&&p.push(v,oe,fe,B,Ce.z,null)}}else if((v.isMesh||v.isLine||v.isPoints)&&(!v.frustumCulled||Je.intersectsObject(v))){const oe=F.update(v),fe=v.material;if(z&&(v.boundingSphere!==void 0?(v.boundingSphere===null&&v.computeBoundingSphere(),Ce.copy(v.boundingSphere.center)):(oe.boundingSphere===null&&oe.computeBoundingSphere(),Ce.copy(oe.boundingSphere.center)),Ce.applyMatrix4(v.matrixWorld).applyMatrix4(j)),Array.isArray(fe)){const ue=oe.groups;for(let Ae=0,Re=ue.length;Ae0&&Ai(I,L,B),Q.length>0&&Ai(Q,L,B),oe.length>0&&Ai(oe,L,B),me.buffers.depth.setTest(!0),me.buffers.depth.setMask(!0),me.buffers.color.setMask(!0),me.setPolygonOffset(!1)}function ra(v,L,B,z){if((B.isScene===!0?B.overrideMaterial:null)!==null)return;u.state.transmissionRenderTarget[z.id]===void 0&&(u.state.transmissionRenderTarget[z.id]=new Dn(1,1,{generateMipmaps:!0,type:De.has("EXT_color_buffer_half_float")||De.has("EXT_color_buffer_float")?xi:Yt,minFilter:Cn,samples:4,stencilBuffer:s,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:ke.workingColorSpace}));const Q=u.state.transmissionRenderTarget[z.id],oe=z.viewport||P;Q.setSize(oe.z*E.transmissionResolutionScale,oe.w*E.transmissionResolutionScale);const fe=E.getRenderTarget(),ue=E.getActiveCubeFace(),Ae=E.getActiveMipmapLevel();E.setRenderTarget(Q),E.getClearColor(q),W=E.getClearAlpha(),W<1&&E.setClearColor(16777215,.5),E.clear(),He&&ve.render(B);const Re=E.toneMapping;E.toneMapping=fn;const ye=z.viewport;if(z.viewport!==void 0&&(z.viewport=void 0),u.setupLightsView(z),We===!0&&ne.setGlobalState(E.clippingPlanes,z),Ai(v,B,z),Ue.updateMultisampleRenderTarget(Q),Ue.updateRenderTargetMipmap(Q),De.has("WEBGL_multisampled_render_to_texture")===!1){let Be=!1;for(let qe=0,rt=L.length;qe0),ye=!!B.morphAttributes.position,Be=!!B.morphAttributes.normal,qe=!!B.morphAttributes.color;let rt=fn;z.toneMapped&&(U===null||U.isXRRenderTarget===!0)&&(rt=E.toneMapping);const je=B.morphAttributes.position||B.morphAttributes.normal||B.morphAttributes.color,$e=je!==void 0?je.length:0,Te=ge.get(z),tt=u.state.lights;if(We===!0&&(Y===!0||v!==M)){const vt=v===M&&z.id===S;ne.setState(z,v,vt)}let Ve=!1;z.version===Te.__version?(Te.needsLights&&Te.lightsStateVersion!==tt.state.version||Te.outputColorSpace!==fe||I.isBatchedMesh&&Te.batching===!1||!I.isBatchedMesh&&Te.batching===!0||I.isBatchedMesh&&Te.batchingColor===!0&&I.colorTexture===null||I.isBatchedMesh&&Te.batchingColor===!1&&I.colorTexture!==null||I.isInstancedMesh&&Te.instancing===!1||!I.isInstancedMesh&&Te.instancing===!0||I.isSkinnedMesh&&Te.skinning===!1||!I.isSkinnedMesh&&Te.skinning===!0||I.isInstancedMesh&&Te.instancingColor===!0&&I.instanceColor===null||I.isInstancedMesh&&Te.instancingColor===!1&&I.instanceColor!==null||I.isInstancedMesh&&Te.instancingMorph===!0&&I.morphTexture===null||I.isInstancedMesh&&Te.instancingMorph===!1&&I.morphTexture!==null||Te.envMap!==ue||z.fog===!0&&Te.fog!==Q||Te.numClippingPlanes!==void 0&&(Te.numClippingPlanes!==ne.numPlanes||Te.numIntersection!==ne.numIntersection)||Te.vertexAlphas!==Ae||Te.vertexTangents!==Re||Te.morphTargets!==ye||Te.morphNormals!==Be||Te.morphColors!==qe||Te.toneMapping!==rt||Te.morphTargetsCount!==$e)&&(Ve=!0):(Ve=!0,Te.__version=z.version);let At=Te.currentProgram;Ve===!0&&(At=bi(z,L,I));let Ln=!1,bt=!1,ri=!1;const nt=At.getUniforms(),Ct=Te.uniforms;if(me.useProgram(At.program)&&(Ln=!0,bt=!0,ri=!0),z.id!==S&&(S=z.id,bt=!0),Ln||M!==v){me.buffers.depth.getReversed()&&v.reversedDepth!==!0&&(v._reversedDepth=!0,v.updateProjectionMatrix()),nt.setValue(T,"projectionMatrix",v.projectionMatrix),nt.setValue(T,"viewMatrix",v.matrixWorldInverse);const Mt=nt.map.cameraPosition;Mt!==void 0&&Mt.setValue(T,de.setFromMatrixPosition(v.matrixWorld)),we.logarithmicDepthBuffer&&nt.setValue(T,"logDepthBufFC",2/(Math.log(v.far+1)/Math.LN2)),(z.isMeshPhongMaterial||z.isMeshToonMaterial||z.isMeshLambertMaterial||z.isMeshBasicMaterial||z.isMeshStandardMaterial||z.isShaderMaterial)&&nt.setValue(T,"isOrthographic",v.isOrthographicCamera===!0),M!==v&&(M=v,bt=!0,ri=!0)}if(I.isSkinnedMesh){nt.setOptional(T,I,"bindMatrix"),nt.setOptional(T,I,"bindMatrixInverse");const vt=I.skeleton;vt&&(vt.boneTexture===null&&vt.computeBoneTexture(),nt.setValue(T,"boneTexture",vt.boneTexture,Ue))}I.isBatchedMesh&&(nt.setOptional(T,I,"batchingTexture"),nt.setValue(T,"batchingTexture",I._matricesTexture,Ue),nt.setOptional(T,I,"batchingIdTexture"),nt.setValue(T,"batchingIdTexture",I._indirectTexture,Ue),nt.setOptional(T,I,"batchingColorTexture"),I._colorsTexture!==null&&nt.setValue(T,"batchingColorTexture",I._colorsTexture,Ue));const Pt=B.morphAttributes;if((Pt.position!==void 0||Pt.normal!==void 0||Pt.color!==void 0)&&ee.update(I,B,At),(bt||Te.receiveShadow!==I.receiveShadow)&&(Te.receiveShadow=I.receiveShadow,nt.setValue(T,"receiveShadow",I.receiveShadow)),z.isMeshGouraudMaterial&&z.envMap!==null&&(Ct.envMap.value=ue,Ct.flipEnvMap.value=ue.isCubeTexture&&ue.isRenderTargetTexture===!1?-1:1),z.isMeshStandardMaterial&&z.envMap===null&&L.environment!==null&&(Ct.envMapIntensity.value=L.environmentIntensity),bt&&(nt.setValue(T,"toneMappingExposure",E.toneMappingExposure),Te.needsLights&&Xo(Ct,ri),Q&&z.fog===!0&&K.refreshFogUniforms(Ct,Q),K.refreshMaterialUniforms(Ct,z,G,Z,u.state.transmissionRenderTarget[v.id]),rr.upload(T,aa(Te),Ct,Ue)),z.isShaderMaterial&&z.uniformsNeedUpdate===!0&&(rr.upload(T,aa(Te),Ct,Ue),z.uniformsNeedUpdate=!1),z.isSpriteMaterial&&nt.setValue(T,"center",I.center),nt.setValue(T,"modelViewMatrix",I.modelViewMatrix),nt.setValue(T,"normalMatrix",I.normalMatrix),nt.setValue(T,"modelMatrix",I.matrixWorld),z.isShaderMaterial||z.isRawShaderMaterial){const vt=z.uniformsGroups;for(let Mt=0,gr=vt.length;Mt0&&Ue.useMultisampledRTT(v)===!1?I=ge.get(v).__webglMultisampledFramebuffer:Array.isArray(Re)?I=Re[B]:I=Re,P.copy(v.viewport),O.copy(v.scissor),H=v.scissorTest}else P.copy(Ee).multiplyScalar(G).floor(),O.copy(Oe).multiplyScalar(G).floor(),H=Ke;if(B!==0&&(I=Yo),me.bindFramebuffer(T.FRAMEBUFFER,I)&&z&&me.drawBuffers(v,I),me.viewport(P),me.scissor(O),me.setScissorTest(H),Q){const ue=ge.get(v.texture);T.framebufferTexture2D(T.FRAMEBUFFER,T.COLOR_ATTACHMENT0,T.TEXTURE_CUBE_MAP_POSITIVE_X+L,ue.__webglTexture,B)}else if(oe){const ue=L;for(let Ae=0;Ae=0&&L<=v.width-z&&B>=0&&B<=v.height-I&&(v.textures.length>1&&T.readBuffer(T.COLOR_ATTACHMENT0+fe),T.readPixels(L,B,z,I,xe.convert(Re),xe.convert(ye),Q))}finally{const Ae=U!==null?ge.get(U).__webglFramebuffer:null;me.bindFramebuffer(T.FRAMEBUFFER,Ae)}}},this.readRenderTargetPixelsAsync=async function(v,L,B,z,I,Q,oe,fe=0){if(!(v&&v.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let ue=ge.get(v).__webglFramebuffer;if(v.isWebGLCubeRenderTarget&&oe!==void 0&&(ue=ue[oe]),ue)if(L>=0&&L<=v.width-z&&B>=0&&B<=v.height-I){me.bindFramebuffer(T.FRAMEBUFFER,ue);const Ae=v.textures[fe],Re=Ae.format,ye=Ae.type;if(!we.textureFormatReadable(Re))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!we.textureTypeReadable(ye))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");const Be=T.createBuffer();T.bindBuffer(T.PIXEL_PACK_BUFFER,Be),T.bufferData(T.PIXEL_PACK_BUFFER,Q.byteLength,T.STREAM_READ),v.textures.length>1&&T.readBuffer(T.COLOR_ATTACHMENT0+fe),T.readPixels(L,B,z,I,xe.convert(Re),xe.convert(ye),0);const qe=U!==null?ge.get(U).__webglFramebuffer:null;me.bindFramebuffer(T.FRAMEBUFFER,qe);const rt=T.fenceSync(T.SYNC_GPU_COMMANDS_COMPLETE,0);return T.flush(),await zc(T,rt,4),T.bindBuffer(T.PIXEL_PACK_BUFFER,Be),T.getBufferSubData(T.PIXEL_PACK_BUFFER,0,Q),T.deleteBuffer(Be),T.deleteSync(rt),Q}else throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")},this.copyFramebufferToTexture=function(v,L=null,B=0){const z=Math.pow(2,-B),I=Math.floor(v.image.width*z),Q=Math.floor(v.image.height*z),oe=L!==null?L.x:0,fe=L!==null?L.y:0;Ue.setTexture2D(v,0),T.copyTexSubImage2D(T.TEXTURE_2D,B,0,0,oe,fe,I,Q),me.unbindTexture()};const $o=T.createFramebuffer(),Ko=T.createFramebuffer();this.copyTextureToTexture=function(v,L,B=null,z=null,I=0,Q=null){Q===null&&(I!==0?(vi("WebGLRenderer: copyTextureToTexture function signature has changed to support src and dst mipmap levels."),Q=I,I=0):Q=0);let oe,fe,ue,Ae,Re,ye,Be,qe,rt;const je=v.isCompressedTexture?v.mipmaps[Q]:v.image;if(B!==null)oe=B.max.x-B.min.x,fe=B.max.y-B.min.y,ue=B.isBox3?B.max.z-B.min.z:1,Ae=B.min.x,Re=B.min.y,ye=B.isBox3?B.min.z:0;else{const Pt=Math.pow(2,-I);oe=Math.floor(je.width*Pt),fe=Math.floor(je.height*Pt),v.isDataArrayTexture?ue=je.depth:v.isData3DTexture?ue=Math.floor(je.depth*Pt):ue=1,Ae=0,Re=0,ye=0}z!==null?(Be=z.x,qe=z.y,rt=z.z):(Be=0,qe=0,rt=0);const $e=xe.convert(L.format),Te=xe.convert(L.type);let tt;L.isData3DTexture?(Ue.setTexture3D(L,0),tt=T.TEXTURE_3D):L.isDataArrayTexture||L.isCompressedArrayTexture?(Ue.setTexture2DArray(L,0),tt=T.TEXTURE_2D_ARRAY):(Ue.setTexture2D(L,0),tt=T.TEXTURE_2D),T.pixelStorei(T.UNPACK_FLIP_Y_WEBGL,L.flipY),T.pixelStorei(T.UNPACK_PREMULTIPLY_ALPHA_WEBGL,L.premultiplyAlpha),T.pixelStorei(T.UNPACK_ALIGNMENT,L.unpackAlignment);const Ve=T.getParameter(T.UNPACK_ROW_LENGTH),At=T.getParameter(T.UNPACK_IMAGE_HEIGHT),Ln=T.getParameter(T.UNPACK_SKIP_PIXELS),bt=T.getParameter(T.UNPACK_SKIP_ROWS),ri=T.getParameter(T.UNPACK_SKIP_IMAGES);T.pixelStorei(T.UNPACK_ROW_LENGTH,je.width),T.pixelStorei(T.UNPACK_IMAGE_HEIGHT,je.height),T.pixelStorei(T.UNPACK_SKIP_PIXELS,Ae),T.pixelStorei(T.UNPACK_SKIP_ROWS,Re),T.pixelStorei(T.UNPACK_SKIP_IMAGES,ye);const nt=v.isDataArrayTexture||v.isData3DTexture,Ct=L.isDataArrayTexture||L.isData3DTexture;if(v.isDepthTexture){const Pt=ge.get(v),vt=ge.get(L),Mt=ge.get(Pt.__renderTarget),gr=ge.get(vt.__renderTarget);me.bindFramebuffer(T.READ_FRAMEBUFFER,Mt.__webglFramebuffer),me.bindFramebuffer(T.DRAW_FRAMEBUFFER,gr.__webglFramebuffer);for(let _n=0;_n(i[i.None=0]="None",i[i.Left=1]="Left",i[i.Right=2]="Right",i[i.Across=3]="Across",i))(fi||{}),pt=(i=>(i[i.Clubs=0]="Clubs",i[i.Diamonds=1]="Diamonds",i[i.Hearts=2]="Hearts",i[i.Spades=3]="Spades",i))(pt||{});class ho{mesh;card;cardGeometry;cardMaterial;isHovered=!1;isSelected=!1;constructor(e,t){this.card=e,this.mesh=new hi,this.mesh.position.copy(t),this.cardGeometry=new Ti(1.2,1.7),this.cardMaterial=new Bs({color:this.getCardColor(),side:kt});const n=new Et(this.cardGeometry,this.cardMaterial);this.mesh.add(n);const r=new gl(this.cardGeometry),s=new No({color:0,linewidth:2}),a=new ml(r,s);this.mesh.add(a),this.addCardDetails(),this.mesh.userData={card:this}}getCardColor(){switch(this.card.suit){case pt.Hearts:return 16739179;case pt.Diamonds:return 16751001;case pt.Clubs:return 3355443;case pt.Spades:return 1710618;default:return 16777215}}addCardDetails(){const e=new hr(.2,16),t=new cr({color:this.card.suit===pt.Hearts||this.card.suit===pt.Diamonds?16711680:0}),n=new Et(e,t);n.position.set(-.4,.6,.01),this.mesh.add(n);const r=new hr(.3,this.getSuitSegments()),s=new cr({color:this.card.suit===pt.Hearts||this.card.suit===pt.Diamonds?16711680:0}),a=new Et(r,s);a.position.set(0,0,.01),this.mesh.add(a)}getSuitSegments(){switch(this.card.suit){case pt.Hearts:return 3;case pt.Diamonds:return 4;case pt.Clubs:return 5;case pt.Spades:return 6;default:return 16}}getRankString(){return["","","2","3","4","5","6","7","8","9","10","J","Q","K","A"][this.card.rank]||"?"}getSuitString(){switch(this.card.suit){case pt.Hearts:return"♥";case pt.Diamonds:return"♦";case pt.Clubs:return"♣";case pt.Spades:return"♠";default:return"?"}}setHovered(e){this.isHovered!==e&&(this.isHovered=e,e&&!this.isSelected?(this.mesh.position.y+=.3,this.cardMaterial.emissive=new Fe(4473924)):this.isSelected||(this.mesh.position.y-=.3,this.cardMaterial.emissive=new Fe(0)))}setSelected(e){this.isSelected=e,e?(this.mesh.position.y=.5,this.cardMaterial.emissive=new Fe(8947848)):(this.mesh.position.y=0,this.cardMaterial.emissive=new Fe(0))}animateToPosition(e,t=500){return new Promise(n=>{const r=this.mesh.position.clone(),s=Date.now(),a=()=>{const o=Date.now()-s,l=Math.min(o/t,1),c=l<.5?2*l*l:1-Math.pow(-2*l+2,2)/2;this.mesh.position.lerpVectors(r,e,c),l<1?requestAnimationFrame(a):n()};a()})}dispose(){this.cardGeometry.dispose(),this.cardMaterial.dispose()}}class up{scene;camera;renderer;raycaster;mouse;playerCards=[];currentTrickCards=[];hoveredCard=null;selectedCards=[];onCardClick;constructor(e){this.scene=new ul,this.scene.background=new Fe(1722154),this.camera=new It(75,window.innerWidth/window.innerHeight,.1,1e3),this.camera.position.set(0,10,12),this.camera.lookAt(0,0,0),this.renderer=new lp({antialias:!0}),this.renderer.setSize(window.innerWidth,window.innerHeight),this.renderer.shadowMap.enabled=!0,e.appendChild(this.renderer.domElement),this.raycaster=new Al,this.mouse=new Ge,this.setupLights(),this.createTable(),window.addEventListener("resize",this.onWindowResize.bind(this)),this.renderer.domElement.addEventListener("mousemove",this.onMouseMove.bind(this)),this.renderer.domElement.addEventListener("click",this.onClick.bind(this)),this.animate()}setupLights(){const e=new yl(16777215,.6);this.scene.add(e);const t=new El(16777215,.8);t.position.set(5,10,5),t.castShadow=!0,this.scene.add(t);const n=new xl(16777215,4473924,.4);this.scene.add(n)}createTable(){const e=new Js(8,8,.2,32),t=new Bs({color:678442,roughness:.8,metalness:.1}),n=new Et(e,t);n.position.y=-.5,n.receiveShadow=!0,this.scene.add(n);const r=new Qs(8,.15,16,32),s=new Bs({color:9127187}),a=new Et(r,s);a.rotation.x=Math.PI/2,a.position.y=-.4,this.scene.add(a)}addPlayerCards(e){this.clearPlayerCards();const t=e.length,n=1.5,r=-(t-1)*n/2;e.forEach((s,a)=>{const o=new N(r+a*n,0,5),l=new ho(s,o);this.playerCards.push(l),this.scene.add(l.mesh)})}addTrickCard(e,t){const r=[new N(0,0,2),new N(-2,0,0),new N(0,0,-2),new N(2,0,0)][t%4],s=new ho(e,r);this.currentTrickCards.push(s),this.scene.add(s.mesh)}clearTrick(){this.currentTrickCards.forEach(e=>{this.scene.remove(e.mesh),e.dispose()}),this.currentTrickCards=[]}clearPlayerCards(){this.playerCards.forEach(e=>{this.scene.remove(e.mesh),e.dispose()}),this.playerCards=[],this.selectedCards=[]}removePlayerCard(e){const t=this.playerCards.findIndex(n=>n.card.rank===e.rank&&n.card.suit===e.suit);if(t!==-1){const n=this.playerCards[t];this.scene.remove(n.mesh),n.dispose(),this.playerCards.splice(t,1),this.rearrangePlayerCards()}}rearrangePlayerCards(){const e=this.playerCards.length,t=1.5,n=-(e-1)*t/2;this.playerCards.forEach((r,s)=>{const a=new N(n+s*t,r.mesh.position.y,5);r.animateToPosition(a,300)})}getSelectedCards(){return this.selectedCards}clearSelection(){this.selectedCards.forEach(e=>e.setSelected(!1)),this.selectedCards=[]}onMouseMove(e){this.mouse.x=e.clientX/window.innerWidth*2-1,this.mouse.y=-(e.clientY/window.innerHeight)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);const t=this.playerCards.map(r=>r.mesh),n=this.raycaster.intersectObjects(t,!0);if(n.length>0){const s=n[0].object.parent?.userData.card;s&&s!==this.hoveredCard&&(this.hoveredCard&&this.hoveredCard.setHovered(!1),this.hoveredCard=s,this.hoveredCard.setHovered(!0))}else this.hoveredCard&&(this.hoveredCard.setHovered(!1),this.hoveredCard=null)}onClick(e){this.mouse.x=e.clientX/window.innerWidth*2-1,this.mouse.y=-(e.clientY/window.innerHeight)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);const t=this.playerCards.map(r=>r.mesh),n=this.raycaster.intersectObjects(t,!0);if(n.length>0){const s=n[0].object.parent?.userData.card;s&&(this.handleCardSelection(s),this.onCardClick&&this.onCardClick(s))}}handleCardSelection(e){const t=this.selectedCards.indexOf(e);t!==-1?(this.selectedCards.splice(t,1),e.setSelected(!1)):this.selectedCards.length<3&&(this.selectedCards.push(e),e.setSelected(!0))}onWindowResize(){this.camera.aspect=window.innerWidth/window.innerHeight,this.camera.updateProjectionMatrix(),this.renderer.setSize(window.innerWidth,window.innerHeight)}animate(){requestAnimationFrame(this.animate.bind(this)),this.renderer.render(this.scene,this.camera)}dispose(){window.removeEventListener("resize",this.onWindowResize.bind(this)),this.renderer.domElement.removeEventListener("mousemove",this.onMouseMove.bind(this)),this.renderer.domElement.removeEventListener("click",this.onClick.bind(this)),this.renderer.dispose()}}class hp{connectionPanel;gameInfo;messageDisplay;statusElement;roundNumberEl;playerScoreEl;totalScoreEl;passDirectionEl;turnStatusEl;connectionStatusEl;constructor(){this.connectionPanel=document.getElementById("connection-panel"),this.gameInfo=document.getElementById("game-info"),this.messageDisplay=document.getElementById("message-display"),this.statusElement=document.getElementById("status"),this.roundNumberEl=document.getElementById("round-number"),this.playerScoreEl=document.getElementById("player-score"),this.totalScoreEl=document.getElementById("total-score"),this.passDirectionEl=document.getElementById("pass-direction"),this.turnStatusEl=document.getElementById("turn-status"),this.connectionStatusEl=document.getElementById("connection-status")}showConnectionPanel(){this.connectionPanel.classList.remove("hidden"),this.gameInfo.classList.add("hidden")}hideConnectionPanel(){this.connectionPanel.classList.add("hidden"),this.gameInfo.classList.remove("hidden")}setConnectionStatus(e){this.connectionStatusEl.textContent=e}updateGameInfo(e){e.roundNumber!==void 0&&(this.roundNumberEl.textContent=e.roundNumber.toString()),e.playerScore!==void 0&&(this.playerScoreEl.textContent=e.playerScore.toString()),e.totalScore!==void 0&&(this.totalScoreEl.textContent=e.totalScore.toString()),e.passDirection!==void 0&&(this.passDirectionEl.textContent=`Pass: ${e.passDirection}`),e.isMyTurn!==void 0&&(this.turnStatusEl.textContent=e.isMyTurn?"Your turn!":"Waiting...",this.turnStatusEl.style.color=e.isMyTurn?"#4caf50":"#666")}setStatus(e){this.statusElement.textContent=e}showMessage(e,t=3e3){this.messageDisplay.textContent=e,this.messageDisplay.classList.add("show"),setTimeout(()=>{this.messageDisplay.classList.remove("show")},t)}getConnectionInputs(){return{playerName:document.getElementById("player-name").value,gameId:document.getElementById("game-id").value}}setConnectButtonEnabled(e){const t=document.getElementById("connect-btn");t.disabled=!e}}class dp{constructor(e,t){this.actionSocket=e,this.notificationSocket=t,this.gameStartedHandlers=[],this.passingPhaseStartedHandlers=[],this.allPlayersPassedHandlers=[],this.playerPassedCardsHandlers=[],this.itsYourTurnHandlers=[],this.itsPlayersTurnHandlers=[],this.playerPlayedCardHandlers=[],this.trickCompletedHandlers=[],this.roundEndedHandlers=[],this.gameEndedHandlers=[],this.heartsWereBrokenHandlers=[],this.setupNotificationHandlers()}setupNotificationHandlers(){this.notificationSocket.onmessage=e=>{const t=JSON.parse(e.data);this.handleNotification(t)}}handleNotification(e){switch(e.type){case"GameStarted":this.gameStartedHandlers.forEach(t=>t(e.data));break;case"PassingPhaseStarted":this.passingPhaseStartedHandlers.forEach(t=>t(e.data));break;case"AllPlayersPassed":this.allPlayersPassedHandlers.forEach(t=>t(e.data));break;case"PlayerPassedCards":this.playerPassedCardsHandlers.forEach(t=>t(e.data));break;case"ItsYourTurn":this.itsYourTurnHandlers.forEach(t=>t(e.data));break;case"ItsPlayersTurn":this.itsPlayersTurnHandlers.forEach(t=>t(e.data));break;case"PlayerPlayedCard":this.playerPlayedCardHandlers.forEach(t=>t(e.data));break;case"TrickCompleted":this.trickCompletedHandlers.forEach(t=>t(e.data));break;case"RoundEnded":this.roundEndedHandlers.forEach(t=>t(e.data));break;case"GameEnded":this.gameEndedHandlers.forEach(t=>t(e.data));break;case"HeartsWereBroken":this.heartsWereBrokenHandlers.forEach(t=>t(e.data));break}}onGameStarted(e){this.gameStartedHandlers.push(e)}offGameStarted(e){const t=this.gameStartedHandlers.indexOf(e);t>-1&&this.gameStartedHandlers.splice(t,1)}onPassingPhaseStarted(e){this.passingPhaseStartedHandlers.push(e)}offPassingPhaseStarted(e){const t=this.passingPhaseStartedHandlers.indexOf(e);t>-1&&this.passingPhaseStartedHandlers.splice(t,1)}onAllPlayersPassed(e){this.allPlayersPassedHandlers.push(e)}offAllPlayersPassed(e){const t=this.allPlayersPassedHandlers.indexOf(e);t>-1&&this.allPlayersPassedHandlers.splice(t,1)}onPlayerPassedCards(e){this.playerPassedCardsHandlers.push(e)}offPlayerPassedCards(e){const t=this.playerPassedCardsHandlers.indexOf(e);t>-1&&this.playerPassedCardsHandlers.splice(t,1)}onItsYourTurn(e){this.itsYourTurnHandlers.push(e)}offItsYourTurn(e){const t=this.itsYourTurnHandlers.indexOf(e);t>-1&&this.itsYourTurnHandlers.splice(t,1)}onItsPlayersTurn(e){this.itsPlayersTurnHandlers.push(e)}offItsPlayersTurn(e){const t=this.itsPlayersTurnHandlers.indexOf(e);t>-1&&this.itsPlayersTurnHandlers.splice(t,1)}onPlayerPlayedCard(e){this.playerPlayedCardHandlers.push(e)}offPlayerPlayedCard(e){const t=this.playerPlayedCardHandlers.indexOf(e);t>-1&&this.playerPlayedCardHandlers.splice(t,1)}onTrickCompleted(e){this.trickCompletedHandlers.push(e)}offTrickCompleted(e){const t=this.trickCompletedHandlers.indexOf(e);t>-1&&this.trickCompletedHandlers.splice(t,1)}onRoundEnded(e){this.roundEndedHandlers.push(e)}offRoundEnded(e){const t=this.roundEndedHandlers.indexOf(e);t>-1&&this.roundEndedHandlers.splice(t,1)}onGameEnded(e){this.gameEndedHandlers.push(e)}offGameEnded(e){const t=this.gameEndedHandlers.indexOf(e);t>-1&&this.gameEndedHandlers.splice(t,1)}onHeartsWereBroken(e){this.heartsWereBrokenHandlers.push(e)}offHeartsWereBroken(e){const t=this.heartsWereBrokenHandlers.indexOf(e);t>-1&&this.heartsWereBrokenHandlers.splice(t,1)}async passCards(e){return new Promise((t,n)=>{const r={type:"PassCards",data:{request:e}},s=a=>{const o=JSON.parse(a.data);o.error?n(new Error(o.error)):t(o.data),this.actionSocket.removeEventListener("message",s)};this.actionSocket.addEventListener("message",s),this.actionSocket.send(JSON.stringify(r))})}async playCard(e){return new Promise((t,n)=>{const r={type:"PlayCard",data:{request:e}},s=a=>{const o=JSON.parse(a.data);o.error?n(new Error(o.error)):t(o.data),this.actionSocket.removeEventListener("message",s)};this.actionSocket.addEventListener("message",s),this.actionSocket.send(JSON.stringify(r))})}}class fp{client;scene;ui;playerId="";passingPhase=!1;myTurn=!1;constructor(e,t){this.scene=e,this.ui=t,this.scene.onCardClick=this.handleCardClick.bind(this)}async connect(e,t,n,r){this.playerId=t;try{console.log("Starting connection process..."),this.ui.setConnectionStatus("Authenticating..."),this.ui.setConnectButtonEnabled(!1);const s=e.replace("ws://","http://").replace("wss://","https://");console.log("Authenticating with:",s+"/login");const a=await fetch(`${s}/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:n,password:"default-password"}),credentials:"include"});if(console.log("Login response status:",a.status),!a.ok){const _=await a.text();throw console.error("Login failed:",_),new Error(`Authentication failed: ${a.status} ${a.statusText} +${_}`)}const o=await a.json();console.log("Authenticated successfully:",o);const l=o.accessToken;this.ui.setConnectionStatus("Authenticated. Connecting to game..."),console.log("Attempting to connect to game:",r);const c=`${e}/hearts/join/${encodeURIComponent(r)}`;console.log("Connecting action socket to:",c);const d=new WebSocket(c);await this.waitForSocketOpen(d),console.log("Action socket connected"),this.ui.setConnectionStatus("Action socket connected. Waiting for connection ID..."),console.log("Waiting for connection ID...");const h=await this.getConnectionId(d);console.log("Received connection ID:",h),this.ui.setConnectionStatus("Establishing notification socket...");const f=`${e}/hearts/join/${h}/finish`;console.log("Connecting notification socket to:",f);const m=new WebSocket(f);await this.waitForSocketOpen(m),console.log("Notification socket connected"),this.ui.setConnectionStatus("Connected!"),this.client=new dp(d,m),this.setupEventHandlers(),this.ui.hideConnectionPanel(),this.ui.setStatus("Connected to game"),this.ui.showMessage("Connected to Hearts game!")}catch(s){console.error("Connection error:",s);const a=s instanceof Error?s.message:String(s);throw this.ui.setConnectionStatus(`Connection failed: ${a}`),this.ui.showMessage(`Connection failed: ${a}`,1e4),this.ui.setConnectButtonEnabled(!0),s}}getConnectionId(e){return new Promise((t,n)=>{const r=setTimeout(()=>{n(new Error("Timeout waiting for connection ID (10 seconds). The game may not exist or you may not have permission to join."))},1e4),s=a=>{console.log("Received message while waiting for connection ID:",a.data),clearTimeout(r);try{const o=JSON.parse(a.data);console.log("Parsed data:",o),o.connectionId?(e.removeEventListener("message",s),t(o.connectionId)):(console.error("Message does not contain connectionId:",o),n(new Error("No connectionId in response. Received: "+JSON.stringify(o))))}catch(o){console.error("Failed to parse message:",o,"Raw data:",a.data),n(new Error("Failed to parse connection ID response: "+a.data))}};e.addEventListener("message",s)})}waitForSocketOpen(e){return new Promise((t,n)=>{const r=setTimeout(()=>{n(new Error("Connection timeout - server not responding"))},1e4);e.onopen=()=>{clearTimeout(r),t()},e.onerror=s=>{clearTimeout(r),console.error("WebSocket error:",s),console.error("Socket URL:",e.url),console.error("Socket readyState:",e.readyState),n(new Error(`WebSocket connection failed. Make sure: +1. Server is running on localhost:13992 +2. Game ID exists on server +3. Check server logs for errors`))},e.onclose=s=>{s.wasClean||(clearTimeout(r),n(new Error(`Connection closed unexpectedly (code: ${s.code}, reason: ${s.reason||"none"})`)))}})}setupEventHandlers(){this.client&&(this.client.onGameStarted(e=>{console.log("Game started:",e),this.ui.showMessage("Game started!"),this.ui.setStatus("Game in progress"),e.playerViewOfGame&&this.updateGameState(e.playerViewOfGame)}),this.client.onPassingPhaseStarted(e=>{console.log("Passing phase started:",e),this.passingPhase=!0;const t=this.getPassDirectionString(e.passDirection);this.ui.showMessage(`Pass 3 cards ${t}`),this.ui.setStatus(`Select 3 cards to pass ${t}`),this.ui.updateGameInfo({passDirection:t})}),this.client.onAllPlayersPassed(e=>{console.log("All players passed:",e),this.passingPhase=!1,this.scene.clearSelection(),e.receivedCards&&e.receivedCards.length>0&&this.ui.showMessage(`Received ${e.receivedCards.length} cards`),this.ui.setStatus("Cards passed. Waiting for round to start...")}),this.client.onPlayerPassedCards(e=>{console.log("Player passed cards:",e)}),this.client.onItsYourTurn(e=>{console.log("Your turn:",e),this.myTurn=!0,this.ui.showMessage("Your turn!"),this.ui.setStatus("Your turn - select a card to play"),this.ui.updateGameInfo({isMyTurn:!0}),e.playerViewOfGame&&this.updateGameState(e.playerViewOfGame)}),this.client.onItsPlayersTurn(e=>{console.log("It's another player's turn:",e),this.myTurn=!1,this.ui.updateGameInfo({isMyTurn:!1}),this.ui.setStatus("Waiting for other players...")}),this.client.onPlayerPlayedCard(e=>{console.log("Player played card:",e),this.scene.addTrickCard(e.card,0)}),this.client.onTrickCompleted(e=>{console.log("Trick completed:",e),this.ui.showMessage(`${e.winnerName||"Player"} won the trick! (+${e.points} points)`),setTimeout(()=>{this.scene.clearTrick()},2e3)}),this.client.onRoundEnded(e=>{console.log("Round ended:",e);let t="Round ended!";e.moonShooterName&&(t=`${e.moonShooterName} shot the moon!`),this.ui.showMessage(t,5e3),this.ui.setStatus("Round ended. Waiting for next round..."),e.scores&&console.log("Scores:",e.scores)}),this.client.onGameEnded(e=>{console.log("Game ended:",e),this.ui.showMessage(`Game Over! Winner: ${e.winnerName||"Unknown"}`,1e4),this.ui.setStatus("Game ended")}),this.client.onHeartsWereBroken(()=>{console.log("Hearts were broken"),this.ui.showMessage("Hearts have been broken!")}))}updateGameState(e){console.log("Updating game state:",e),this.ui.updateGameInfo({roundNumber:e.roundNumber,playerScore:e.roundScore,totalScore:e.totalScore,isMyTurn:e.isMyTurn}),e.cards&&this.scene.addPlayerCards(e.cards),e.currentTrick&&(this.scene.clearTrick(),e.currentTrick.forEach((t,n)=>{this.scene.addTrickCard(t.card,n)}))}getPassDirectionString(e){switch(e){case fi.Left:return"Left";case fi.Right:return"Right";case fi.Across:return"Across";case fi.None:return"None";default:return"Unknown"}}async handleCardClick(e){if(this.passingPhase){const t=this.scene.getSelectedCards();t.length===3&&(this.ui.setStatus("Passing cards..."),await this.passCards(t.map(n=>n.card)))}else this.myTurn&&(this.ui.setStatus("Playing card..."),await this.playCard(e.card))}async passCards(e){if(this.client)try{const t=await this.client.passCards({playerId:this.playerId,cards:e});console.log("Pass cards response:",t),t.hasError?(this.ui.showMessage(`Error: ${t.error}`),this.scene.clearSelection()):(this.ui.showMessage("Cards passed!"),this.ui.setStatus("Waiting for other players to pass..."),e.forEach(n=>this.scene.removePlayerCard(n)),this.scene.clearSelection())}catch(t){console.error("Error passing cards:",t),this.ui.showMessage("Failed to pass cards"),this.scene.clearSelection()}}async playCard(e){if(this.client)try{const t=await this.client.playCard({playerId:this.playerId,card:e});console.log("Play card response:",t),t.hasError?this.ui.showMessage(`Error: ${t.error}`):(this.myTurn=!1,this.scene.removePlayerCard(e),this.scene.addTrickCard(e,0),this.ui.setStatus("Waiting for other players..."),this.updateGameState(t))}catch(t){console.error("Error playing card:",t),this.ui.showMessage("Failed to play card")}}}function pp(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,i=>{const e=Math.random()*16|0;return(i==="x"?e:e&3|8).toString(16)})}function fo(){console.log("Initializing Hearts Web Client...");const i=document.getElementById("canvas-container");if(!i){console.error("Canvas container not found!");return}const e=new up(i);console.log("3D scene initialized");const t=new hp;console.log("UI initialized");const n=new fp(e,t);console.log("Game controller initialized");const r=document.getElementById("connect-btn");r&&r.addEventListener("click",async()=>{const s=t.getConnectionInputs(),a=s.playerName.trim(),o=s.gameId.trim();if(!a||!o){t.setConnectionStatus("Please fill in all fields");return}const l=pp(),c="ws://localhost:13992";console.log("Connection details:"),console.log("- Server URL:",c),console.log("- Player ID:",l),console.log("- Player Name:",a),console.log("- Game ID:",o);try{await n.connect(c,l,a,o)}catch(d){console.error("Failed to connect:",d)}}),console.log("Hearts Web Client ready!")}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",fo):fo(); diff --git a/web-clients/hearts/dist/index.html b/web-clients/hearts/dist/index.html new file mode 100644 index 00000000..0841a2aa --- /dev/null +++ b/web-clients/hearts/dist/index.html @@ -0,0 +1,180 @@ + + + + + + Hearts - Deckster + + + + +
+
+
+
+

Connect to Hearts Game

+ + + +

+
+ +
+
Waiting to connect...
+
+
+ + diff --git a/web-clients/hearts/index.html b/web-clients/hearts/index.html new file mode 100644 index 00000000..88ee1263 --- /dev/null +++ b/web-clients/hearts/index.html @@ -0,0 +1,180 @@ + + + + + + Hearts - Deckster + + + +
+
+
+
+

Connect to Hearts Game

+ + + +

+
+ +
+
Waiting to connect...
+
+
+ + + diff --git a/web-clients/hearts/package-lock.json b/web-clients/hearts/package-lock.json new file mode 100644 index 00000000..c456cd88 --- /dev/null +++ b/web-clients/hearts/package-lock.json @@ -0,0 +1,1160 @@ +{ + "name": "hearts", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hearts", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@types/three": "^0.180.0", + "three": "^0.180.0" + }, + "devDependencies": { + "@types/node": "^24.7.1", + "typescript": "^5.9.3", + "vite": "^7.1.9" + } + }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "license": "Apache-2.0" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.1.tgz", + "integrity": "sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.180.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.180.0.tgz", + "integrity": "sha512-ykFtgCqNnY0IPvDro7h+9ZeLY+qjgUWv+qEvUt84grhenO60Hqd4hScHE7VTB9nOQ/3QM8lkbNE+4vKjEpUxKg==", + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": "*", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.22.0" + } + }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "license": "MIT" + }, + "node_modules/@webgpu/types": { + "version": "0.1.65", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.65.tgz", + "integrity": "sha512-cYrHab4d6wuVvDW5tdsfI6/o6vcLMDe6w2Citd1oS51Xxu2ycLCnVo4fqwujfKWijrZMInTJIKcXxteoy21nVA==", + "license": "BSD-3-Clause" + }, + "node_modules/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/meshoptimizer": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.22.0.tgz", + "integrity": "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/three": { + "version": "0.180.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.180.0.tgz", + "integrity": "sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz", + "integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/web-clients/hearts/package.json b/web-clients/hearts/package.json new file mode 100644 index 00000000..9b396108 --- /dev/null +++ b/web-clients/hearts/package.json @@ -0,0 +1,23 @@ +{ + "name": "hearts", + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "Hearts card game web client using three.js", + "devDependencies": { + "@types/node": "^24.7.1", + "typescript": "^5.9.3", + "vite": "^7.1.9" + }, + "dependencies": { + "@types/three": "^0.180.0", + "three": "^0.180.0" + } +} diff --git a/web-clients/hearts/src/game/HeartsGame.ts b/web-clients/hearts/src/game/HeartsGame.ts new file mode 100644 index 00000000..9d39b8d4 --- /dev/null +++ b/web-clients/hearts/src/game/HeartsGame.ts @@ -0,0 +1,384 @@ +import { HeartsClientImpl } from '@generated/hearts/HeartsClient'; +import { Card, PassDirection, PlayerViewOfGame } from '@generated/hearts/types'; +import { CardScene } from '../graphics/CardScene'; +import { GameUI } from '../ui/GameUI'; +import { Card3D } from '../graphics/Card3D'; + +export class HeartsGame { + private client?: HeartsClientImpl; + private scene: CardScene; + private ui: GameUI; + private playerId: string = ''; + + private passingPhase: boolean = false; + private myTurn: boolean = false; + + constructor(scene: CardScene, ui: GameUI) { + this.scene = scene; + this.ui = ui; + + // Setup scene card click handler + this.scene.onCardClick = this.handleCardClick.bind(this); + } + + public async connect(serverUrl: string, playerId: string, playerName: string, gameId: string): Promise { + this.playerId = playerId; + + try { + console.log('Starting connection process...'); + this.ui.setConnectionStatus('Authenticating...'); + this.ui.setConnectButtonEnabled(false); + + // First, authenticate to get access token + const httpUrl = serverUrl.replace('ws://', 'http://').replace('wss://', 'https://'); + console.log('Authenticating with:', httpUrl + '/login'); + + const loginResponse = await fetch(`${httpUrl}/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + username: playerName, + password: 'default-password' + }), + credentials: 'include' // Important for cookies + }); + + console.log('Login response status:', loginResponse.status); + + if (!loginResponse.ok) { + const errorText = await loginResponse.text(); + console.error('Login failed:', errorText); + throw new Error(`Authentication failed: ${loginResponse.status} ${loginResponse.statusText}\n${errorText}`); + } + + const userData = await loginResponse.json(); + console.log('Authenticated successfully:', userData); + const accessToken = userData.accessToken; + + this.ui.setConnectionStatus('Authenticated. Connecting to game...'); + console.log('Attempting to connect to game:', gameId); + + // Create WebSocket connections with proper URL pattern + const actionSocketUrl = `${serverUrl}/hearts/join/${encodeURIComponent(gameId)}`; + console.log('Connecting action socket to:', actionSocketUrl); + const actionSocket = new WebSocket(actionSocketUrl); + + await this.waitForSocketOpen(actionSocket); + console.log('Action socket connected'); + this.ui.setConnectionStatus('Action socket connected. Waiting for connection ID...'); + + // Get connection ID from the first message + console.log('Waiting for connection ID...'); + const connectionId = await this.getConnectionId(actionSocket); + console.log('Received connection ID:', connectionId); + + this.ui.setConnectionStatus('Establishing notification socket...'); + + // After action socket is connected, establish notification socket + const notificationSocketUrl = `${serverUrl}/hearts/join/${connectionId}/finish`; + console.log('Connecting notification socket to:', notificationSocketUrl); + const notificationSocket = new WebSocket(notificationSocketUrl); + + await this.waitForSocketOpen(notificationSocket); + console.log('Notification socket connected'); + this.ui.setConnectionStatus('Connected!'); + + // Create Hearts client + this.client = new HeartsClientImpl(actionSocket, notificationSocket); + + // Setup event handlers + this.setupEventHandlers(); + + // Hide connection panel + this.ui.hideConnectionPanel(); + this.ui.setStatus('Connected to game'); + this.ui.showMessage('Connected to Hearts game!'); + + } catch (error) { + console.error('Connection error:', error); + const errorMessage = error instanceof Error ? error.message : String(error); + this.ui.setConnectionStatus(`Connection failed: ${errorMessage}`); + this.ui.showMessage(`Connection failed: ${errorMessage}`, 10000); + this.ui.setConnectButtonEnabled(true); + throw error; + } + } + + private getConnectionId(socket: WebSocket): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error('Timeout waiting for connection ID (10 seconds). The game may not exist or you may not have permission to join.')); + }, 10000); + + const messageHandler = (event: MessageEvent) => { + console.log('Received message while waiting for connection ID:', event.data); + clearTimeout(timeout); + try { + const data = JSON.parse(event.data); + console.log('Parsed data:', data); + + if (data.connectionId) { + socket.removeEventListener('message', messageHandler); + resolve(data.connectionId); + } else { + console.error('Message does not contain connectionId:', data); + reject(new Error('No connectionId in response. Received: ' + JSON.stringify(data))); + } + } catch (error) { + console.error('Failed to parse message:', error, 'Raw data:', event.data); + reject(new Error('Failed to parse connection ID response: ' + event.data)); + } + }; + + socket.addEventListener('message', messageHandler); + }); + } + + private waitForSocketOpen(socket: WebSocket): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error('Connection timeout - server not responding')); + }, 10000); + + socket.onopen = () => { + clearTimeout(timeout); + resolve(); + }; + + socket.onerror = (error) => { + clearTimeout(timeout); + console.error('WebSocket error:', error); + console.error('Socket URL:', socket.url); + console.error('Socket readyState:', socket.readyState); + reject(new Error(`WebSocket connection failed. Make sure:\n1. Server is running on localhost:13992\n2. Game ID exists on server\n3. Check server logs for errors`)); + }; + + socket.onclose = (event) => { + if (!event.wasClean) { + clearTimeout(timeout); + reject(new Error(`Connection closed unexpectedly (code: ${event.code}, reason: ${event.reason || 'none'})`)); + } + }; + }); + } + + private setupEventHandlers(): void { + if (!this.client) return; + + this.client.onGameStarted((data) => { + console.log('Game started:', data); + this.ui.showMessage('Game started!'); + this.ui.setStatus('Game in progress'); + + if (data.playerViewOfGame) { + this.updateGameState(data.playerViewOfGame); + } + }); + + this.client.onPassingPhaseStarted((data) => { + console.log('Passing phase started:', data); + this.passingPhase = true; + const direction = this.getPassDirectionString(data.passDirection); + this.ui.showMessage(`Pass 3 cards ${direction}`); + this.ui.setStatus(`Select 3 cards to pass ${direction}`); + this.ui.updateGameInfo({ passDirection: direction }); + }); + + this.client.onAllPlayersPassed((data) => { + console.log('All players passed:', data); + this.passingPhase = false; + this.scene.clearSelection(); + + if (data.receivedCards && data.receivedCards.length > 0) { + this.ui.showMessage(`Received ${data.receivedCards.length} cards`); + } + + this.ui.setStatus('Cards passed. Waiting for round to start...'); + }); + + this.client.onPlayerPassedCards((data) => { + console.log('Player passed cards:', data); + }); + + this.client.onItsYourTurn((data) => { + console.log('Your turn:', data); + this.myTurn = true; + this.ui.showMessage('Your turn!'); + this.ui.setStatus('Your turn - select a card to play'); + this.ui.updateGameInfo({ isMyTurn: true }); + + if (data.playerViewOfGame) { + this.updateGameState(data.playerViewOfGame); + } + }); + + this.client.onItsPlayersTurn((data) => { + console.log("It's another player's turn:", data); + this.myTurn = false; + this.ui.updateGameInfo({ isMyTurn: false }); + this.ui.setStatus('Waiting for other players...'); + }); + + this.client.onPlayerPlayedCard((data) => { + console.log('Player played card:', data); + // Note: In production, you'd map playerId to position + const playerPosition = 0; // Simplified + this.scene.addTrickCard(data.card, playerPosition); + }); + + this.client.onTrickCompleted((data) => { + console.log('Trick completed:', data); + this.ui.showMessage( + `${data.winnerName || 'Player'} won the trick! (+${data.points} points)` + ); + + // Clear trick after a delay + setTimeout(() => { + this.scene.clearTrick(); + }, 2000); + }); + + this.client.onRoundEnded((data) => { + console.log('Round ended:', data); + let message = 'Round ended!'; + + if (data.moonShooterName) { + message = `${data.moonShooterName} shot the moon!`; + } + + this.ui.showMessage(message, 5000); + this.ui.setStatus('Round ended. Waiting for next round...'); + + if (data.scores) { + console.log('Scores:', data.scores); + } + }); + + this.client.onGameEnded((data) => { + console.log('Game ended:', data); + this.ui.showMessage( + `Game Over! Winner: ${data.winnerName || 'Unknown'}`, + 10000 + ); + this.ui.setStatus('Game ended'); + }); + + this.client.onHeartsWereBroken(() => { + console.log('Hearts were broken'); + this.ui.showMessage('Hearts have been broken!'); + }); + } + + private updateGameState(state: PlayerViewOfGame): void { + console.log('Updating game state:', state); + + // Update UI + this.ui.updateGameInfo({ + roundNumber: state.roundNumber, + playerScore: state.roundScore, + totalScore: state.totalScore, + isMyTurn: state.isMyTurn, + }); + + // Update cards in hand + if (state.cards) { + this.scene.addPlayerCards(state.cards); + } + + // Update current trick + if (state.currentTrick) { + this.scene.clearTrick(); + state.currentTrick.forEach((cardPlay, index) => { + this.scene.addTrickCard(cardPlay.card, index); + }); + } + } + + private getPassDirectionString(direction: PassDirection): string { + switch (direction) { + case PassDirection.Left: + return 'Left'; + case PassDirection.Right: + return 'Right'; + case PassDirection.Across: + return 'Across'; + case PassDirection.None: + return 'None'; + default: + return 'Unknown'; + } + } + + private async handleCardClick(card: Card3D): Promise { + if (this.passingPhase) { + // Handle card passing + const selectedCards = this.scene.getSelectedCards(); + + if (selectedCards.length === 3) { + this.ui.setStatus('Passing cards...'); + await this.passCards(selectedCards.map(c => c.card)); + } + } else if (this.myTurn) { + // Handle card playing + this.ui.setStatus('Playing card...'); + await this.playCard(card.card); + } + } + + private async passCards(cards: Card[]): Promise { + if (!this.client) return; + + try { + const response = await this.client.passCards({ + playerId: this.playerId, + cards: cards, + }); + + console.log('Pass cards response:', response); + + if (response.hasError) { + this.ui.showMessage(`Error: ${response.error}`); + this.scene.clearSelection(); + } else { + this.ui.showMessage('Cards passed!'); + this.ui.setStatus('Waiting for other players to pass...'); + + // Remove passed cards from hand + cards.forEach(card => this.scene.removePlayerCard(card)); + this.scene.clearSelection(); + } + } catch (error) { + console.error('Error passing cards:', error); + this.ui.showMessage('Failed to pass cards'); + this.scene.clearSelection(); + } + } + + private async playCard(card: Card): Promise { + if (!this.client) return; + + try { + const response = await this.client.playCard({ + playerId: this.playerId, + card: card, + }); + + console.log('Play card response:', response); + + if (response.hasError) { + this.ui.showMessage(`Error: ${response.error}`); + } else { + this.myTurn = false; + this.scene.removePlayerCard(card); + this.scene.addTrickCard(card, 0); // Current player position + this.ui.setStatus('Waiting for other players...'); + this.updateGameState(response); + } + } catch (error) { + console.error('Error playing card:', error); + this.ui.showMessage('Failed to play card'); + } + } +} diff --git a/web-clients/hearts/src/graphics/Card3D.ts b/web-clients/hearts/src/graphics/Card3D.ts new file mode 100644 index 00000000..97f87012 --- /dev/null +++ b/web-clients/hearts/src/graphics/Card3D.ts @@ -0,0 +1,171 @@ +import * as THREE from 'three'; +import { Card, Suit } from '@generated/hearts/types'; + +export class Card3D { + public mesh: THREE.Group; + public card: Card; + private cardGeometry: THREE.PlaneGeometry; + private cardMaterial: THREE.MeshStandardMaterial; + private isHovered = false; + private isSelected = false; + + constructor(card: Card, position: THREE.Vector3) { + this.card = card; + this.mesh = new THREE.Group(); + this.mesh.position.copy(position); + + // Create card geometry + this.cardGeometry = new THREE.PlaneGeometry(1.2, 1.7); + + // Create card material with color based on card + this.cardMaterial = new THREE.MeshStandardMaterial({ + color: this.getCardColor(), + side: THREE.DoubleSide, + }); + + const cardMesh = new THREE.Mesh(this.cardGeometry, this.cardMaterial); + this.mesh.add(cardMesh); + + // Add card border + const borderGeometry = new THREE.EdgesGeometry(this.cardGeometry); + const borderMaterial = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 2 }); + const border = new THREE.LineSegments(borderGeometry, borderMaterial); + this.mesh.add(border); + + // Add card text (simplified - would use texture in production) + this.addCardDetails(); + + this.mesh.userData = { card: this }; + } + + private getCardColor(): number { + switch (this.card.suit) { + case Suit.Hearts: + return 0xff6b6b; + case Suit.Diamonds: + return 0xff9999; + case Suit.Clubs: + return 0x333333; + case Suit.Spades: + return 0x1a1a1a; + default: + return 0xffffff; + } + } + + private addCardDetails(): void { + // Create a simple representation using geometry + // In production, you'd use textures with actual card images + + // Add rank indicator (simplified) + const rankGeometry = new THREE.CircleGeometry(0.2, 16); + const rankMaterial = new THREE.MeshBasicMaterial({ + color: this.card.suit === Suit.Hearts || this.card.suit === Suit.Diamonds ? 0xff0000 : 0x000000 + }); + const rankMesh = new THREE.Mesh(rankGeometry, rankMaterial); + rankMesh.position.set(-0.4, 0.6, 0.01); + this.mesh.add(rankMesh); + + // Add suit indicator + const suitGeometry = new THREE.CircleGeometry(0.3, this.getSuitSegments()); + const suitMaterial = new THREE.MeshBasicMaterial({ + color: this.card.suit === Suit.Hearts || this.card.suit === Suit.Diamonds ? 0xff0000 : 0x000000 + }); + const suitMesh = new THREE.Mesh(suitGeometry, suitMaterial); + suitMesh.position.set(0, 0, 0.01); + this.mesh.add(suitMesh); + } + + private getSuitSegments(): number { + // Different number of segments for visual distinction + switch (this.card.suit) { + case Suit.Hearts: + return 3; + case Suit.Diamonds: + return 4; + case Suit.Clubs: + return 5; + case Suit.Spades: + return 6; + default: + return 16; + } + } + + public getRankString(): string { + const ranks = ['', '', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']; + return ranks[this.card.rank] || '?'; + } + + public getSuitString(): string { + switch (this.card.suit) { + case Suit.Hearts: + return '♥'; + case Suit.Diamonds: + return '♦'; + case Suit.Clubs: + return '♣'; + case Suit.Spades: + return '♠'; + default: + return '?'; + } + } + + public setHovered(hovered: boolean): void { + if (this.isHovered === hovered) return; + this.isHovered = hovered; + + if (hovered && !this.isSelected) { + this.mesh.position.y += 0.3; + this.cardMaterial.emissive = new THREE.Color(0x444444); + } else if (!this.isSelected) { + this.mesh.position.y -= 0.3; + this.cardMaterial.emissive = new THREE.Color(0x000000); + } + } + + public setSelected(selected: boolean): void { + this.isSelected = selected; + + if (selected) { + this.mesh.position.y = 0.5; + this.cardMaterial.emissive = new THREE.Color(0x888888); + } else { + this.mesh.position.y = 0; + this.cardMaterial.emissive = new THREE.Color(0x000000); + } + } + + public animateToPosition(targetPosition: THREE.Vector3, duration: number = 500): Promise { + return new Promise((resolve) => { + const startPosition = this.mesh.position.clone(); + const startTime = Date.now(); + + const animate = () => { + const elapsed = Date.now() - startTime; + const progress = Math.min(elapsed / duration, 1); + + // Easing function + const eased = progress < 0.5 + ? 2 * progress * progress + : 1 - Math.pow(-2 * progress + 2, 2) / 2; + + this.mesh.position.lerpVectors(startPosition, targetPosition, eased); + + if (progress < 1) { + requestAnimationFrame(animate); + } else { + resolve(); + } + }; + + animate(); + }); + } + + public dispose(): void { + this.cardGeometry.dispose(); + this.cardMaterial.dispose(); + } +} diff --git a/web-clients/hearts/src/graphics/CardScene.ts b/web-clients/hearts/src/graphics/CardScene.ts new file mode 100644 index 00000000..ae933c88 --- /dev/null +++ b/web-clients/hearts/src/graphics/CardScene.ts @@ -0,0 +1,279 @@ +import * as THREE from 'three'; +import { Card3D } from './Card3D'; +import { Card } from '@generated/hearts/types'; + +export class CardScene { + private scene: THREE.Scene; + private camera: THREE.PerspectiveCamera; + private renderer: THREE.WebGLRenderer; + private raycaster: THREE.Raycaster; + private mouse: THREE.Vector2; + + public playerCards: Card3D[] = []; + public currentTrickCards: Card3D[] = []; + private hoveredCard: Card3D | null = null; + private selectedCards: Card3D[] = []; + + public onCardClick?: (card: Card3D) => void; + + constructor(container: HTMLElement) { + // Initialize scene + this.scene = new THREE.Scene(); + this.scene.background = new THREE.Color(0x1a472a); + + // Initialize camera + this.camera = new THREE.PerspectiveCamera( + 75, + window.innerWidth / window.innerHeight, + 0.1, + 1000 + ); + this.camera.position.set(0, 10, 12); + this.camera.lookAt(0, 0, 0); + + // Initialize renderer + this.renderer = new THREE.WebGLRenderer({ antialias: true }); + this.renderer.setSize(window.innerWidth, window.innerHeight); + this.renderer.shadowMap.enabled = true; + container.appendChild(this.renderer.domElement); + + // Initialize raycaster for mouse interaction + this.raycaster = new THREE.Raycaster(); + this.mouse = new THREE.Vector2(); + + // Add lights + this.setupLights(); + + // Add table + this.createTable(); + + // Event listeners + window.addEventListener('resize', this.onWindowResize.bind(this)); + this.renderer.domElement.addEventListener('mousemove', this.onMouseMove.bind(this)); + this.renderer.domElement.addEventListener('click', this.onClick.bind(this)); + + // Start animation loop + this.animate(); + } + + private setupLights(): void { + // Ambient light + const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); + this.scene.add(ambientLight); + + // Directional light (main light) + const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); + directionalLight.position.set(5, 10, 5); + directionalLight.castShadow = true; + this.scene.add(directionalLight); + + // Hemisphere light for better ambient + const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.4); + this.scene.add(hemiLight); + } + + private createTable(): void { + // Create table surface + const tableGeometry = new THREE.CylinderGeometry(8, 8, 0.2, 32); + const tableMaterial = new THREE.MeshStandardMaterial({ + color: 0x0a5a2a, + roughness: 0.8, + metalness: 0.1, + }); + const table = new THREE.Mesh(tableGeometry, tableMaterial); + table.position.y = -0.5; + table.receiveShadow = true; + this.scene.add(table); + + // Add table border + const borderGeometry = new THREE.TorusGeometry(8, 0.15, 16, 32); + const borderMaterial = new THREE.MeshStandardMaterial({ color: 0x8b4513 }); + const border = new THREE.Mesh(borderGeometry, borderMaterial); + border.rotation.x = Math.PI / 2; + border.position.y = -0.4; + this.scene.add(border); + } + + public addPlayerCards(cards: Card[]): void { + // Clear existing cards + this.clearPlayerCards(); + + // Create 3D cards + const cardCount = cards.length; + const spacing = 1.5; + const startX = -(cardCount - 1) * spacing / 2; + + cards.forEach((card, index) => { + const position = new THREE.Vector3( + startX + index * spacing, + 0, + 5 + ); + const card3D = new Card3D(card, position); + this.playerCards.push(card3D); + this.scene.add(card3D.mesh); + }); + } + + public addTrickCard(card: Card, playerIndex: number): void { + // Position cards in the center based on player position + const positions = [ + new THREE.Vector3(0, 0, 2), // South (current player) + new THREE.Vector3(-2, 0, 0), // West + new THREE.Vector3(0, 0, -2), // North + new THREE.Vector3(2, 0, 0), // East + ]; + + const position = positions[playerIndex % 4]; + const card3D = new Card3D(card, position); + this.currentTrickCards.push(card3D); + this.scene.add(card3D.mesh); + } + + public clearTrick(): void { + this.currentTrickCards.forEach(card => { + this.scene.remove(card.mesh); + card.dispose(); + }); + this.currentTrickCards = []; + } + + public clearPlayerCards(): void { + this.playerCards.forEach(card => { + this.scene.remove(card.mesh); + card.dispose(); + }); + this.playerCards = []; + this.selectedCards = []; + } + + public removePlayerCard(card: Card): void { + const index = this.playerCards.findIndex(c => + c.card.rank === card.rank && c.card.suit === card.suit + ); + + if (index !== -1) { + const card3D = this.playerCards[index]; + this.scene.remove(card3D.mesh); + card3D.dispose(); + this.playerCards.splice(index, 1); + + // Rearrange remaining cards + this.rearrangePlayerCards(); + } + } + + private rearrangePlayerCards(): void { + const cardCount = this.playerCards.length; + const spacing = 1.5; + const startX = -(cardCount - 1) * spacing / 2; + + this.playerCards.forEach((card, index) => { + const targetPosition = new THREE.Vector3( + startX + index * spacing, + card.mesh.position.y, + 5 + ); + card.animateToPosition(targetPosition, 300); + }); + } + + public getSelectedCards(): Card3D[] { + return this.selectedCards; + } + + public clearSelection(): void { + this.selectedCards.forEach(card => card.setSelected(false)); + this.selectedCards = []; + } + + private onMouseMove(event: MouseEvent): void { + // Calculate mouse position in normalized device coordinates + this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; + + // Update raycaster + this.raycaster.setFromCamera(this.mouse, this.camera); + + // Check for intersections with player cards + const playerMeshes = this.playerCards.map(c => c.mesh); + const intersects = this.raycaster.intersectObjects(playerMeshes, true); + + if (intersects.length > 0) { + const intersectedGroup = intersects[0].object.parent; + const card = intersectedGroup?.userData.card as Card3D; + + if (card && card !== this.hoveredCard) { + if (this.hoveredCard) { + this.hoveredCard.setHovered(false); + } + this.hoveredCard = card; + this.hoveredCard.setHovered(true); + } + } else { + if (this.hoveredCard) { + this.hoveredCard.setHovered(false); + this.hoveredCard = null; + } + } + } + + private onClick(event: MouseEvent): void { + // Calculate mouse position + this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; + + // Update raycaster + this.raycaster.setFromCamera(this.mouse, this.camera); + + // Check for intersections with player cards + const playerMeshes = this.playerCards.map(c => c.mesh); + const intersects = this.raycaster.intersectObjects(playerMeshes, true); + + if (intersects.length > 0) { + const intersectedGroup = intersects[0].object.parent; + const card = intersectedGroup?.userData.card as Card3D; + + if (card) { + this.handleCardSelection(card); + if (this.onCardClick) { + this.onCardClick(card); + } + } + } + } + + private handleCardSelection(card: Card3D): void { + const index = this.selectedCards.indexOf(card); + + if (index !== -1) { + // Deselect + this.selectedCards.splice(index, 1); + card.setSelected(false); + } else { + // Select (limit to 3 for passing phase) + if (this.selectedCards.length < 3) { + this.selectedCards.push(card); + card.setSelected(true); + } + } + } + + private onWindowResize(): void { + this.camera.aspect = window.innerWidth / window.innerHeight; + this.camera.updateProjectionMatrix(); + this.renderer.setSize(window.innerWidth, window.innerHeight); + } + + private animate(): void { + requestAnimationFrame(this.animate.bind(this)); + this.renderer.render(this.scene, this.camera); + } + + public dispose(): void { + window.removeEventListener('resize', this.onWindowResize.bind(this)); + this.renderer.domElement.removeEventListener('mousemove', this.onMouseMove.bind(this)); + this.renderer.domElement.removeEventListener('click', this.onClick.bind(this)); + this.renderer.dispose(); + } +} diff --git a/web-clients/hearts/src/main.ts b/web-clients/hearts/src/main.ts new file mode 100644 index 00000000..c883afb8 --- /dev/null +++ b/web-clients/hearts/src/main.ts @@ -0,0 +1,83 @@ +import { CardScene } from './graphics/CardScene'; +import { GameUI } from './ui/GameUI'; +import { HeartsGame } from './game/HeartsGame'; + +// Generate a GUID (UUID v4) +function generateGuid(): string { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = Math.random() * 16 | 0; + const v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} + +// Initialize the application +function init() { + console.log('Initializing Hearts Web Client...'); + + // Get canvas container + const canvasContainer = document.getElementById('canvas-container'); + if (!canvasContainer) { + console.error('Canvas container not found!'); + return; + } + + // Initialize graphics scene + const scene = new CardScene(canvasContainer); + console.log('3D scene initialized'); + + // Initialize UI + const ui = new GameUI(); + console.log('UI initialized'); + + // Initialize game controller + const game = new HeartsGame(scene, ui); + console.log('Game controller initialized'); + + // Setup connect button + const connectBtn = document.getElementById('connect-btn'); + if (connectBtn) { + connectBtn.addEventListener('click', async () => { + const inputs = ui.getConnectionInputs(); + + // Trim whitespace from inputs + const playerName = inputs.playerName.trim(); + const gameId = inputs.gameId.trim(); + + if (!playerName || !gameId) { + ui.setConnectionStatus('Please fill in all fields'); + return; + } + + // Generate player ID and use default server URL + const playerId = generateGuid(); + const serverUrl = 'ws://localhost:13992'; + + console.log('Connection details:'); + console.log('- Server URL:', serverUrl); + console.log('- Player ID:', playerId); + console.log('- Player Name:', playerName); + console.log('- Game ID:', gameId); + + try { + await game.connect( + serverUrl, + playerId, + playerName, + gameId + ); + } catch (error) { + console.error('Failed to connect:', error); + } + }); + } + + console.log('Hearts Web Client ready!'); +} + +// Wait for DOM to be ready +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); +} else { + init(); +} diff --git a/web-clients/hearts/src/ui/GameUI.ts b/web-clients/hearts/src/ui/GameUI.ts new file mode 100644 index 00000000..6c3dac8c --- /dev/null +++ b/web-clients/hearts/src/ui/GameUI.ts @@ -0,0 +1,94 @@ +export class GameUI { + private connectionPanel: HTMLElement; + private gameInfo: HTMLElement; + private messageDisplay: HTMLElement; + private statusElement: HTMLElement; + + private roundNumberEl: HTMLElement; + private playerScoreEl: HTMLElement; + private totalScoreEl: HTMLElement; + private passDirectionEl: HTMLElement; + private turnStatusEl: HTMLElement; + private connectionStatusEl: HTMLElement; + + constructor() { + this.connectionPanel = document.getElementById('connection-panel')!; + this.gameInfo = document.getElementById('game-info')!; + this.messageDisplay = document.getElementById('message-display')!; + this.statusElement = document.getElementById('status')!; + + this.roundNumberEl = document.getElementById('round-number')!; + this.playerScoreEl = document.getElementById('player-score')!; + this.totalScoreEl = document.getElementById('total-score')!; + this.passDirectionEl = document.getElementById('pass-direction')!; + this.turnStatusEl = document.getElementById('turn-status')!; + this.connectionStatusEl = document.getElementById('connection-status')!; + } + + public showConnectionPanel(): void { + this.connectionPanel.classList.remove('hidden'); + this.gameInfo.classList.add('hidden'); + } + + public hideConnectionPanel(): void { + this.connectionPanel.classList.add('hidden'); + this.gameInfo.classList.remove('hidden'); + } + + public setConnectionStatus(message: string): void { + this.connectionStatusEl.textContent = message; + } + + public updateGameInfo(data: { + roundNumber?: number; + playerScore?: number; + totalScore?: number; + passDirection?: string; + isMyTurn?: boolean; + }): void { + if (data.roundNumber !== undefined) { + this.roundNumberEl.textContent = data.roundNumber.toString(); + } + if (data.playerScore !== undefined) { + this.playerScoreEl.textContent = data.playerScore.toString(); + } + if (data.totalScore !== undefined) { + this.totalScoreEl.textContent = data.totalScore.toString(); + } + if (data.passDirection !== undefined) { + this.passDirectionEl.textContent = `Pass: ${data.passDirection}`; + } + if (data.isMyTurn !== undefined) { + this.turnStatusEl.textContent = data.isMyTurn ? "Your turn!" : "Waiting..."; + this.turnStatusEl.style.color = data.isMyTurn ? '#4caf50' : '#666'; + } + } + + public setStatus(message: string): void { + this.statusElement.textContent = message; + } + + public showMessage(message: string, duration: number = 3000): void { + this.messageDisplay.textContent = message; + this.messageDisplay.classList.add('show'); + + setTimeout(() => { + this.messageDisplay.classList.remove('show'); + }, duration); + } + + public getConnectionInputs(): { + playerName: string; + gameId: string; + } { + return { + playerName: (document.getElementById('player-name') as HTMLInputElement).value, + gameId: (document.getElementById('game-id') as HTMLInputElement).value, + }; + } + + public setConnectButtonEnabled(enabled: boolean): void { + const button = document.getElementById('connect-btn') as HTMLButtonElement; + button.disabled = !enabled; + } +} diff --git a/web-clients/hearts/tsconfig.json b/web-clients/hearts/tsconfig.json new file mode 100644 index 00000000..49ddc508 --- /dev/null +++ b/web-clients/hearts/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting - relaxed for generated code */ + "strict": false, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + + /* Path mapping */ + "baseUrl": ".", + "paths": { + "@generated/*": ["../../generated/typescript/*"] + } + }, + "include": ["src/**/*"] +} diff --git a/web-clients/hearts/vite.config.ts b/web-clients/hearts/vite.config.ts new file mode 100644 index 00000000..d559f30b --- /dev/null +++ b/web-clients/hearts/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import { resolve } from 'path'; + +export default defineConfig({ + resolve: { + alias: { + '@generated': resolve(__dirname, '../../generated/typescript'), + }, + }, + server: { + port: 3000, + open: true, + }, +}); From bc56cf4edd1b457ee9fa6bb567091aa2d16d58bb Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 12:39:38 +0200 Subject: [PATCH 08/26] wip --- .../typescript/bullshit/BullshitClient.ts | 112 ++-- .../typescript/chatroom/ChatRoomClient.ts | 20 +- .../crazyeights/CrazyEightsClient.ts | 104 ++-- generated/typescript/gabong/GabongClient.ts | 112 ++-- generated/typescript/hearts/HeartsClient.ts | 68 ++- generated/typescript/idiot/IdiotClient.ts | 160 +++--- .../texasholdem/TexasHoldEmClient.ts | 108 ++-- generated/typescript/uno/UnoClient.ts | 92 ++-- generated/typescript/yaniv/YanivClient.ts | 56 +- .../Generators/TypeScriptClientGenerator.cs | 46 +- src/Deckster.Server/Games/GameHost.cs | 2 +- .../Games/Hearts/HeartsGameHost.cs | 56 +- src/Deckster.Server/Startup.cs | 2 +- web-clients/hearts/assets/bg.png | Bin 0 -> 3185 bytes web-clients/hearts/assets/bg_table.png | Bin 0 -> 657753 bytes web-clients/hearts/assets/club/10_club.png | Bin 0 -> 2664 bytes web-clients/hearts/assets/club/11_club.png | Bin 0 -> 2390 bytes web-clients/hearts/assets/club/12_club.png | Bin 0 -> 2607 bytes web-clients/hearts/assets/club/13_club.png | Bin 0 -> 2539 bytes web-clients/hearts/assets/club/1_club.png | Bin 0 -> 2599 bytes web-clients/hearts/assets/club/2_club.png | Bin 0 -> 2621 bytes web-clients/hearts/assets/club/3_club.png | Bin 0 -> 2658 bytes web-clients/hearts/assets/club/4_club.png | Bin 0 -> 2494 bytes web-clients/hearts/assets/club/5_club.png | Bin 0 -> 2603 bytes web-clients/hearts/assets/club/6_club.png | Bin 0 -> 2631 bytes web-clients/hearts/assets/club/7_club.png | Bin 0 -> 2507 bytes web-clients/hearts/assets/club/8_club.png | Bin 0 -> 2697 bytes web-clients/hearts/assets/club/9_club.png | Bin 0 -> 2647 bytes .../hearts/assets/diamond/10_diamond.png | Bin 0 -> 2549 bytes .../hearts/assets/diamond/11_diamond.png | Bin 0 -> 2291 bytes .../hearts/assets/diamond/12_diamond.png | Bin 0 -> 2489 bytes .../hearts/assets/diamond/13_diamond.png | Bin 0 -> 2433 bytes .../hearts/assets/diamond/1_diamond.png | Bin 0 -> 2468 bytes .../hearts/assets/diamond/2_diamond.png | Bin 0 -> 2552 bytes .../hearts/assets/diamond/3_diamond.png | Bin 0 -> 2538 bytes .../hearts/assets/diamond/4_diamond.png | Bin 0 -> 2313 bytes .../hearts/assets/diamond/5_diamond.png | Bin 0 -> 2479 bytes .../hearts/assets/diamond/6_diamond.png | Bin 0 -> 2521 bytes .../hearts/assets/diamond/7_diamond.png | Bin 0 -> 2375 bytes .../hearts/assets/diamond/8_diamond.png | Bin 0 -> 2569 bytes .../hearts/assets/diamond/9_diamond.png | Bin 0 -> 2531 bytes web-clients/hearts/assets/heart/10_heart.png | Bin 0 -> 2612 bytes web-clients/hearts/assets/heart/11_heart.png | Bin 0 -> 2330 bytes web-clients/hearts/assets/heart/12_heart.png | Bin 0 -> 2462 bytes web-clients/hearts/assets/heart/13_heart.png | Bin 0 -> 2475 bytes web-clients/hearts/assets/heart/1_heart.png | Bin 0 -> 2547 bytes web-clients/hearts/assets/heart/2_heart.png | Bin 0 -> 2611 bytes web-clients/hearts/assets/heart/3_heart.png | Bin 0 -> 2576 bytes web-clients/hearts/assets/heart/4_heart.png | Bin 0 -> 2450 bytes web-clients/hearts/assets/heart/5_heart.png | Bin 0 -> 2524 bytes web-clients/hearts/assets/heart/6_heart.png | Bin 0 -> 2519 bytes web-clients/hearts/assets/heart/7_heart.png | Bin 0 -> 2422 bytes web-clients/hearts/assets/heart/8_heart.png | Bin 0 -> 2621 bytes web-clients/hearts/assets/heart/9_heart.png | Bin 0 -> 2548 bytes web-clients/hearts/assets/spade/10_spade.png | Bin 0 -> 2693 bytes web-clients/hearts/assets/spade/11_spade.png | Bin 0 -> 2446 bytes web-clients/hearts/assets/spade/12_spade.png | Bin 0 -> 2637 bytes web-clients/hearts/assets/spade/13_spade.png | Bin 0 -> 2584 bytes web-clients/hearts/assets/spade/1_spade.png | Bin 0 -> 2668 bytes web-clients/hearts/assets/spade/2_spade.png | Bin 0 -> 2661 bytes web-clients/hearts/assets/spade/3_spade.png | Bin 0 -> 2708 bytes web-clients/hearts/assets/spade/4_spade.png | Bin 0 -> 2559 bytes web-clients/hearts/assets/spade/5_spade.png | Bin 0 -> 2671 bytes web-clients/hearts/assets/spade/6_spade.png | Bin 0 -> 2657 bytes web-clients/hearts/assets/spade/7_spade.png | Bin 0 -> 2533 bytes web-clients/hearts/assets/spade/8_spade.png | Bin 0 -> 2720 bytes web-clients/hearts/assets/spade/9_spade.png | Bin 0 -> 2682 bytes .../{index-w1daCLpV.js => index-AWEoIZL7.js} | 351 ++++++------ web-clients/hearts/dist/bg.png | Bin 0 -> 367189 bytes web-clients/hearts/dist/card_atlas.json | 322 +++++++++++ web-clients/hearts/dist/cards.png | Bin 0 -> 82966 bytes web-clients/hearts/dist/index.html | 27 +- web-clients/hearts/index.html | 25 +- web-clients/hearts/src/game/HeartsGame.ts | 193 +++++-- web-clients/hearts/src/graphics/Card3D.ts | 307 ++++++++--- web-clients/hearts/src/graphics/CardAtlas.ts | 108 ++++ web-clients/hearts/src/graphics/CardScene.ts | 508 ++++++++++++++++-- web-clients/hearts/src/main.ts | 150 ++++-- web-clients/hearts/vite.config.ts | 1 + 79 files changed, 2088 insertions(+), 842 deletions(-) create mode 100644 web-clients/hearts/assets/bg.png create mode 100644 web-clients/hearts/assets/bg_table.png create mode 100644 web-clients/hearts/assets/club/10_club.png create mode 100644 web-clients/hearts/assets/club/11_club.png create mode 100644 web-clients/hearts/assets/club/12_club.png create mode 100644 web-clients/hearts/assets/club/13_club.png create mode 100644 web-clients/hearts/assets/club/1_club.png create mode 100644 web-clients/hearts/assets/club/2_club.png create mode 100644 web-clients/hearts/assets/club/3_club.png create mode 100644 web-clients/hearts/assets/club/4_club.png create mode 100644 web-clients/hearts/assets/club/5_club.png create mode 100644 web-clients/hearts/assets/club/6_club.png create mode 100644 web-clients/hearts/assets/club/7_club.png create mode 100644 web-clients/hearts/assets/club/8_club.png create mode 100644 web-clients/hearts/assets/club/9_club.png create mode 100644 web-clients/hearts/assets/diamond/10_diamond.png create mode 100644 web-clients/hearts/assets/diamond/11_diamond.png create mode 100644 web-clients/hearts/assets/diamond/12_diamond.png create mode 100644 web-clients/hearts/assets/diamond/13_diamond.png create mode 100644 web-clients/hearts/assets/diamond/1_diamond.png create mode 100644 web-clients/hearts/assets/diamond/2_diamond.png create mode 100644 web-clients/hearts/assets/diamond/3_diamond.png create mode 100644 web-clients/hearts/assets/diamond/4_diamond.png create mode 100644 web-clients/hearts/assets/diamond/5_diamond.png create mode 100644 web-clients/hearts/assets/diamond/6_diamond.png create mode 100644 web-clients/hearts/assets/diamond/7_diamond.png create mode 100644 web-clients/hearts/assets/diamond/8_diamond.png create mode 100644 web-clients/hearts/assets/diamond/9_diamond.png create mode 100644 web-clients/hearts/assets/heart/10_heart.png create mode 100644 web-clients/hearts/assets/heart/11_heart.png create mode 100644 web-clients/hearts/assets/heart/12_heart.png create mode 100644 web-clients/hearts/assets/heart/13_heart.png create mode 100644 web-clients/hearts/assets/heart/1_heart.png create mode 100644 web-clients/hearts/assets/heart/2_heart.png create mode 100644 web-clients/hearts/assets/heart/3_heart.png create mode 100644 web-clients/hearts/assets/heart/4_heart.png create mode 100644 web-clients/hearts/assets/heart/5_heart.png create mode 100644 web-clients/hearts/assets/heart/6_heart.png create mode 100644 web-clients/hearts/assets/heart/7_heart.png create mode 100644 web-clients/hearts/assets/heart/8_heart.png create mode 100644 web-clients/hearts/assets/heart/9_heart.png create mode 100644 web-clients/hearts/assets/spade/10_spade.png create mode 100644 web-clients/hearts/assets/spade/11_spade.png create mode 100644 web-clients/hearts/assets/spade/12_spade.png create mode 100644 web-clients/hearts/assets/spade/13_spade.png create mode 100644 web-clients/hearts/assets/spade/1_spade.png create mode 100644 web-clients/hearts/assets/spade/2_spade.png create mode 100644 web-clients/hearts/assets/spade/3_spade.png create mode 100644 web-clients/hearts/assets/spade/4_spade.png create mode 100644 web-clients/hearts/assets/spade/5_spade.png create mode 100644 web-clients/hearts/assets/spade/6_spade.png create mode 100644 web-clients/hearts/assets/spade/7_spade.png create mode 100644 web-clients/hearts/assets/spade/8_spade.png create mode 100644 web-clients/hearts/assets/spade/9_spade.png rename web-clients/hearts/dist/assets/{index-w1daCLpV.js => index-AWEoIZL7.js} (61%) create mode 100644 web-clients/hearts/dist/bg.png create mode 100644 web-clients/hearts/dist/card_atlas.json create mode 100644 web-clients/hearts/dist/cards.png create mode 100644 web-clients/hearts/src/graphics/CardAtlas.ts diff --git a/generated/typescript/bullshit/BullshitClient.ts b/generated/typescript/bullshit/BullshitClient.ts index d2aa9796..5da193b3 100644 --- a/generated/typescript/bullshit/BullshitClient.ts +++ b/generated/typescript/bullshit/BullshitClient.ts @@ -94,41 +94,41 @@ export class BullshitClientImpl implements BullshitClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'GameStarted': - this.gameStartedHandlers.forEach(h => h(notification.data)); + case 'Bullshit.GameStartedNotification': + this.gameStartedHandlers.forEach(h => h(notification)); break; - case 'PlayerDrewCard': - this.playerDrewCardHandlers.forEach(h => h(notification.data)); + case 'Bullshit.PlayerDrewCardNotification': + this.playerDrewCardHandlers.forEach(h => h(notification)); break; - case 'ItsYourTurn': - this.itsYourTurnHandlers.forEach(h => h(notification.data)); + case 'Bullshit.ItsYourTurnNotification': + this.itsYourTurnHandlers.forEach(h => h(notification)); break; - case 'ItsPlayersTurn': - this.itsPlayersTurnHandlers.forEach(h => h(notification.data)); + case 'Bullshit.ItsPlayersTurnNotification': + this.itsPlayersTurnHandlers.forEach(h => h(notification)); break; - case 'PlayerPassed': - this.playerPassedHandlers.forEach(h => h(notification.data)); + case 'Bullshit.PlayerPassedNotification': + this.playerPassedHandlers.forEach(h => h(notification)); break; - case 'PlayerPutCard': - this.playerPutCardHandlers.forEach(h => h(notification.data)); + case 'Bullshit.PlayerPutCardNotification': + this.playerPutCardHandlers.forEach(h => h(notification)); break; - case 'GameEnded': - this.gameEndedHandlers.forEach(h => h(notification.data)); + case 'Bullshit.GameEndedNotification': + this.gameEndedHandlers.forEach(h => h(notification)); break; - case 'PlayerIsDone': - this.playerIsDoneHandlers.forEach(h => h(notification.data)); + case 'Bullshit.PlayerIsDoneNotification': + this.playerIsDoneHandlers.forEach(h => h(notification)); break; - case 'DiscardPileShuffled': - this.discardPileShuffledHandlers.forEach(h => h(notification.data)); + case 'Bullshit.DiscardPileShuffledNotification': + this.discardPileShuffledHandlers.forEach(h => h(notification)); break; - case 'PlayersBullshitHasBeenCalled': - this.playersBullshitHasBeenCalledHandlers.forEach(h => h(notification.data)); + case 'Bullshit.BullshitBroadcastNotification': + this.playersBullshitHasBeenCalledHandlers.forEach(h => h(notification)); break; - case 'YourBullshitHasBeenCalled': - this.yourBullshitHasBeenCalledHandlers.forEach(h => h(notification.data)); + case 'Bullshit.BullshitPlayerNotification': + this.yourBullshitHasBeenCalledHandlers.forEach(h => h(notification)); break; - case 'PlayerAccusedFalseBullshit': - this.playerAccusedFalseBullshitHandlers.forEach(h => h(notification.data)); + case 'Bullshit.FalseBullshitCallNotification': + this.playerAccusedFalseBullshitHandlers.forEach(h => h(notification)); break; } } @@ -267,97 +267,89 @@ export class BullshitClientImpl implements BullshitClient { async putCard(request: PutCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Bullshit.PutCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async drawCard(request: DrawCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'DrawCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Bullshit.DrawCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async pass(request: PassRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'Pass', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Bullshit.PassRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async callBullshit(request: BullshitRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'CallBullshit', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Bullshit.BullshitRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } diff --git a/generated/typescript/chatroom/ChatRoomClient.ts b/generated/typescript/chatroom/ChatRoomClient.ts index 54115abd..20a7d0fe 100644 --- a/generated/typescript/chatroom/ChatRoomClient.ts +++ b/generated/typescript/chatroom/ChatRoomClient.ts @@ -35,8 +35,8 @@ export class ChatRoomClientImpl implements ChatRoomClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'PlayerSaid': - this.playerSaidHandlers.forEach(h => h(notification.data)); + case 'ChatRoom.ChatNotification': + this.playerSaidHandlers.forEach(h => h(notification)); break; } } @@ -54,25 +54,23 @@ export class ChatRoomClientImpl implements ChatRoomClient { async chatAsync(request: SendChatRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'ChatAsync', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'ChatRoom.SendChatRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } diff --git a/generated/typescript/crazyeights/CrazyEightsClient.ts b/generated/typescript/crazyeights/CrazyEightsClient.ts index 8d189f77..cc35b54a 100644 --- a/generated/typescript/crazyeights/CrazyEightsClient.ts +++ b/generated/typescript/crazyeights/CrazyEightsClient.ts @@ -84,35 +84,35 @@ export class CrazyEightsClientImpl implements CrazyEightsClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'GameStarted': - this.gameStartedHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.GameStartedNotification': + this.gameStartedHandlers.forEach(h => h(notification)); break; - case 'PlayerDrewCard': - this.playerDrewCardHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.PlayerDrewCardNotification': + this.playerDrewCardHandlers.forEach(h => h(notification)); break; - case 'ItsYourTurn': - this.itsYourTurnHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.ItsYourTurnNotification': + this.itsYourTurnHandlers.forEach(h => h(notification)); break; - case 'ItsPlayersTurn': - this.itsPlayersTurnHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.ItsPlayersTurnNotification': + this.itsPlayersTurnHandlers.forEach(h => h(notification)); break; - case 'PlayerPassed': - this.playerPassedHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.PlayerPassedNotification': + this.playerPassedHandlers.forEach(h => h(notification)); break; - case 'PlayerPutCard': - this.playerPutCardHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.PlayerPutCardNotification': + this.playerPutCardHandlers.forEach(h => h(notification)); break; - case 'PlayerPutEight': - this.playerPutEightHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.PlayerPutEightNotification': + this.playerPutEightHandlers.forEach(h => h(notification)); break; - case 'GameEnded': - this.gameEndedHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.GameEndedNotification': + this.gameEndedHandlers.forEach(h => h(notification)); break; - case 'PlayerIsDone': - this.playerIsDoneHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.PlayerIsDoneNotification': + this.playerIsDoneHandlers.forEach(h => h(notification)); break; - case 'DiscardPileShuffled': - this.discardPileShuffledHandlers.forEach(h => h(notification.data)); + case 'CrazyEights.DiscardPileShuffledNotification': + this.discardPileShuffledHandlers.forEach(h => h(notification)); break; } } @@ -229,97 +229,89 @@ export class CrazyEightsClientImpl implements CrazyEightsClient { async putCard(request: PutCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'CrazyEights.PutCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async putEight(request: PutEightRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutEight', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'CrazyEights.PutEightRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async drawCard(request: DrawCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'DrawCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'CrazyEights.DrawCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async pass(request: PassRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'Pass', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'CrazyEights.PassRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } diff --git a/generated/typescript/gabong/GabongClient.ts b/generated/typescript/gabong/GabongClient.ts index 79ca681f..d56cb900 100644 --- a/generated/typescript/gabong/GabongClient.ts +++ b/generated/typescript/gabong/GabongClient.ts @@ -74,29 +74,29 @@ export class GabongClientImpl implements GabongClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'GameStarted': - this.gameStartedHandlers.forEach(h => h(notification.data)); + case 'Gabong.GameStartedNotification': + this.gameStartedHandlers.forEach(h => h(notification)); break; - case 'PlayerPutCard': - this.playerPutCardHandlers.forEach(h => h(notification.data)); + case 'Gabong.PlayerPutCardNotification': + this.playerPutCardHandlers.forEach(h => h(notification)); break; - case 'PlayerDrewCard': - this.playerDrewCardHandlers.forEach(h => h(notification.data)); + case 'Gabong.PlayerDrewCardNotification': + this.playerDrewCardHandlers.forEach(h => h(notification)); break; - case 'PlayerDrewPenaltyCard': - this.playerDrewPenaltyCardHandlers.forEach(h => h(notification.data)); + case 'Gabong.PlayerDrewPenaltyCardNotification': + this.playerDrewPenaltyCardHandlers.forEach(h => h(notification)); break; - case 'GameEnded': - this.gameEndedHandlers.forEach(h => h(notification.data)); + case 'Gabong.GameEndedNotification': + this.gameEndedHandlers.forEach(h => h(notification)); break; - case 'RoundStarted': - this.roundStartedHandlers.forEach(h => h(notification.data)); + case 'Gabong.RoundStartedNotification': + this.roundStartedHandlers.forEach(h => h(notification)); break; - case 'RoundEnded': - this.roundEndedHandlers.forEach(h => h(notification.data)); + case 'Gabong.RoundEndedNotification': + this.roundEndedHandlers.forEach(h => h(notification)); break; - case 'PlayerLostTheirTurn': - this.playerLostTheirTurnHandlers.forEach(h => h(notification.data)); + case 'Gabong.PlayerLostTheirTurnNotification': + this.playerLostTheirTurnHandlers.forEach(h => h(notification)); break; } } @@ -191,121 +191,111 @@ export class GabongClientImpl implements GabongClient { async drawCard(request: DrawCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'DrawCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Gabong.DrawCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async playGabong(request: PlayGabongRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PlayGabong', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Gabong.PlayGabongRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async playBonga(request: PlayBongaRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PlayBonga', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Gabong.PlayBongaRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async pass(request: PassRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'Pass', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Gabong.PassRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async putCard(request: PutCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Gabong.PutCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } diff --git a/generated/typescript/hearts/HeartsClient.ts b/generated/typescript/hearts/HeartsClient.ts index 2b7126be..8b822116 100644 --- a/generated/typescript/hearts/HeartsClient.ts +++ b/generated/typescript/hearts/HeartsClient.ts @@ -86,38 +86,38 @@ export class HeartsClientImpl implements HeartsClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'GameStarted': - this.gameStartedHandlers.forEach(h => h(notification.data)); + case 'Hearts.GameStartedNotification': + this.gameStartedHandlers.forEach(h => h(notification)); break; - case 'PassingPhaseStarted': - this.passingPhaseStartedHandlers.forEach(h => h(notification.data)); + case 'Hearts.PassingPhaseStartedNotification': + this.passingPhaseStartedHandlers.forEach(h => h(notification)); break; - case 'AllPlayersPassed': - this.allPlayersPassedHandlers.forEach(h => h(notification.data)); + case 'Hearts.AllPlayersPassedNotification': + this.allPlayersPassedHandlers.forEach(h => h(notification)); break; - case 'PlayerPassedCards': - this.playerPassedCardsHandlers.forEach(h => h(notification.data)); + case 'Hearts.PlayerPassedCardsNotification': + this.playerPassedCardsHandlers.forEach(h => h(notification)); break; - case 'ItsYourTurn': - this.itsYourTurnHandlers.forEach(h => h(notification.data)); + case 'Hearts.ItsYourTurnNotification': + this.itsYourTurnHandlers.forEach(h => h(notification)); break; - case 'ItsPlayersTurn': - this.itsPlayersTurnHandlers.forEach(h => h(notification.data)); + case 'Hearts.ItsPlayersTurnNotification': + this.itsPlayersTurnHandlers.forEach(h => h(notification)); break; - case 'PlayerPlayedCard': - this.playerPlayedCardHandlers.forEach(h => h(notification.data)); + case 'Hearts.PlayerPlayedCardNotification': + this.playerPlayedCardHandlers.forEach(h => h(notification)); break; - case 'TrickCompleted': - this.trickCompletedHandlers.forEach(h => h(notification.data)); + case 'Hearts.TrickCompletedNotification': + this.trickCompletedHandlers.forEach(h => h(notification)); break; - case 'RoundEnded': - this.roundEndedHandlers.forEach(h => h(notification.data)); + case 'Hearts.RoundEndedNotification': + this.roundEndedHandlers.forEach(h => h(notification)); break; - case 'GameEnded': - this.gameEndedHandlers.forEach(h => h(notification.data)); + case 'Hearts.GameEndedNotification': + this.gameEndedHandlers.forEach(h => h(notification)); break; - case 'HeartsWereBroken': - this.heartsWereBrokenHandlers.forEach(h => h(notification.data)); + case 'Hearts.HeartsAreBrokenNotification': + this.heartsWereBrokenHandlers.forEach(h => h(notification)); break; } } @@ -246,18 +246,16 @@ export class HeartsClientImpl implements HeartsClient { async passCards(request: PassCardsRequest): Promise { return new Promise((resolve, reject) => { const requestPayload = { - type: 'PassCards', - data: { - request: request, - } + ...request, + type: 'Hearts.PassCardsRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; @@ -270,18 +268,16 @@ export class HeartsClientImpl implements HeartsClient { async playCard(request: PlayCardRequest): Promise { return new Promise((resolve, reject) => { const requestPayload = { - type: 'PlayCard', - data: { - request: request, - } + ...request, + type: 'Hearts.PlayCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; diff --git a/generated/typescript/idiot/IdiotClient.ts b/generated/typescript/idiot/IdiotClient.ts index f38896a6..92ffc463 100644 --- a/generated/typescript/idiot/IdiotClient.ts +++ b/generated/typescript/idiot/IdiotClient.ts @@ -97,41 +97,41 @@ export class IdiotClientImpl implements IdiotClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'ItsTimeToSwapCards': - this.itsTimeToSwapCardsHandlers.forEach(h => h(notification.data)); + case 'Idiot.ItsTimeToSwapCardsNotification': + this.itsTimeToSwapCardsHandlers.forEach(h => h(notification)); break; - case 'PlayerIsReady': - this.playerIsReadyHandlers.forEach(h => h(notification.data)); + case 'Idiot.PlayerIsReadyNotification': + this.playerIsReadyHandlers.forEach(h => h(notification)); break; - case 'GameHasStarted': - this.gameHasStartedHandlers.forEach(h => h(notification.data)); + case 'Idiot.GameStartedNotification': + this.gameHasStartedHandlers.forEach(h => h(notification)); break; - case 'GameEnded': - this.gameEndedHandlers.forEach(h => h(notification.data)); + case 'Idiot.GameEndedNotification': + this.gameEndedHandlers.forEach(h => h(notification)); break; - case 'ItsYourTurn': - this.itsYourTurnHandlers.forEach(h => h(notification.data)); + case 'Idiot.ItsYourTurnNotification': + this.itsYourTurnHandlers.forEach(h => h(notification)); break; - case 'PlayerDrewCards': - this.playerDrewCardsHandlers.forEach(h => h(notification.data)); + case 'Idiot.PlayerDrewCardsNotification': + this.playerDrewCardsHandlers.forEach(h => h(notification)); break; - case 'PlayerPutCards': - this.playerPutCardsHandlers.forEach(h => h(notification.data)); + case 'Idiot.PlayerPutCardsNotification': + this.playerPutCardsHandlers.forEach(h => h(notification)); break; - case 'DiscardPileFlushed': - this.discardPileFlushedHandlers.forEach(h => h(notification.data)); + case 'Idiot.DiscardPileFlushedNotification': + this.discardPileFlushedHandlers.forEach(h => h(notification)); break; - case 'PlayerIsDone': - this.playerIsDoneHandlers.forEach(h => h(notification.data)); + case 'Idiot.PlayerIsDoneNotification': + this.playerIsDoneHandlers.forEach(h => h(notification)); break; - case 'PlayerSwappedCards': - this.playerSwappedCardsHandlers.forEach(h => h(notification.data)); + case 'Idiot.PlayerSwappedCardsNotification': + this.playerSwappedCardsHandlers.forEach(h => h(notification)); break; - case 'PlayerAttemptedPuttingCard': - this.playerAttemptedPuttingCardHandlers.forEach(h => h(notification.data)); + case 'Idiot.PlayerAttemptedPuttingCardNotification': + this.playerAttemptedPuttingCardHandlers.forEach(h => h(notification)); break; - case 'PlayerPulledInDiscardPile': - this.playerPulledInDiscardPileHandlers.forEach(h => h(notification.data)); + case 'Idiot.PlayerPulledInDiscardPileNotification': + this.playerPulledInDiscardPileHandlers.forEach(h => h(notification)); break; } } @@ -270,169 +270,155 @@ export class IdiotClientImpl implements IdiotClient { async iamReady(request: IamReadyRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'IamReady', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Idiot.IamReadyRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async swapCards(request: SwapCardsRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'SwapCards', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Idiot.SwapCardsRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async putCardsFromHand(request: PutCardsFromHandRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutCardsFromHand', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Idiot.PutCardsFromHandRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async putCardsFacingUp(request: PutCardsFacingUpRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutCardsFacingUp', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Idiot.PutCardsFacingUpRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async putCardFacingDown(request: PutCardFacingDownRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutCardFacingDown', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Idiot.PutCardFacingDownRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async putChanceCard(request: PutChanceCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutChanceCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Idiot.PutChanceCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async pullInDiscardPile(request: PullInDiscardPileRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PullInDiscardPile', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Idiot.PullInDiscardPileRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } diff --git a/generated/typescript/texasholdem/TexasHoldEmClient.ts b/generated/typescript/texasholdem/TexasHoldEmClient.ts index 39498c2a..479f5f90 100644 --- a/generated/typescript/texasholdem/TexasHoldEmClient.ts +++ b/generated/typescript/texasholdem/TexasHoldEmClient.ts @@ -88,38 +88,38 @@ export class TexasHoldEmClientImpl implements TexasHoldEmClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'GameStarted': - this.gameStartedHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.GameStartedNotification': + this.gameStartedHandlers.forEach(h => h(notification)); break; - case 'ItsYourTurn': - this.itsYourTurnHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.ItsYourTurnNotification': + this.itsYourTurnHandlers.forEach(h => h(notification)); break; - case 'RoundStarted': - this.roundStartedHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.NewRoundStartedNotification': + this.roundStartedHandlers.forEach(h => h(notification)); break; - case 'RoundEnded': - this.roundEndedHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.RoundEndedNotification': + this.roundEndedHandlers.forEach(h => h(notification)); break; - case 'PlayerBetted': - this.playerBettedHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.PlayerBettedNotification': + this.playerBettedHandlers.forEach(h => h(notification)); break; - case 'PlayerAllIn': - this.playerAllInHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.PlayerAllInNotification': + this.playerAllInHandlers.forEach(h => h(notification)); break; - case 'PlayerChecked': - this.playerCheckedHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.PlayerCheckedNotification': + this.playerCheckedHandlers.forEach(h => h(notification)); break; - case 'PlayerFolded': - this.playerFoldedHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.PlayerFoldedNotification': + this.playerFoldedHandlers.forEach(h => h(notification)); break; - case 'PlayerCalled': - this.playerCalledHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.PlayerCalledNotification': + this.playerCalledHandlers.forEach(h => h(notification)); break; - case 'NewCardsRevealed': - this.newCardsRevealedHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.NewCardsRevealed': + this.newCardsRevealedHandlers.forEach(h => h(notification)); break; - case 'GameEnded': - this.gameEndedHandlers.forEach(h => h(notification.data)); + case 'TexasHoldEm.GameEndedNotification': + this.gameEndedHandlers.forEach(h => h(notification)); break; } } @@ -247,97 +247,89 @@ export class TexasHoldEmClientImpl implements TexasHoldEmClient { async playerBetRequest(request: BetRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PlayerBetRequest', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'TexasHoldEm.BetRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async playerFoldRequest(request: FoldRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PlayerFoldRequest', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'TexasHoldEm.FoldRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async playerCheckRequest(request: CheckRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PlayerCheckRequest', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'TexasHoldEm.CheckRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async playerCallRequest(request: CallRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PlayerCallRequest', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'TexasHoldEm.CallRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } diff --git a/generated/typescript/uno/UnoClient.ts b/generated/typescript/uno/UnoClient.ts index b531a44c..71861557 100644 --- a/generated/typescript/uno/UnoClient.ts +++ b/generated/typescript/uno/UnoClient.ts @@ -69,26 +69,26 @@ export class UnoClientImpl implements UnoClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'GameStarted': - this.gameStartedHandlers.forEach(h => h(notification.data)); + case 'Uno.GameStartedNotification': + this.gameStartedHandlers.forEach(h => h(notification)); break; - case 'PlayerPutCard': - this.playerPutCardHandlers.forEach(h => h(notification.data)); + case 'Uno.PlayerPutCardNotification': + this.playerPutCardHandlers.forEach(h => h(notification)); break; - case 'PlayerPutWild': - this.playerPutWildHandlers.forEach(h => h(notification.data)); + case 'Uno.PlayerPutWildNotification': + this.playerPutWildHandlers.forEach(h => h(notification)); break; - case 'PlayerDrewCard': - this.playerDrewCardHandlers.forEach(h => h(notification.data)); + case 'Uno.PlayerDrewCardNotification': + this.playerDrewCardHandlers.forEach(h => h(notification)); break; - case 'PlayerPassed': - this.playerPassedHandlers.forEach(h => h(notification.data)); + case 'Uno.PlayerPassedNotification': + this.playerPassedHandlers.forEach(h => h(notification)); break; - case 'GameEnded': - this.gameEndedHandlers.forEach(h => h(notification.data)); + case 'Uno.GameEndedNotification': + this.gameEndedHandlers.forEach(h => h(notification)); break; - case 'ItsYourTurn': - this.itsYourTurnHandlers.forEach(h => h(notification.data)); + case 'Uno.ItsYourTurnNotification': + this.itsYourTurnHandlers.forEach(h => h(notification)); break; } } @@ -172,97 +172,89 @@ export class UnoClientImpl implements UnoClient { async putCard(request: PutCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Uno.PutCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async putWild(request: PutWildRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutWild', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Uno.PutWildRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async drawCard(request: DrawCardRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'DrawCard', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Uno.DrawCardRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async pass(request: PassRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'Pass', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Uno.PassRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } diff --git a/generated/typescript/yaniv/YanivClient.ts b/generated/typescript/yaniv/YanivClient.ts index ac9ccba2..de3e723d 100644 --- a/generated/typescript/yaniv/YanivClient.ts +++ b/generated/typescript/yaniv/YanivClient.ts @@ -62,23 +62,23 @@ export class YanivClientImpl implements YanivClient { private handleNotification(notification: any): void { switch (notification.type) { - case 'PlayerPutCards': - this.playerPutCardsHandlers.forEach(h => h(notification.data)); + case 'Yaniv.PlayerPutCardsNotification': + this.playerPutCardsHandlers.forEach(h => h(notification)); break; - case 'ItsYourTurn': - this.itsYourTurnHandlers.forEach(h => h(notification.data)); + case 'Yaniv.ItsYourTurnNotification': + this.itsYourTurnHandlers.forEach(h => h(notification)); break; - case 'RoundStarted': - this.roundStartedHandlers.forEach(h => h(notification.data)); + case 'Yaniv.RoundStartedNotification': + this.roundStartedHandlers.forEach(h => h(notification)); break; - case 'RoundEnded': - this.roundEndedHandlers.forEach(h => h(notification.data)); + case 'Yaniv.RoundEndedNotification': + this.roundEndedHandlers.forEach(h => h(notification)); break; - case 'GameEnded': - this.gameEndedHandlers.forEach(h => h(notification.data)); + case 'Yaniv.GameEndedNotification': + this.gameEndedHandlers.forEach(h => h(notification)); break; - case 'DiscardPileShuffled': - this.discardPileShuffledHandlers.forEach(h => h(notification.data)); + case 'Yaniv.DiscardPileShuffledNotification': + this.discardPileShuffledHandlers.forEach(h => h(notification)); break; } } @@ -151,49 +151,45 @@ export class YanivClientImpl implements YanivClient { async callYaniv(request: CallYanivRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'CallYaniv', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Yaniv.CallYanivRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } async putCards(request: PutCardsRequest): Promise { return new Promise((resolve, reject) => { - const request = { - type: 'PutCards', - data: { - request: request, - } + const requestPayload = { + ...request, + type: 'Yaniv.PutCardsRequest' }; const messageHandler = (event: MessageEvent) => { const response = JSON.parse(event.data); - if (response.error) { - reject(new Error(response.error)); + if (response.hasError) { + reject(new Error(response.error || 'Unknown error')); } else { - resolve(response.data); + resolve(response); } this.actionSocket.removeEventListener('message', messageHandler); }; this.actionSocket.addEventListener('message', messageHandler); - this.actionSocket.send(JSON.stringify(request)); + this.actionSocket.send(JSON.stringify(requestPayload)); }); } diff --git a/src/Deckster.CodeGenerator/Generators/TypeScriptClientGenerator.cs b/src/Deckster.CodeGenerator/Generators/TypeScriptClientGenerator.cs index 4d34d36e..e830df7f 100644 --- a/src/Deckster.CodeGenerator/Generators/TypeScriptClientGenerator.cs +++ b/src/Deckster.CodeGenerator/Generators/TypeScriptClientGenerator.cs @@ -158,10 +158,10 @@ public TypeScriptClientGenerator(GameMeta meta, string moduleName, HashSet h(notification.data));"); + Source.AppendLine($"this.{notification.Name.ToCamelCase()}Handlers.forEach(h => h(notification));"); Source.AppendLine("break;"); } } @@ -209,24 +209,30 @@ public TypeScriptClientGenerator(GameMeta meta, string moduleName, HashSet {"); using (Source.Indent()) { - Source.AppendLine("const request = {"); - using (Source.Indent()) + // If there's a single parameter named "request", spread it and add the type + if (method.Parameters.Count() == 1 && method.Parameters.First().Name == "request") { - Source.AppendLine($"type: '{method.Name}',"); - if (method.Parameters.Any()) + Source.AppendLine("const requestPayload = {"); + using (Source.Indent()) { - Source.AppendLine("data: {"); - using (Source.Indent()) + Source.AppendLine("...request,"); + Source.AppendLine($"type: '{method.Parameters.First().Type.Type}'"); + } + Source.AppendLine("};"); + } + else + { + Source.AppendLine("const requestPayload = {"); + using (Source.Indent()) + { + foreach (var param in method.Parameters) { - foreach (var param in method.Parameters) - { - Source.AppendLine($"{param.Name}: {param.Name},"); - } + Source.AppendLine($"{param.Name}: {param.Name},"); } - Source.AppendLine("}"); + Source.AppendLine($"type: 'Unknown'"); } + Source.AppendLine("};"); } - Source.AppendLine("};"); Source.AppendLine(); Source.AppendLine("const messageHandler = (event: MessageEvent) => {"); using (Source.Indent()) @@ -234,24 +240,24 @@ public TypeScriptClientGenerator(GameMeta meta, string moduleName, HashSet= PlayerLimit.Value) { diff --git a/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs b/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs index 3c9e80b6..7c19b18b 100644 --- a/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs +++ b/src/Deckster.Server/Games/Hearts/HeartsGameHost.cs @@ -1,8 +1,10 @@ using System.Diagnostics.CodeAnalysis; using Deckster.Client.Games.Hearts; using Deckster.Core.Games.Common; +using Deckster.Games; using Deckster.Games.Hearts; using Deckster.Hearts.SampleClient; +using Deckster.Server.Communication; using Deckster.Server.Data; using Deckster.Server.Games.Common.Fakes; @@ -13,11 +15,63 @@ public class HeartsGameHost : StandardGameHost public override string GameType => "Hearts"; private readonly List _bots = []; + private bool _hasAutoAddedBots = false; public HeartsGameHost(IRepo repo, ILoggerFactory loggerFactory) : base(repo, loggerFactory, new HeartsProjection(), 4) { } + public override bool TryAddPlayer(IServerChannel channel, [MaybeNullWhen(true)] out string error) + { + // Call base method to add the player + if (!base.TryAddPlayer(channel, out error)) + { + return false; + } + + Logger.LogInformation("Player {PlayerName} joined. Current player count: {Count}", channel.Player.Name, Players.Count); + + // Auto-add 3 bots when the first human player joins + if (!_hasAutoAddedBots && Players.Count == 1) + { + _hasAutoAddedBots = true; + Logger.LogInformation("First player joined. Auto-adding 3 bots..."); + + for (int i = 0; i < 3; i++) + { + if (TryAddBot(out var botError)) + { + Logger.LogInformation("Bot {Number} added successfully", i + 1); + } + else + { + Logger.LogError("Failed to add bot {Number}: {Error}", i + 1, botError); + } + } + } + + // Auto-start game when we have 4 players + if (Players.Count == 4 && State == GameState.Waiting) + { + Logger.LogInformation("4 players reached. Auto-starting game..."); + _ = Task.Run(async () => + { + try + { + await Task.Delay(1000); // Small delay to ensure all connections are ready + await StartAsync(); + Logger.LogInformation("Game started successfully"); + } + catch (Exception ex) + { + Logger.LogError(ex, "Failed to auto-start game"); + } + }); + } + + return true; + } + public override bool TryAddBot([MaybeNullWhen(true)] out string error) { var channel = new InMemoryChannel @@ -30,6 +84,6 @@ public override bool TryAddBot([MaybeNullWhen(true)] out string error) }; var bot = new HeartsPoorAi(new HeartsClient(channel)); _bots.Add(bot); - return TryAddPlayer(channel, out error); + return base.TryAddPlayer(channel, out error); } } diff --git a/src/Deckster.Server/Startup.cs b/src/Deckster.Server/Startup.cs index 7c1a841e..1a3999ce 100644 --- a/src/Deckster.Server/Startup.cs +++ b/src/Deckster.Server/Startup.cs @@ -87,7 +87,7 @@ public static void ConfigureServices(IServiceCollection services, DecksterConfig { options.AddPolicy("AllowWebClient", builder => { - builder.WithOrigins("http://localhost:3000") + builder.WithOrigins("http://localhost:3000", "http://localhost:3001") .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); diff --git a/web-clients/hearts/assets/bg.png b/web-clients/hearts/assets/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..e818ae496edf4be959db0ce56890eef15dc47fe2 GIT binary patch literal 3185 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 Iyx-OT0h>;|@Bjb+ literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/bg_table.png b/web-clients/hearts/assets/bg_table.png new file mode 100644 index 0000000000000000000000000000000000000000..3f4ad90c1887886a4b06ae590d28749f8d67e025 GIT binary patch literal 657753 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
F>6a=-J&TqjV@YeNtYRA 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%0D(j*|voDK5 z6xLaAm>C#yUGvuj&Oz-gvR4mrak4o z=6eNKAt2dRxeVQFPI%1yyz=q_E3okx8JTi?WPr08<}e1#tlsz@!_eCt`o7It8o*DN zpZ=;XdN3d=?}W%gkW-+EjWq*o((`RlOqZ4DOz0O52fvtuc8 zOU^JGIkvV?Wzx%Qzpz3MJM8XT8Mem)wh20UQAd4gJ}oK4Ew`(#6A$$k$7{mUqJO5Z zcm6P8C#@!g2k6M8Y+dMIb=RnY$EWGuUZ(H19(@p~%|A7AT3#^5$ z7s#z@BQtA5koL1!<;YxIQ7_S(y1#aNUyLQ%lr(Ok0>wj#Xc$hV6g3;;;nS*BIGDA$ zs0%)4VO;&j&yE?i%;(p%F2t?x3f|x=|BiaYGMz2lJtU7PyrSOqNj&5A{KFlqm4HP` zIZa#NYdoJQrnU2RY9FIbJnR#&hkZTfEM9>2?)5^mZLWOr#fk2WUqW14^qk{`kBc_mFp*4QT*4bK5O&z9-ZC&uYUTO{i3zw7 z;29Ts)zok^2B{#ek2JWk2DyJXf$ZEFwKXM)x`rAOAX5PXr!P-5lg#g7IseK~m{Ryy zX7+;yT-|pM7bKb8H15mb+(wIN2V@~Ys0WKvkVcmQ0kABHZ2}QeMaJL~&ci@~F{A)6 z)o|ipI!iazUtXB5`mj(L2-5^3%z)%sm7+&BxVJgoRcW4{pXv$qzqj=E4jFVwQhWz| z8%LAeD+NU1^4saCrbdM3^A%TDKf`F;2EUM_{FcQRyy5$A3I1o}blb;{EpHFn9#nhq7d@3$Zp-fffrA`dxoubY2mlkAG$ zVH+65(>yxkJf$)7 z!Kb82o~5`~|a(ejB%J9?kR1k&TrPA@~7VT(v&LKPdP^rnv^;%2);}`hJ zoyT)T`oqho1AniR$Pp^$?1bm9-R0)#j`TnsY1EwR6GO!Ul1-Wco zjM{|8Y{j!8pR97A0-^1tGoUwPQ4<-9;})aU+%+PMH?K?`w5_iDX^=yEd#cPq*g-oH zJuyzIytOUPHDvj*`WE=^!+CXSQGReUCFqEhM*FK;;!zxpBJOy`w*X~~&}jpmS;>^g z`hA6=zSaSa>C1In8^iKAJS-@M`3FI13{Okl#-n0;%}23)n~}ivMB`uK4R6+E3AE`$ zeQJllCX&hNDZ53}58xiv8pt#Sve|vK*-|EF9XG<69SM1FL8V|rkNv#{byPoY-+Iy! zJO1Fb5Z7QQf=Q*xVBi$4t9g7k4VJK)dSH3yyJqqwm ziWEg{hiM9yOjH_)b4yL|_gM(_T}Cvxx>}w?Us3muzA1IGW6Cs7sw5@iicca5`(mY# zTA6LK0_OAZynl|wIzE+{rvwz+X3K>m!1|qiPR;*eTLnUx6;5C-26($j_I_PVw)lsh z79*-;jlqe2PM>oCOBWO}(6=87gu1bI$n-8`o9MfRsk#&j^>`%KkR4s9f`lq=R6*FW z)?M)CP8x)n3@AnCWH4paml9#migNqz!rPXOUJXwCei2J%Sq zJ7=Y7!(m-Noc@u)4+=yot9^#jjeH^)3DxWkE@_ijQMA40fcG#j6V*2K9f%+^^*h*| zS;#hCDP<%v2RUz!B#TO;FqQCyOmLUgH8Zfu@F@O4Pui3XqM0xgQ=aygfz7=hwXA+^ z!1X*XJx>{vVPu0>_+9OnuVuwI^g)S)=bCGSIm0r6#G5=o0_K|Vc%8gSe`dH5wmpN6 zT1hVYH0ELXZx<1o0x&F2+1-5@aT;63q$3ihra5Lwj*t%_kE5(D7GEZyn)7A0$mGMx9tPgGVZyuv+0-o(~%`1;pL(38*Op< z046R1Ah`t>v<^hg#xkz5IvqOv2kOtD{_6!2;u!=bP&PIqgoQ{6{rM4B%}-!tZXj-H z+am%LLx<2p9&i|g59zyb=n%{Qkv30|u8?E9-@RamnE%2=+SbGkUS_@V>&y`X+WIka zaIM%IT~Or@#6!osAfbMM_UZ25?k)C3DsJESta0Ev<)D2_6F`QDxy6?zAHtdBKS@jM z#S#sXo*G{W*w&q5W)SDnFkB_`Niyj){e@7j_D78>%AhJ%Crg!{l;S*R7gaS6U1{@` z+bkP;%O*!h#r(WIiL6KdAUR>vVsZaAx;JICYGmV|uOW#j#<8A~++(`Djr_yHY??J1 z&gT{NgB*2ZIv%b&_9e%^qdykg{)MR)59>MQ+oDx(vkk|=AtYKITbx;-{Z*wXIvwsg z{=8cVrVo`lXNTLva2X4#BUOq#BNlpvsLA@&9fIN|C`~=>m6_=+eb~l%DoM&`r2EJs zhu*>rvCU=z<4*K^YfwyPcBvu<I*JR@sKY>tYCvgoGCSJ#!st3;&OC^hO2co~<8*KRWvsOXaTZ8;rs zTvaM?{u?S@2X5Y0Av+!DkToKtPQ;6ISDtYPG`G{gK;#Dsq(asgf?yRLfnu1n7q^Kc z`cV((X+uuS9sHwDzcjFMX=NUW8n0x4)^`t#eALt%dXql`5!b1j?{iQ4K?|uH?{NFv zdx1l1NI;xeLP0yXNzL?3V2Myc?PpW&n)flLBE9lL*TL$=q<6z@+UBGNyrK3u3 z@xZ9f{i37$HJO__%c8sT%-eV#zuTh`k&AxHKx0@HK8M#B$F^t0N;W&|_pO0nwls9x zYJf@&!S7W-5S(lwvS%e4@*X!iW2=5Y(2(eUp|ll%2WHU+xr6IZ4f~mLQkQ z!snSOief`hG!HpG!8KwsXR0vOn&+lmP5skZH0%;seG-9k*TTc2O?uFtFOr{rtx^sh z6-9veV+k~*GoM-Mkrfp)*a+D!TR~ImlS9crJO8k(*m+Sh$Wsb2>r9H0`}|4iOuSuS zKbMq$gg&(?Vqt`Qu3gcJ?HJftva4&N41};mXzd+f21mmNRcR^nZVirONRZP4Kr4x0 zYhr*z8%TUqAM=Rg?)7NLIV2+i9Gzg6heZ!c1aosevr8ag;#6TZ(Z4&j0KEh@^O$@v z%IQ#F3%HG>b9AzC+xU}+W4r#^OC%PMDm}uJHCpm(L!rOb6yV5L8f`R#RDOBtb4ho3 zo9c5oh6=V7kW%synfaEcJFTz1r8d9!dAT(o^Hnd7q&a0(vD^kz7Kd9HOenR* z9Z|83X5PW_MxW`UT_}@>^tOU)n0=~0q4%!fVmWY5Xk5fij_?t!X|&KSl+Fx-Wwn|D z?35|9*5r07_XbPEzrTHi#gd;g<2OLGbW#i~MJcP?^ zpQqVV6OrfhlNoo$=8HYgm-vFGg;1sJ&G$@DSe!KzJWYj^ZwOA*R>kqYSD5?!`Ay=OYAx+AcPu3M9lP z*rX(%iovN}Pg{pqUxuFMno}?RB7#&T|6Dg-AxL-MGL!AQ7KXFFdKcTak^mue{Bf~8 zoSXu5jVJ+MuLKeDcJJmP>tya_2uui&SInH8)&weg{0(^ozzuJKJN(5ED0^#vz-%G% zH@5K#98@XatNvd?eH589(kX;qk`O5$Z}M`Y*F#Z$Gb*6DFgUt8frrbKCRmJ8eTcrE z%H2;}Lp;!!V?^`VGQC407kxX340pYuzI&xBa@s9LL(CZ8Tv6a|&Ja)J^>)GV&m*?p<%(AC_sr$7p+;+O5upyQZ9ib-O z%)94|RhV%CXRO+&V|!nq)N?dea*gfR@Hp$G_uh(KVR~aXVmPhU!xxM;sbD%yvpYi> zOZM|jk}e>%|#zeENj4nNR`!7YVN-RO(@pey>is~KJ}T%ECJky z1oxfcuBz51`E{0;hi#|_P~*e0EN3$bb#T|FD-A`SQLcD2rR8SNT$)KNc1k^kkyLnP z8S!@7Gf|hH*jjKx>C8Uen8@HyHt%+(X4OHvztIDWjK!9w9LOw(%>f?E)dMQ)?G$L? z#w6Rz>e>jN{s+2g1**($uI;<|4SG5Y0ZsfuN_Kgy`^B6hDsG#O7rpL0;O9{%9)TX5 z2q~%8eWF0#2YTPN**z}eYTeXl*=T;!=u+!tB+Lkwm;DvCSItCn`}@D@_2AM9q~+wa zc4Ce4VD#T5qXX+m@(yS>YOS}p#h zo~%O7!MPMKJIY2o(#v0mxhI8eOq7S!XWH`nZ_MzmtE(sJ7UScs>n#w-)PM5%#xIWd zVQ_twT|V|t<%hxH)+UZA3CkKJ{DD&*bqJQ9;DiDL4ubcOV#+`B&P&+HK4dgRdp0v* z20Z5;?(%h)ae|W)?N+5>VRX&U{=pMS`x)4i_9p?Yv8@(Ts`$=NHT1AhUL-gnhO`)- z%_h0cR41#D+69KuIOhL8VJ9))eA_GcAtF4Xq$x)ASA}BoEUBs)^BDniAVx1Zm++#x zV_dTkqT5`9O83ngEH+cl|I=&%>gKk_p^%Uoc8ABfo20X8*7rV1J0%S{nZb_@bq!9K z0kixjG2GSJ9>Eu}AzVluNFyDUjtayE34NE%l~a=J7yc~9p_rPDjXdsaqS^(%4F-jZwD>q(WgtR;}fr)<`TKq!ogsMi$p^Gk4%c1q0b?Jvv}VKtHynLKukGTqOp;yT7fXzWU?IRDiYO7y=3*)oBco>dsSf6VxClf&u{&%M-$2!R>1xwBTr|PV zUv|q|(Ugydi7{8&@{_OK!W7iUrJL4=FJ%h$kq;k6=9_0Q$-uNa19|ie6rKEm3kVjA z**HEiHDB9!CjPW98tgBFo^jS^j$8C?dDhRX*8Uy|FE5K4HcbViQZa`(ul^21qE#cG z%xsPczK6EqLyZg#)whc&h4>D~`Ywm-DR?SUDJE6t8MP|>uE;r0@6H@u=Bn}aqUl|5 zo772*n6La5zY84r7-Km^)G!)(S1G0(ic|`inF;NCCj=8)D~){W#%apnv$vc`oENqc-*44#=4?yJ zyf_XtrfR|&L~M|I#f%9HH}8K+0fK>r3~L&RB^6UR_(_S8l`<%IXlE<#qtF{lL=Dcj z@~>2e*M745sKGSl@=)@yUo?)N+wzyJYZN^vGJ$2+Q!}}>u>t&32P*#k zClEw_C$qbM3|h#Y5EzAihkc^p!Ca%UCn$GU>JoWQSSFy1f+vEeeqrk-U9}Z5J!Kvr z^p2-5n9V!sz3XYBn{{9#!$7Q`#i8gY*87_5jtsTU(0m}Nx;Uq9oI?xB^G_}$S|evE z#V$a#WVj1gwY@eyStHuB?3GkIS`=7V=80%NF?_y(dbjKNQJ1U>uJL8BhTu=`!sFQ) zo96MlF;JsTcm|)sjKqFgl3DBD)PZ)1RB!HIAltsmlQk-Ji32!pfr4S-_z56IdH=C?svm3`GI z_2N|3zO-C56q1&gp~3Z;HTsO2jwvqI9NpdDAIt{eTSB6KL4OMq#?W*oTf4+l(CcwJ{S$KU*xtj#;f4k3svf?^t=74 zAy|f)C660c?}q@3#uFIiWxy-NLKLp7CAW8{1q^E2X5~?G@#NLR%O8W-Sxo**`HF0; zn_!HrIT3Av>V8LVPB=tpE2RdvD1LIUiF`?!`zCQIK}k1DfJMM*^Z2-oS&1`Kg~EL( znk5;nCrw}T4#jIJe!rNL_+u1~ljR_JhRl!olEEt{8FLeO_|a@~O_y%M6xJWkwDG0+ zG{(o8G&JWu^b3N937k#$OpTt)~a65d)2cpUUyOE~b1 zQ>3K?Ui-z2-rN9XIz)oC?Iwz=6ic0nxIpl4Dr8MAKk~AN37%eVkT7>~0UWT!v>*a> zGt(=q2vGJ*{vJeh>={gR)g-)7eKN@5xtdLjls|+z2Eznx z8s?d{!zN-*_mh`)rQpGCNeh8tr#Fy_4bFcz#K__AF(+EKMgP8m+=Cp3W1G5WZbo?n z7$n?`1%;`0wj*+FT>@X3f6#&~+?apQGO6fKdlW)M-`zzrD1Y}HMCCnA0e#MTI-?kc zPEJ^SsWRSi@+b0;S{EGM5LUFDQCY@aKRH2l$4`k0TLVOdd%p{)3K zR@J364PoH;C((qn8&l~@258-x9fN{1XWY)q`dtAiUuwXk;On-r`hlFkW%I>l3j{`kalaUPBL4;xhEo@)}pOXRE! zzZ-#6{nqLNVkIk1TLWOcNi7ThlyF&MAtUGl2b}tSD2UqyMDj#`8 zDv_wPF;OX{^5|~H^_|A?LH5-Z#>7|Fz^1qFOLwu6_Q}WF^&# zPki&<54GjV3#8)2{F*e(w|MH_3FIDZVPt^auqL-Wcz?-rtPD4F@3;nhOtKHa42luK z_uJA-M*%nw+v-(V7g*~pgP%B@+Ung$Gs?T?+y`b;%Z^e zauJ^S-4$eyz!ku1avvVmUV5>c-q?YPA2jG}MX10N<=>uTN4;~2R!2}S%9iv&`SW-< zxBrd1&(p~h?#kctkMC*7)-KMkJ|FBBrUJN}l;l#vXI`IVPof`MkS-FaxbPGa49<#1 zN}|{18+ESwC!OeP#+f2TNi-iYl-qybPIxai{Hc|Dl*|;=zoHqVE)>?M|ETfRZf9?q zo~pyuZ5yFzTNI6Bq(2}zdR`e8-s=BEv;rg?9o*?4)^0=ZPS(kx=O_&w#+?R30ztzs zjh5`!Qv<&UN}D}P>?56UJD^6S?CD7z2F?ex_nl#)U4p0mlBtVZ0OVn z{TJxAFLI)rz=d4XB6E4h$ILka$1U(;SQ=eOGk(b_W7m!p`B&emfd7biHFeyylWp2Y z_{vdY{h-=>F0I z)W{8dr&)79a&*zl;zmf>d!^BxCOXr9JG4VTEVG~a1keon`nC(nuGkCz(D@nGrlTGx zI;E0{^}O2SwW*}^4WIUYDZIK{_`Nn(d)U?O)y&OT7>(s>F>ch?`Y6?{@a>7F-GG?- zz_n}MOfh1OE)Fdc$RJDwEiIa(FzS)24Z7xkFPl&_uwEll!HTNwIi3EYEl)&M?`T0g^i|vt48t zSh^JxGJH>?DhB0H7q=yDGb&MR$#eHrdD#4+=rqH=JR>SIoBB#UxEK5r6*YBBDGK^> zQ4f`yX3*GQXrfafY23$IyM@Y9_){I1*eK1s%E83)JP&_CtdG{m4ce|tr?)moZv|g5 zzHoodYoBqQ`%2Gn;i6d*Fi9DiIxDKs{ks={*b|BhjNYBPOFfnk7j=RGP{DX02CUg+ zxxtVO*-oF%cy;gH_b60?dLIPJCKI*`P^U2-KeaIdqclVlK6%6Msm}(LAJsrYbQ+RE zuwH*TK)yIZy<>L&;Ij7EU|0bRI~fC`1g*)e=^ikFSIeOCxm{-*SZ`Yf3JkL5G@{W% z9w&4ZS^gxZjlbuikb0OV3kv4q5Cub6M7{~(m$+L@{uJXKjqosV-u`si(yrGpv*)j* zMCJ8!B$xt5^A%EaXn3$qutdMk6*T)o`E;p8f8F#AQu!Qvt!*mPAMjYwwX(g$68M)= zY%PU)GA;gE`J>Wjd4j^+4_8xg@&xDYu}m>R@ss@qWmj~L_#Y3JM2*20C%Xg>K0P4# zC)320l;0p@E4;7vg_fj|31396mXGJH`L#pyoatURpuBx2o;j#0pH?d}6!Shci4Wpi z(ST!zcbG=KX{{#|?6{Ho*empv6ToUo9}XhX^0t^8y!u_DrE9eW3q*ZcgN z(&sMSiC9J*v)8E84N<|*h<}JD9(h@1*NmD)W837Rqr{%J3iKQ8I*s0JG?yeagWo|j zDAlJ!gnZ;4^nPCe0#saE8gT6a$b6Le-WtdRUkb0>Ay^#z^SBKdQCE{+Uv;h+k6vE_ zX<4o6qJpSwrvFBa!Gx`%e=wQj`Wx@(cnHx2hbNA_yT*OnQJ&O56Vlq2nc(A~^xX$D zo~$|txD1U_S;$-CH+w`UGqNspu!NY_zOJ7mgc|&ONAkK$AKbcS$UJ?*{J|+Ce znc~(Wgo~nUPk2?^o?6N*58sVIG@bvpVTcYVZMu_lKtrGBy)xmKvbZ>bVX8sq{9t>I zAj!)ecoqn`#i^IjZ@Y;pjGLq_%Z*$-~rF zHT9vnH7^4ZJAt=zjZxFQ>DSiSX&dgWPJMN|jU?w9MS_XUfr&V36t$xKG9y)XvM;(z zR<=4a7#QaW3PM^!cLOX8^WF8F6K$2C5z9a4%5yVS!kSH&1#RPx>X-1VgYh@{5 zu9zZtsCy6r2@Tk9jlPDXrzo|x8e$?T2j3ssQk(VRzxNl|tqg`SO>%Is0;B@BH57+V zLPR^gt%+#n{30?8SJa_p%bx_Ep1W!%HqqmOb?abpTM9gbY0j$MUeS5rY0BS(tRt=N zCU!r)RixLBmB#9;4LO!GRYzFo2*y|_bLsh-mu8Pxp(;wv;6Sz!f(`GQKA?1s=jCn$;DOW&TdHFN% zkkhiT@#TGUnQMo>y+MeJ8503fPr#)7GKg)zn?|cJBdzuqfjnKHv_IqP+>9Z<^>JRO zIiXCYFm&@;!fD;$9L6%Ude$HENsD~abuRS<{8rehgBpkC<7vFnS zC=GaJu;cy^Fn#&gpF?RZj5?X*``=}o2TAaTFC_*nT6`M{oYF*dZaxLWExrQfyt|c% zoSOx3_C?j#qibMM-%S_31}>3!Wqt$6#I)|Rc+=Abun0yjlUG--2i9GEr>`G0qj!v< z+t(zMnZ^e>3-EDX20lCZ2;sS2F>U9O3sWXzTmbt7>?0TW<47nDZHI$c*)rRe=tdRNP9OG&U= zCZ|ySj_r0F`VrzF}{R!o5g-)`9&?hNE1p_u(phF+3nn^A&W^M-CbDi6mu4ULIsl7WS^LvF( z?=rA~*BaG8<)g_s+^Z@kA=o>sm6d@DsxcdS&GKALjZsW>g;BKJY|Zwzl+3n97{XS_ zCyaCn6)>6zK_f2iRTx21lt=6=lTW@wiA#gXk)ri($~Vr>-37< zKODkme85<>^*I8<^>>9h`TYa%dKquH`|AQF;T;?`^iv>NFz1O~8W2J7%l#gaF zs-wOA24kC_@~Uj~i>WJ?L}s;5Qyc2jg=c!RP`zr`P38+@k>K7jpD90k%ya>cc=Lp1 z`Zr|wRPHV#8IbI-P33~Tq}5!qpg~MpkQh?X|x@6-0u}TG%RN zNFN*1MpKi1lQ&Bm1>D! zWE6mDfPALP&8(KTM9Hx@;^A9K!_`7?KdT z04mnc68`WRysGoq0xkjA7-+?GBa1m}@HQ?*_C+9F>_BMFaW4Qv&Lw_2qkIPL@LQ>S zyf-q=Cj}acR*XwJONnz{!Ar1@hRF%OiS~NXGJYd}!?D`*4EKMqGCxy#a81(PSE9J& zh;Vee_Y$<931Z^_cL9-C&Vllgj01DbfI8DPQUI}RqFBe|O@HcFUG89Z`wMInGRu+h z9!Ybn!rJ0D#Op?56G_ggF26rZMw2Q@>sJ5O)cJihyrPsg=9bEtuSomXQxCnqMTxU= zF_xr2m*$Ivs)>2Msxelfi2w?Jt3B(RTCTSi_^*^Xi#?oYnU?Tqy7K<9B&Eefu4mdV zvPi^1hvMj$Op;P82MQBo>&%3*+$@{&CB9{z^^a^=r%itC)x-od{IY%hutMUs#P7zc zjcGh#Z5v`8W3Za*u?uDV#mDxuuJN6!!J6=E=~lyJiR_#?jjV$_PGiJ5Qf{j?<$_O- zxLErQnT_OxAd>uxALU-ih5mFf{M4s`Ms6*p6UaRH7N+!V>&P8c18D~q@nn}R zeUTS1Z<(vk&MSA2%)MoXuWtb2oYyo&;NixGc{ia(ublehPu^muQNwwb!FnB{+J0sdy?P3{Lxa} zNLlAc0g7j?H)%dmSGQyNvc~h&)FP!3R9Xz(ciz4uzC52K?rRYuBDzpB$gCuJ#6}d) zxmMPpt`3y(N>4&N)hRwz?|eRzA>Mrj{Tb$KrqfhxH7Y=aMn-+AklUf^T-u`hhw1!s zBXfYw;hz$We%r9$FVm#zwU}gd&37aNWjv>oVY__(Z_DCU1p)mztv3iczorO+mLW6D z5iIFn(!QfSCL;m}rmNSrJT~8|c~(+urn9k|=G6VGG2Gmx7NOM#*Rn&(t$c^fqO<93 z=>m+S=C55IhsljXb0QI!8&wU@vd~^!hX90ab_j&4FnbR$?Fg{m{|j^wpoYZ0>F57S znp|{G18t@>5%zpvGWTc89~Tyk{j-{WhQWkP?B4m)Z-7PUi>jRU_YoP!o-#~nMyBmr z@}~a=%NQQDo(QHWi?r(vGb4k!(_WXD>EAffy%r&aBYkQtW>|sOUoNNCZJz{Wzv?eD!ytV9r?#%U%&aH zWn5PNynJ-~g4ar`^6F6Pa83EJrQ_?vF5AD8eRLk0FxSIhLyr&bM~#q~!l!Ec!?Ur` z$xALXgpUKXU7mh%c%-{Ybt4i2<+5=%D$492L2DmkdsuDCLV`?24qGvIG-{6Gw^E&|>bTn)K*#3l-BAw`Y&Jt7162^4bN(Lk@C2mlzzS81p(AuO7mxm0o6g`;{ME8i5* zJFytQlg{ypRq)N*RR$VYst72Pzx(6BstDB&;T$-uOMY`7kFnSe^*ir_IoP0V_WL`= z!a*RHuqEr@i1jx}tDhs0Tr9A?t?t@*B4b$$kU}=KT?ZC`o~_kV_EuYxcs{vgMX5$F zF)=)Kip2=FPo6>6=ggFz?AWRTVfl=ugwf~4{xz1r(9AESG#O&KX2^89WS6fs(|*bk zGxhDaLtED*<&OeQgviVep`Al%HQr!Wz>z%!lgOfecH07*{6cfwpp zrbH58vNSLc0S&t(xPzsJR>&su_V$OIl>kZaNY7NLh@C`Y>}j7!U9JL(v6nZ16Dc7F8) za_{H4t-m&fp3u!&0l$nid3nj++8-aD_SL;zbd?;y+oo_C`2c`bfdGfoMtxDAG0*8Z zr&HO`?VNEic5Apyj4rY43mRWl{I7$|#@?^gNK(}A ztyAa9oC4IR#jUtCy`qRFXCJ&8B4=hsYN1S*J}$RGk$w-ySdQeDWF5L@G`9vajbtxJ ze7l(F3ORjbuI)~;$iQM_Wk{8rfn_v}%`Z>{bGj#^?ZkLWxV1J8`Pt=*HE1=W>9H4D zV3#eqG`ZC~O8xb>lRufwShG_#EKMGfj?^enjxB`rPEbgnJLUC;Er)n7^bD{rFT*F! z=h&0|1s}DV?xX&59Z*log8LCRz~O}e^#tfT)&6)?p8G@w z??;1Cnv$W*pv@6d+22g|>>ZroqOOuwKR+-OBoR$acuE%*BS3d6(oO>&+nKwgdsu`P z8k#fRkPNl49$MRtrEhUAXq?NZCEDe?smwZY=Pn>@@*sKIiu1I^bf6rSvy21(hdju{ zIEDTBMTlqb3h|<`HPIUWgT`Df3}@v%dCyB_g-Cv}FKC`;sHFLAL0hgV3@RZy5OhfKGjxEPR%i4j9rS_C{Vn1) zC?3Ah@%3Fti;7i3ct_OqUTmL7@)Knsq-0;g1mJBr(ED!saKqT2FO7h%MO(#4ole0W zKc)Zg1^5X2Y2}%y>XYoP&z&BJGM)kWf8_>>*8u8CqUys9fWkrM#Y=?N!3?8`Uul^I zAV4p#VDF8{|7Q^haMIr-;Z`+lD0_s%Pxhf ziu7+C`371GDBbv*WBOv1c)2XPjWioIU$BvfPO6;Wj>PX9vti5%V*l9>7#1i$gvqIS zMTGbU@62<<4S8bXuQc1U?T^9`?_*?{Z>NGucdV1kCb}TQo4X@Ow$Sbxp)AjWQV$D^ zW%5>4Y~;9g4@BLCuqJP9{#NLbWbpQ|jfF+bqgmhAVOT9sE^IKC9C=qqL%n93E6yN&%XRt>To|9E*$QHeb*1=MI8PHm@ z)lC@<;nGyPB98zRBlNYmZHK@IjgDV$FI7P@-OV^r!fh=^q;Mo>uEr`+3OI9(2nj&7 z4VAA4pe)Ed(aj7d!o8i}cjjeG^s%i%`TF>=)YwG;;roUM!~+Y)HPI9UPIdGBFD&@x zF5+Ak`^RHLPp}gZy8oUXI_`V{i~qV4?YH^i7^1Y;uswhX1Z)+$*9zvTs<| zj7oz8+G<%goPd+Cfa(Szjd_f2Wrz1h!uHl-AixQcl!_^nWO{+bC|lsRWQb*mkafIM z83i+<$o7Qlt9=Fude37i*X9hR0XC4gIg9-jDaWTGjvolq~LRB{EBx`52Xnawl`#zAstcs$esLcgDU*q>oH zTh7ni06l{Q$+0FDA|{b_2M9?}n&dw1{{-W7eNg5!|KwSeeY?(H#0NYds!FWPbG-^mK!!eCBIE`bcqipYe~PCKAXgxh7z? z18vYeQ5%6maVyI3a19-vO}rSA)Wh|KMC&YRIb+~# zUztq=Q*2cBk#*>lEG#UNqIvAN-@M86(8X6&K)<@zY&#*NL|NB&u1os6pI}|Zm!e#{ ztVFumDdc3!ZR0`{Wv5o^yhs?a&a_GGg>`@l-fZ%fE?hLKmn+I2eE(AyI3S2F@_8qm2a>7Y8X$FohW+ zdamIupQG=qt|w#+o9T--^E9h4Lgs|=ajaqNShnF0(;RpxnYZ;H-Ie#52eX)aA)GUH zCjseR`uYP`+F1N?e~;`CTPt)M8d0O zyvIYB9F9~Z6<-sEKwBg?%3Q;SBi*G4J&gb(aJVZPdo#oCfA1E6k8L*WpS=F7Ddr%Z z10l%vewil^RHpl+?IL0gAm*YT&mIP3Lv4;h^PO&%#35=fMCFIvGd1B+=X5omw#5zt<4{_f=^zJwu0XO-(5A)a%XBq6D0Av#Aq;885fZc@++c1}f0Q+ROL$Y#kGL689T?75s+#2k?m z95{GeF5)A6pjO={$^rNNCS*v;Bl-Yp!YMcT(iay-&}e@SJYC?J%jb;@dqas}g<6^J z2IoWr#m93w?(`I6A7M%WbM5nqNnQ9goWru=rwm~DX_3FObPir6aoXQR0vwIz4?IL* z*tKf!cAnBeu@Q%D{lNAwP?j`#cMi^;*c`h01Z|cvS!OXECTazxi-{Wuf0Jl<_;=a_ zL51ga8prRC;t&&Er)&2{@DncANQXw=Y0B1TnlurAtw=z^~!n5PL$$v*#1@i!#*8#9#IrKH-KQeP1@K@nsfBkq@P0u za|#xJBO14jksuk&$P>)0*vqHy(-_-`yD*V{zca?j+F*yY3WB7#D%p-~=GMP?oS6PV zE}c~19MPqvM&zHHua@GPn>WN)#FECT@~XCkL^zg{;`;8ZE@QvGh3>veapt?Ne~}ED z!c0N9sd?(i}!QlDh(ws69p?I@L|N4;-YGo6o z3#deft3&xaKmWcd)cjU;F9D`Nw!^*$eeMTbzIkUhyHiXaE;yn6n+g|Rt==dwt~aeq zK%f`Y)<)1?Q?EPC~Xn)^V?NmQ}m^(UhJi-Cw{?ccA zznr(1FgzZ&PQ;iLgTcJvk3u0tXt9a>&YRiV$^Y*bW&k@BuU%U`aximuDKx!UZPE-< z>-DIpgl*T`lvMRan6k(9AEs#~aHae&ko3@e{Dm2t)4y$Z__1d=_tAjcGWiS$n4*QwjJP<+ZM4L&0S*I!$L??(YfmcT@Dd=Q~ z^e3<$-C{*zlva#HK#uNRiib9etCf!Jn!D7>!+kYWhLPIbx{19z>*N@>CqX0mri~N* zK2z*uBq%fW`x`|b!Ug6R>2{+|PSZb}L{o-eu8_hmjnWN9Vx|g&yxcRpd~|F#xVUq9 zMlyj)Q56qe2i}k6#8R{sjW1mLA-c9vO{!K}wz}9$L+HXd@JBZe2fOwUZ0iLa$DQTs zIq2}?zb>`!PwGI9%7MPkS(4Ib(E)wD5LQ_D&$tR-+N{Vkv>fd#x9 z1rCYkqVaoMM}I&kH35j1<^_wr1z?;P_s75&=3kSZ>G})9xYkRabK08q5;o`J(aEW3 z>fOfdPZs^gYb}5AI`XqGYYDBXTA*Pbeis5QBpnYO?-B15|KmTdb;u5!+VWdVvI8wVveYmXC zDWE07gd`;Jif8o_bEMe0JqyC zpph6c&b`G#&o0ydSp79Tev3I;owgKQ1l7FEIuc(dk5mjYi^C4Rs(B-v6t1z#`8RUE z0yz*}T!+LlWpV~4{ZWAvzam_yU=Ek)hIPFv6h#cyU!MmWmmVJ&-`zCoJpOach{O4s1gyOEetR5zXX`&OZ#NCmu?##wPC9(3at}^OLk~mf1 zrhl3=qWJN z;$P#6gK5+JvJX>PA%{QZlS%j~S8I<*my4X%XYwvOY9KLgwdfK^skxTsc9FDDPU#CS z*3mfJ&yd?youS439^{*&ChD!SQN^MaJu6AH;Otlh-d`}tBC}pXuO^MiC~01KeA+Jd z(or#eblAWLTDIfr`lWBlia(MAm8FQo7q8J&9_UIl(WjpdP7e09wnUz4(p;qUER~dT z6_C5JN|&|OQX0~#APaPxqUggGRq=n<^o*SSmO2|+^Bj#!TBEdz#PZpSnZHM$ORfnH z2=(r>u{E}qLBGUsquQ_GnsqP12D~y~=c+8=?<>|IgF1Mk1CF%#s?yS3=;d+3^Y^u2 z-NyLtR`XRE|7KoJB=}FkAlSOFB;Q`FRbC5uefGd90gLO#+gV>jo%j5KtwZ?&S|vW; z7OEt4oXes|kR?pFjXBKbz4V2fnOlE+c;bX+Sm&4c6T@HrRjxj*F!k}4f-=-T-t!5L zvIG5JT`O~bfP^FdrMqQzX9yxUbM4!&kL-X$;8M&6^ob5;5{_fQYV;adQ2+yXYw`WL z6b=VKaR!wAt9l&`^zYe?mj{Td`wpf%`U(DC8OU>K-`_Dny~7kByVhWlH0_8Hb~9o6 zCjaM97wFEPmS&#LhbYjv+;{F5GNPpLv2i?pmMQ!{C>Faz+O%3*Sg<(t$pS5S;$l1_~&0S15 zJyItfCqkdeGKI4SXKs#GDk+ZjwWN@Vz>A7s+T=OktmWT2nZz7o`&KBgRb)1PnnXzz zYh3##snn}V*e@HW*T0P;lg)r#OAY4g6K3R&(KqO|#9k#^l7?KXsL!@fzGtGYz^ZP> zNumy+HV=MZRI~?+Iek(6-r)z?MH1>rGE>^u4!E$gxuSsfq6XKiMhwT}hY>}pZD#*J zo=6;fG219#&e2Ca7tpBmz{+uG*KMseiYQ3V&7*;`os>alngkmr#755B(k|8EEh4@A z7K5Y6Jf@Y-xmV?!%9h=ojsrvco54+`v)v&>pZ@-&7eKzR9YoKaN+v5I_E}5)r}_;W z>CgVp;{K1fMWA;g347_|;26pK+JkJwCMc!r48vOw^f~t#w&S4zjYZsn_zXo5994EE z!g*yykGDX(Pri%Ma|j~I$A-=@hZsJp;~W2}*9tIee|AzMz8wUVB6|VJJpO$iwujA3 z%OAO5$X8ecS3qrl$3^|>z6^Za=wdXL_6CG;Sw8L}3}pP{s`zL9yZLDtv>S{7KFHJB z^LdwmZ|E}y>M~~L%s;-9@O#9dx&8Of((c*1@f=&2JOWDbWUz%v#&59}=zCEh=b#b0%=Vjm<`LRwF2$Sg_;7~?RVvewWitOb@*NNh2TT^+{(78TpMQ)i2Ln zWvy8SSl6d8shM`X@0TE+7ude&b$m7@{6O~c2iAQ0#qZs!_dk|ZD_LLgaJ4>Hz+1tj z@D3wy6?Ug&SZ63A6Ln4yzy}F3(6T`@@OFk`I(T95k?oi-%b9S_aL(rwa^=ymI+1 zDAV6o7#ssHgkwJGR7_%-Yw9RYYNL7>`Y|)L5zzR^2VcGL-WQmviCq*MONjIPXwRp5*91%QAeRZ?t;& z6TQl831A+dJOe!8b93X$Lmh6vVLjtzjX-Y#XvX^twrpABhPIM+cEE^Qd@AdrLGNDJ z<=T)VTW()*Ux0|VO9;wv&$;hykUn{`|54=gA{0GDN-?*g^-9ZZIf}1$=~2bqHvbx% zfOUQ(wbp(ol*EaGpu^D>sRtEqBFb;hIP6aLm)B-`j=Lzlhua%H1CRDc?AVl`C5jm* zX&cW-rQPqix;pS66fQozJ3%J44p^hOOBNlk;O<1M@@@(sW3L*cQXx02@Oto}%(mKh z@+^-BlUjwQ?hK(IX^-JK?2i6Jx9eJ&aL5cwgydU`y3~iDOF^Ol66|89Stjk_uUT!m zUSVaw=1xjZ^EF;9r2e?XG}KYW{6|+Yu#H`DXM-D*$&*q`pvpcxxQHlb*%ibX_U-<< zi*Ue6bYCFq9Y(;qALAR1iwIf4BU!2d2kae4u26$ytvSsnM_GkjUt2I2}inZ{6P% z?-|z)$shRcK*7T;fD&lziI-78OkF?gq{$=^nd|sV&;wflo_KvVnfyCjO;`t) zkX6V4Cf-e2zJR1Mn9D~6RSi-rWwa!VN7b42mX;kI55#;-Vj#xWwRpv>Y78qzO%4U|C`>V?eQs%FC*ViF@+}c5L3Al4SL+xi zQwQds?6bkohXifD`q=0zCg&TuX@x$_1$A=cKlx*4|8$Zl z)6T1Zd+TmvxLA(9S>Hb)S>&u<(JI@ds}o#f($1;s7z9};`D}_mgw#$1EYAe2BAtRT zyaCL<6Zg*AW^%4Gdkzr{`{NIQH~#t*4=rnZ0cy*oWih(b z*(5U{CxNw%;L(?T{HkpUY-PD5ON$h{AJ8LO-WlEgBj&X*6!`Jewb@>v^*5eE2ijgb zqZ__eK#wJL4C-udAAX(@Z#BleG^gCODzv~*7NJoLEKMDabeIN^D;TLZB2db^0@ zSocw{V@06FK?aod-ENcbj>YW2T1Mg;7t!t8dHJ_dsecB`@$!UsAlYcxFTDaRy7t>v zMIV42=NITSMl;`}$maNg`>ijVMh0T#d{g?$^HDt>8Q{r$rsgS7q0kQr};_%;?8J5NM zj?h)g+d$yZKV+6vGy1c|;e^%=PiM9gH%TbP*$Gk~kj zVbf-00ljz_Ojxh~gNw94KLdzjMfetu$m$&=JNGFZhcpCpazG@vrEHms!<8^awv5c zum)2DCh3Q?d!p&mR!x)x-f4}7k%TW&npZcG@0?&XyyhH;tk+8Vf#k*T24dnMEa_F} z$7`$fT183u=j&8RvfRimpLTXC9L3azoq)UCGux*cEXpGK;e$n-1R2BNgG0_rHgUcfIiP1dG1ehFS(JTPf@8?uQ;OMfPY_fx@iNc{|jRSWmi2wk(UzHJRF<6bAs%u^k(|gF(r4m?km>|n zJEc-$cK6M)m%n&b2vW+wnC>p24Fv+fWMk;Eq5P@)x!&@JNgh9c3|4xg%3;4;+o{`3Wu0UV{>H_z%e(m zxVi2By#q8GPz>O@I7$`8^40<>gAX?oVSup+`J)HiaKcRbJT_fS$*|Us%xR9^fhiI} zqC4ju{Xg9;u|a|M2S%`)BWY-?hXpj&@pnrv`{d;Y@_RPriLy$Xu0xw3s^?OENmec; z1N_%nqdcQh-HbcUdIj8{_h@-}EOz_63w)q_``TWHu=K?U0iF~?_7=q-)E#cF#Ion1 z_G>!MsVS%K9i_t&Af#z`60BoiDaia+xk~OX(m+9@m-|rt1J0ehYhMgg`4o=${;c+P zh)svuI&Ey!Lv>#hphi-=txWmBT_AqOQP(}8SKxxIZrECAw@=Jv27%#2DRw+JzAa6T zOhO>l9*QFYiacMFMq)C0rzd*ok-z!ml$L!wj(KdVIj^aa9^j?0O;tb;6q|&lsV-A5FKVp5PnY**BZ5)I~ z2f9NngkahhO&b;9^{?Fd0)G_?z%4)Xl99`K>heBK9tOW52evIN6HDs;^}iQj?IyQr zcg_lYcJ|uADYgqTbUlsl>WSl@|L_O+E=>jnBXve10Dru(Lu(G437xexw|iz-NlWwf zy^G1Rfab#YoEp>RvaN${pl*Lo#Iee+irp^>yAcGY^!PboO7i+Ms7>7$8@?kBwH*g) z3PSc3MOSA)$VLOR5_t!+LgI?QuB*Ln2L1O&bdtcD=et`@BV0IBZ%JT8m2Q8}+xtl| zcEJ&@RNJ?1(BNcc7RpEF|E4~o>2dz~a?L`UCEHo%pi`dNEc0va=e;Yu_TjVQ94J|n zZ$B$%+tb;0YR}RyTYRGfa`-i>OWbGtp@HorZO<Aj()X-4YqFN=q()) zL;FiRIk}HSUW%xw;)9+isjBr(WzsMslgN$Txkt=qAP0U16kS&Icb(vU^|J3puOBn( z22Hw-QZ*7L|BeY@oKc9+$O2g>6go z78Vx)KO=_4#@=m{nJi94x>)5xvhP5M1Tk7c)#1IgrooHsyZZ`|qhbFg9JD3~69D`B zdkzTtqXIgSOtTK3XD~nwGRLO$2f>k8u}N(b764$NMMx<+B9_D9VGWQA<&A6(i@Ep+ z!4lgqhzY88$1LIbMhf^ww4(n`!S#bO43uWpskF2NBj*`Q$)z&V`wn#*kOJ!<&%a%XkM(xh+;T@uS)P!Xa`WRSI;>vm(sN5G&Q_+MZy+=JTT!d&(3v_~ zhX>Bmg9OyG)^6D~x+{^Gx&X3Sv|M}{V*fQ>%Xb<-P$K7gIzT&h)R~JXse{%^&aZGk z+a{B9&e2%}D$@~KExsV`hKPa`XJ25_YoJx%k}>3BDuXGoTplmi1GA>A;7P{)LoAuU=5T6nM8}f3tWX)!XAwnb!3EPN zB=Kb#7sZBfDsY(%y-)Iqtx|+u#_$Np-M?~?%74e+B)y~glTIx$-%bZ_+^cT`b?z%9 z6IH>BX^^twLyg9KdOPQbDic^Y8G~2yB24{9*$1AWoFK&JcjEpDg=Zn4)(>V|f8>N7 zaGhmt#QQM-P85*Aa^QoEKgN9NW~zre@QpxB$AAT8KTF)pG5 zs0u(a{64^Fc57lPCXat{7!n4C8%043%3&vA%(ZI~5M!p!hcD2S1~P&j{!U7Gz-}yj z-n1QOH}$Uaq|akQbH}q21-8RyvYg=|F`7}lR0`EqO}{C0`C^8PWSZ^NjA1Y=dGb!x zKSn%T)y%4fuC~OwkCrf*(M!D-MRAm`h};bQJhXGtQ<7eoK%j6no+#^-5=_v%<_Ets zHO;o8jY`#KW2VU05NKlNDuN;+^|zqZTAP-Z-C&O3(QlZn6Z5jF3A5I;vrN&()~xiy z7QD!rE&^S%wJLoN35RtGp9a*+m%PG+UaWE9cewTOFQ_9sP|hJfAuH(n7bC&OFlC>? z=g7-Z@3x0cW*W{1DEK9~%95?=87gpj>-;bVh?tyT5eijV_0f5njWD)0%%~BQ(gNOm zKl+%3xVE)zNIgsCWSjbov+gzgy?7FJv(tVc_)!iZCp%wwOu~Mq z`d>Uy)59MC4S9opFA7Cq-L4>dK_}^cR}vsC-Z%M}4;(PA2!wz?Hq5&uM|J8SFstRD zHFc|^#PGq_-q{x^z)kBe>-^7nux83X{HIhONkwB2uOa~i1xL1G!UowURkt@XxgDnUEZ7g+LBiA3seJK`v)40v_$VjCdz1Ap zu6piGuq4f7)W^Z9A!3r3T;?viD%)1^P9t(*I%1*kHQo-$CNIgxGD2J&lLFrRN1&(2 zhZE;iF38L@49E@WO<-!y^?DFnAJ=Za`2MX2OL`zsU0@V>hL*WHD@V(8BfynFDXShG z#}r94app&b{-#ZUm}1t47t>Kuns}~|jj*<`?_BaoN*4DG`Gz|dN?nfMEHE{@4XzFw z-*GATg^?y z92usd&ZjpqGvvw7?wi+4r5slLi~;xAyDln6+=k69cw>Wa1!04v+&+A;e#~IAhjIUj zrl)Z*MV?DF_wcouu(Xd2={P(C>|n!;nOjH(JgMkGRC>k7U*POFYX}1n2EsyuI2Bm9 zu^#pHnr>D=IXC7pv1{KEXV)~<&ySxus__N+7`jN|e`KB=pe%{uiSMTTp$K1@u`jZx zl)X3M|Ltz>Cd*{-tr&D1``dny)>{(1fX%<17;w=GiWDQRF5p+eFv#r?n%_&f&eOg( zheMmh^5-e(Cni{xU)0sL+A4fIYB5O7waY&eq9w(Lx_cDHag4kHU*b^q!}&!kHN!Vp ztSCK1cRMKwbL@Zw&B}N9uQF<9v=YliUHSH>!)SuD5^*}qx!fRwh4J-EQ>x@u6%esP z|InK){W_exJJcXSQ#Q6Qa=R)tsj7JS=D}Y=ytNuVF_#kQabK$--I{EtFp89T{?U~< znSwMblxD=o7_DWv?rzoIoK;Lk%L_+NC?wv3e^*bzGSzg#lNwZg(pty*kjm0IzBsO4 zc;cLN-Ynw?G`$uKAhuC%&+`bl3+y>w;CuiVcgBh~r%SdErhymrwiu99ZVNvYY+iq} zP>5Wdh{W($Zd5YpFGJ=CJ`rb!*cDe z`q#deQcxM8tq{bPkTP^njwI7Nm(Ixu)=2EfwUI14$EPx#=+To?vW8moV6kBouE_=1 z;wv!%06>86mN>q#CAQW)-^(usW$?p+DZQ&u6MfbN@l6!Za9nMJ_#Sr>Ehe;jJvb|p z_lNvlputw`33CS~4?R16qA>V9*sy3_$ju2*o#bQwA5CW+71j5(aY{-WfuS2Dq=s&! z8%aSrm2?Q{5~Uov8w8}gyN3orx@8DyhHl>beb@T^#kzN$b!M1*@4091{p`=PohpR^ zzmEnHo9LhcCrEyCQg!me9G+)q?f_yHyTVp8(6s}2>h;|6atkEScMA_0C~i&m2oL!e zVJ`r>(J}@Xqg1&(*hF!1loCY7u?CgE>np?}Gfm4+(aXiG<-DeHl(0{ILWJnSpJ zgAb1cLJ_SI_nlSf_4^NxI7+95vY7B!E%pmY(7me>XcV#VkGg^JA;`WK*AJf50-aay z40H{xJs`i>r;P|>6Fz)LYi~A0VzhHPNQf8A=grEi{2&1$?~)+Be2|OvhCzFdp|oLX3hm z7n^`@r(5rI-0m=R+QCYEyNsdpC49LtkQSEV9uh+=-7X3HzzCE7;|+$!44cC@KAr-l zNi|Djndc0P_Vn%vWyf|wm~1KcKt6gWD%>Dxy9^X#{1%-Y$Y}u4=_t(_4!jg+EJbIk zo5RYOB>IU2VYid*)>7XYMisop;vO^^eeX%q)GC|>k zQo`BadYBp%A$LNVuNw@_WV>}PiWQF;^x6yYa$EbGmDMPipcn1KD$SieXJ}f-j!LoZ zV=l~^;b$vujn^MMmT3D4(TG|G$d6MPyXL-qyNRVf_7`cpbHNf-D@MKZL0&NW6W;Be zIpga85;_@tZtm?5g&*;(30k(dUIVp5dzzn(2YzDEHe&cLkbv|=rE;`C1CD<%Mt3ip zQyu=AgqN#(Q9}E|5s28ldu-TX=6W;&Wm}}B3ouU1q$4_!O8tgAfi(-k$KJ^A_DD6!5XAV(E41 zzqwI>HXU_6%?GwMYd7?gNHFW-DY@5af_D|OM2HSKO&%EKW&A!6A6NWjZWES5l1xxt zbZJKnij%!B*FM?-!R6K)e{_-7%#c~)1@|Lk;Bb+XCsFNtUzqsg{;CdhC8GSEE?At2 z#u_vH?q4sd{ln|y&vEmBmQPrzRBF)3j2bWY$IzNj8()$6-e6RE_73hE^T6i7!Cr6e zaPx)lUd~-bV0rY6T;)H4-(b7nB00p>#^e!bS)l@=!*eCx%>{6stihzb9=-j=#`t37 z((-@t6(vMU%FAPrGjEpLf(}(xwXZ zzo8U0=~!OFOg+gJ`XcqMGlP&yN1{nE$p2us*0i25h_X(zfu`cqq6SK5LzQKw%{pSy z?U5O_SE7^;@%4oY;UOc>Kpx+KH2ttgV*-C5*ekMw$B3?gR|ftahi9^3S0qFr!k+}L zo?aGmHw1XD6!oY5ao*?=m|KkLwgguI=X9(#x;Ie8SXb=@ zV$y&y&9z7Px}|a8_G9;SPJk-(Iy$rG`ex2-S0cOp!d5!r*U=FWVHSIC_;mTdfP9tKpgCbdry9#*q}{M#2gSy8@|I5 zc>`5Y*;?r)i_WMswqPN_q4A3D(eB$iQNV%nZs8QKs>od6!kex3P_qT}!Z1W9Q3bT! z9H=2(woBYC^-FsL1D0|+NICXzF+C#Z1N8Tt*9B2<2C6JXtTY6ySMZZ{)Xo zXvAHkfI;YXjP>xr^Qnuju`oo9tFw-_;4GHOIC*MFv{x*#e|tO9#!THbamA2iqysvh zaw z)5d}cuM-yT3_&hYfOicZ?2@6bXJkyX&nuqT|Ka2rI5U7BwSM9_b!!OHOxjEmxd(QW zL|Cj&yG0gMbg)Ud2SBx=)ex+D1pKC6xb=(tzI%Q|bXk~Rmvno0bWQX2idl|nE=RpxU!Eh_rITNqNfU)p zOlI+J5M@`AIflpVb|`#2DeeD-^(QO8FK!>lNY_pd)|aYMwKZm%|) zT7GhUGz4sj?JB=TQE0TDfixjqhUjxuB3Ya+6KL+fFtkEZTkV>?On;wU7hqr$Ji<=r zX2W{d`N!PmJ+M-j;UxbAakAh%u@TU6e9(%{`*w~SP0%#78V3_WYzK`FcRR}e{rt>n zKZ=7acb~P*RQgA1Zddo!4{K#+;w45pnKz?oh4zsdSB69Ocsie=X!WR62mM5}YjXZ3mHMNVDYJF?7OSFzLMzf)+YmiDd#hi4!d!m-j!Pu0_*{-ORnpsqmM|fc zefMQCMd>)Dp7E9*QHqtV!fK^}2$<#7i9t)HsaKrCG7d}QX9AB zN+zQtMuu;IC~TZbC{^jaYw%`Fb8dOCtH0SHauFin3%Kgd+aXo&06A%UwR;rU?0akG zmg_oR=l7FXdP1Gy2(Y9R?cIOl+3vl&LgGzU%`}f`p!jjazFDRDp+u9 z+&GSo=I7JWpTvZQ5uTv!AG|D2k5z&6__q6eJFY%pOqLX6ldYTDJPx0iNlhcoRlC&~ z%?k}x%CaRyiIkMeoc0Vl#^`2wpJsMV8g z_|;AOfF%7?#`zLlFl&cmf1=PaqhwI~%C`Y~G?>z|yZj z#-jb#Mi$k{!zhm=I#4kiZ}fPe8;mjjIEMBkc3SqXKz*e9N8iCs(>-S-Q}X!}v9}vp{(ojiOmf0pY>nf2nZ* zd&|KIE%aroIFz~BRG&jSGlWsV3UB|@#QRJR&y=22sA~6bGp_0OKHdPSAP@(o*|zAN z`@kOn(6wE#HZ;(BV{o@(N*q_2(v#_CqdWI>5XbJTn~=EhFAZ{qsH`BKE zKUe}rCe19Q0btnp)C#XzCH)b^DA{ zcpLvNZ;iz!xHMC@ol76x57F1i&`l;yLfx9lI41Y)y8F-O$3CJ95wvzGGmuRMQJ zhy)p%vj=G;3A?JTm<3?8o2<67b?c$ix5S8#_d}v>3IGGusBhlfeJ{+{=5Nb~4B}MI zIkZixT?fa4FcKrKma1tQwZjbzFtoeCmZx;8FV4Hy()l)~# zeq`t~;KG=IeCsnXP)g6!XCwMQEdT=n?yo05sIvFZ7OfIkbeZmcMU`y=dtRdtcmMY1 zasS0Y8!gEXI%nS@r88Zfn!)lc`XR^AEs9KBvIZ6=%6KD-8lE*JPou`uAVlLwV|-B6 zS}6Fvs4pp0Q@Jk+;RMnw-5Y~<8`|vKb>F1+-#}gZnu$5CpHBi&TcyQcz{ZmzU`;?j zL;?LVvFhX{IgexrC6rO&yO!sH{VLVgpG$Iut~cBO{FCY1ZtD784Rc^B{!FO)+oGQ zE0Q=_%i40NWP%A;xv>jrKWJpZaFe&?X`}$0GiXp{ezJE6Tq;#oE3@vYV4xu};6X?p z&xTAOoA@2GU$)_wmw4u80@Rd|hhfHI1cRnQ!G$7k6tgs)nt;CZ9psnVN?TdIP8<%= z=+H8Sl%burXvPdP&Hf>kRp}OA06ws8`4acmX;sf|??dqEQl z>vsN4s8%mBGvruBDtbU-7YOvH^4=81UL&6yZ%o9hS-4J?GKz$}{U=@Ns@YPFDLSr2 zTBNX?EJ1HIOgi;t(Zj?>Ugt^@)?JQH=(d34rJEw23@`Do2=p|c5-de~@4#N9#hkB} zbY`#q1%avj-Qth>rz~40nD^H%jQ|lbK*yL?(q{YxP%AJ-Antd2770knU#lDIku(O5y>7d{|2z;j*8-5?X{lDd6BvP)YM}X1iP^*_dFZI1V=dpg zJFr|pR>``;5v~21!~!0tfS*bTC=hdk6y^~px4(*~ST!g9Kx^{)d&wD*!XWp@9izZ9P&V6ss^_8+|gz#bu-@red*1g6|Y0E!6bZH~w64Q6`e zax$s>m^rGsA^-Z}uvHha_rs7k;=F^oYq|F-b@)^4?3Uxhj@cdpG-?W(`J#pg^j}vB zaFR-mGgDl}ZBzH%D~E#r#KG(m(j%X(&C~j#unBM9R#v}sOd${x6D|AGqJ2wlF4#lm zud}5$A=Az>GCVdQVb6!xoy=tPug(EQkDOYS^+HZPs~f(pq3EV@c(3k96;MezK0Hul zY}1hHuI1W|Hb{WU!r-Rd+TXsjl0gY0=o)-66WKc8u{l7Ry8D~eN_hjyJMUI-^AEfT zd70#WV0q|TFq3T4fJBtXeacHPa}wmhCr!1Y)$a#s9OLr&ng*dNf%<=J4x-WR2C$zx z-O6^Jk1HOKl`n#R10n=glHb^U)?69VbUn4^54+I=Z~PRXcBTQ>RXlh+%kDTPbUCl!g#9<=MANi9l{r0mqvv&& zfHhvqtJPkw_1iiP|J7B>(%T0%-t3ZL-`!rX!2X-9fpx{oABQ@YE7Cw(p^Eo7S{Qw^ z@-M?=BxLAB;Yk2S!n5Pw&6z_6Pnt3loeJ#sVj*Z1|L}wb$NPMTx0x0Z-iOyH}YjCA5$42J8`~fLsOO=YuL<(BK1$} z+J=dDA5|i!V2x|@-xR=R>t@vbB>wu}+SfoyN5i8uY5r479#5C;4cv}YY^;%GGigZr zx)~e?Q|!Ml!Zb`pSZQ79?kJ5$;pr1_>1F;1HDmceuL+xZADc>P;XU15MyaVoiX`k@ z*umVw47a7YC1fcaAp@lxoxZH~@%hic;`Q!u%Dnf=r_rJr>TGH_kEL-WAZSB^jRp&r zq}*MAFi0n)`h-(EEUrbfY2n8lX&2-`GvmjyroVf8!C83sG%Cw_5HaOKp>-q zbPUGaH`v*AXL|YBL&=V?uS8%c80jK{4&B0lB}%t!^+OQEVra5^Zu#7bN{wZpnQPgR zW_!|BJ^2AhJ;M59K}}ydbj$yI?arU#!G`h97v^;Tjmq2|2yZ@!%AduN zeU)35J^1?3tgEEpr;>KoAF890*Oi${B1IlID?j8c+deTBd+8fn>gbx`V)MUuVW!fI zUJ8FtXB^E$9Nv$(r*6Wh{oRWEslbVUP*_tvHhxU);I#1#hRaBN{Z3GsF@viFqmCp8 z!|&@T4Y$YkGUy*JjJU1eH3bRmlROSu>L?rrKONN~Zha{>1I*qTqpSYv$IsGJ=oT&N z^$^k}R>d~I{fz#rmL@3aNLgK)g0<%;rz7Z<|NVABlm7>8Wvy2@LBx@|l47&K+9!>6 z|6-GBe)p53%b3;T2uSwKrDZNLc=FUDYAMA*-M+F^O(SW?UM#~j5zHlMm{h}FYZ^t2 z1Y`$x`kOORsF_1hy-%)#AxGyf_ZX6ar<6$}?WK5SkN=|H5|m za~5t|!ME=NSV0&Z8hVh5ohmPH!}~if9-2~i)zt_^$DdgJ_dUX2K~l;cJTBq9e|N2a zBTRV$GW(mK96l+tFf<12DSnqPF@ezx6i`kpE2Wz$x=m z-%exKL&EHz9>gJfcs1%_e2bR`l^%SS760n^*dGE7+q37q$qgv^bXt|_ z&NOCi$0t$0lM}w7E}K_`O?ZX@!GSUJd^3JO=mZ}Q8xOoh^zIyu4+a~PLcd2(Uh38nWc4!(W z`6AMVvbS5W2(f~zq`F1OLEXhdA%btk6tzn9Z@k8Zig}f2%u!y+ep_^G+TYlQ-E)jL zIV4=|u!)jk7{d4aU#r73b#5R9pE{XUwb+uF{*^!a#QKT!Jm$O8LVoauzw8+C{Siwf za!y)pzzSR9xfT`@_;-c1KGB@u(f41O$|D0wPD413{)%pcqoaX56Txd@Mo6oMUl-Ez z(-`#=Fu;>aUj^*Un?jp&cnB_drdP^2B0Zye-Qg$7Ia3exj0_?LRIINls)i*gK1|rz zdhT0AlqyV-=9XYA#hv#*{e>a@q3(3yu#`vJ+!``Vj}P!vlh3Tjax3jXL-~ixI0Vk7 zpZ#{`i670(2hj%`GpUv-2T)RrSv}iBWmFbJp5yMxHskg52f228Q)pj#kgmrXQU+;| z0^z)y@&!m5ivhLr*Ne&sBz(M{ASx2eis2?0ksh#F;XjoRvc7E)%Dg7K>9ol7e7bI* zD^RpiKKQ`HcyfuwTSPtOR* z{D43DSt`(y5{4c2^Q}xIHC8 zGk>4bEdOP2mpHI-Q@o|m$O>8?us%2WDNLV#>}-fmQ)fG$LeV~{CKa{QqhHPV4jPJ- zd_k}sgydfMDL$u$j~7X;y(zs?w@`pZ>c&ppq{U&iHepTFR;$&Ht0=G5_(i5hTjZGD zm9eYjFXG>JjT7i`?0*~Al1&=d;>P3L0?y_n&m2+bZe7u!X~dpm;SDU-D#Ut|-;Etg zE9_*WDd@-MO;0s?Ic57dwm3X~pSy`2@v)=}hnfv|u{`ue^V?RrcIrUwP%=4YtgsKVU%LJ8zd>UvI&`3n z!5wa{*6mhMRvv04@Lkz8fUq!MC)~H7*adC^w8KW^YRxpn)Y7_@F?|#ZU0NtdDg%E| ziiVEcj8j*uOK@4gd1zkfceRNMsTfo+%Dqb$uPdhQ*H+sK)K_s;A4^)z4%!yJFDA>3 zDQA<4h&d9Zva>=(cn2d&CNUrD8anZWdc^55WVbGK0iDzV_kStn8lX)m_fiKmJyu21cd#foparH1I+U~yE4R?g0 zzH&F!O60ppSS@inNluLl9rL&jF1mnx2`qKaE%wLkRyXd)n4b?@Re9xav;J1_-erv_ zA+_wx+o2rwX^j7w3#zC^ahUhg*I3St`{CBaur3!B-+&B5Q4bsGU;u=RX=a|MyfeHnD zipj`kLudFJuwrGEkM#PHS5FLJ8h1ULhnw{Sq`0_=t+frIj+-?~pxHNTGC3_A_Oho9 zfJrWTT~!F=o?BiX15xio--IeF%EEn!dM6{$73%xJYivjL>wyUX3*`@Kik`z+px{nE z!G)7|&v|1-MSNK{ujrBj24<*+iTxEzdcOudoFV=T$O#h8y(7MT&A|=^HbX9A8&6H3 zYZNzXSSqpBHD`LC?}tKMq}1bozKYObw@m&CC4QHE6w*Ou<~+FY$5)Xoq1vb77sfiV z_A>WQ7`GM%J~=x68dSR_?~3q37zevSs7=dGP7HiCE|mFI@l-8GB!b`(KH29Z*vHS= z?86a7=!z<&zXU|vJEwA~8>Q1nP`cR}R1&RK4opG`Mc*|!na?i-C$~Ti{ePg3m3N}Z#*BJ4@?y!0e<*^%}f3-;RbS& zgxfy$>dc>=LFbz(@7`wTCui`Xe;$-Wi3$be@08wZ@0POSc!p@|IqmpMwfDwS1Tkk_2GlMr2C!Y+we?j4qrMPru6!tJlU&W&FH$GFB~Deu7e&M+#hR zriZ>OLlKt=x##)l)bmI470NPITQZn$*by!{95}>Tplrzpj7BSZzTm}p2?3Cwy>5Hx zOViA^;xNw;1ZHxLhj)ppmHX=@fRGG^d-|bhv7HQ9x7A*jq2s0X>>SiSbMaJeF|BYzchOqQKtEx3 znW}3pLgo%znxFoBDC3%ubA0$YZ7KH+r5~x^bHAd3NM1e@N^!x=H#GgGAP*eXDfiEc zGv9D(vV0mzh=N2W#m#LHLbXz?^zEk=hX}DmAGG^3>K%)P@1Q-A)}L-D)&XU-*mm_! z=4;%6_#rHUZ?*<#WZFpPf8;n>8=(rJ6ubjP@AfnTqdE7eMRRuW9I0i$-RR+=m}#*i zPu+A_WumG((8pp%GB3g@UX;IvBxORm8!9Ip0>+uSb(UhoTbKf32d3)f_c1^{6@N)< ztJL&(x5~-vRG-JM@Pu5)cQQY&=^BY%K53Izd->Wcpv>5OSWIpWmqKcGXH6UU^D$lR zD-(Heic>|`Sjy{1Vb;-aBkcV0MHROruaL)#FYtxlTkY~5>13T4>3mgJV)@`0&-uY2 zy`-+AR-`qWJ1moKfMEu*(ilaad^u+DW&a1z0oJuj5G-XyWgaoJ1Vll|%S*GbFM(=T zcNk?+i-Z`=0)#uV^N0+0V-QM`$)Sd?^=I{?!fyG%;2Q;1dj$a`aw`^Q48&1v<* z*z0pAimLqbQ?)@w+E0Co2A9OymJxkfT&C^U6e9Y;4q506YbjZ8q%oKW)5C8Upo>H< zJ|f6^@!T6%>fFfQddW}yF??TF?f2ue<1{o1t7Lquw3n!eGZhBjwa46R$3bkh?3Sq( z#C|bsiJ%Tb%xvlaBV4?#9i@b02a#W40?cp4rSl!*4rlaseh&GX<0wpO4VUsss5ATD z$*5rJC5qdb>sYV#8{8AaaJ%OQP=T5l@|LarjF&caP)@MT^epf@_ve;=8ff1IJE0Jv8z+O% zXJuZRE%C{rNuD*|HXgiK(?3t`Ecj6bh0M&3DZyjG=htKkEHKpQ)B_`L>9i8CsMQhelv70&P5{K$gX>mea++(sY9t|gI;IT3Y{wn7F5V9a;rDQFt{63s1MonZ8jd< z+oZoU5>jpdIU3;y!ms|@el2AszOxI;3I4nxJh|H^yr6X-UIb)nfT|jaYFmcNV9FQTMlOuXhb*{1wKxcGJtu#({6hJ1#d?0gFavlAy03)b4No^P{gZ z;}$;KSMmQg1nYuc=Ta6AiSC=dUQD$jM(e;gmE|>ZzW2O3si5jj%)i{PUsr>NaV_aB(IWSJ)OyCqahzgpQ$2;%BLAkLZXm@P+sGXZltV zZ@RmwyZmpW_)$*WUr{<05WP6m{Jpjs{up=+7#ju6e_v}!Zo>DOT)w85jj0;z3Y>3RI zqpxIdnD4I#WCF0Ej24gD|8Dku{Zx9P%EP-o&8qE4w?`mFcB}*d zWM-`?{rb<->~%9&#TP5-M}AOP73>zM(uvu^{hN4>ZC~9?OdJx4fLogNGe2=Vpy?O% zK2Le`PKWYomA-yUxh&cq;ZT5KX2q?}9K&ajlmer>wu5*eDJ+;{2QG6FFrqAnQPw3P zwKkWCaPQH87@s;l5|N%Z%|+U@D?CLt=Fuss6_X6jLzlarD^%Z@c~y+iH;DWe+?%9% zY5Ml1?&215PxZRP!_DN=c`Hj~e9pOjvN-RT}@#oWq_+`fm|XZ>lQ zW+&oVs8wM{t7#>nm=OQPhAV4G<$yL9l{3e=^$zR1j4cUkYPsUVCuN5?s`-!~#}d;b>}W_q;K?Fv3|F42;Vy|aq#q5uTA&=MoY$2N$K*EF2p)d)!}^LfPws?|pvxum6P|tLtg$%Lg3%CW>|Y zEsR_(9w^lIQpnM8%h2I(12jX2@z3EoKonX;U~GRS1Fs1!tUZ5L3J`_|6*M1SLNic5 zgn2%T!+JV?iBDEpwu?Bfd-2|J!jNzJevSU+Aos+$if*>q%_omBm#NT3GaYD7@pKNL zfs0Jhdgek`=6RgmH*_fmiU6yjFQ#096J8GzaGo2hU7%qCBqT*$SY@+9^|*`&20mid z5RCfp6>)nFP;9u~AP>$Z=9Ip8A2Le;1Em5a4MC&P+GP9k+ojUxBvHk8BgWL*&4uM_ zl%q{8s-dv@Tm1>_HxF~oQ`Tzwuo2O4a@T859wS*p(Ny}R_olPW`kzZoY|3RSjCrU{ zE4ay%{>73qk_mqJBD$=7)!E8CURy3;X!B0bph+(+^L+|yzqkZ3q%p1hclr_9cPHN} z4l3J9lvr15B-Qe46*iri-mb%C!xzg*l=Xm)Et3YUUs!onN>K;0GK{&vc~^=4gL_9P zX+@Lehj{8jpgG#MSt@sb!&F9nQ$v~oqIbrtes0RapFFRLf6S`)TBAzE5E{B|Q_Q=A z{;RzcO=Y{U+xh*tf6u1Ek-FInwcVW_fotg#Wd~`Y8lHE2I!MWQoO!rja65(XmQi7Y zm%Zxg%%^q(t_ln>2iP3shkh)n<#tA+`1ttN;0gA-IjSa*637PfL{Z{0M50 zYIbs!2UuE49EW?0hair2p_&x0lA;lL(56lXu#4zm6s~@4%DammXqy#Cn5N6}K{#Nd zSwv@Uzt`c^hVVN()qLsHsCImR${}V2Umv_rh*aFTs-7b2*d^5OZV4$jr~Y!nm>a1q zVd@UWnIDWYD6Ich@=~+q)Dq7~n(I(V<-!ZBM^v=KHEj!BT@rpU%Yp5eX(Fuj4f4R$#A07LTPuKi`nUHdB*!@s`>zokgwf;oCj$ zNI8UxM94`?)$MQ^e`kS{h3M0JKLRYTT`DiQ1#czB)jm=3@Ff}XMf6AYv6iGz zivk@ntK!5$+r}7k!gz`A13Vaiq&ZZi-As9SW(4dFy#Q?@E8b>z+k<;)Hej$p#_}C9~}-Cfo6dDKD%{yiNWKbXiUe0 zUg(ZGT!)Ihl`l_@d;o62BQT<7sPuji@W2f`ls>rz2o^_TwmZPF?rceYP#cdVi<-k_ zAIQ^AG!}L?zS}H5#Fq6BA26bd?uppt?WB0|_zePDG4I~kVr6IjmSxxI6w-uy-xuxO zQGQw{!*D}xw+06ys#pSafw2Q~L7 z;tU)9idY4T=*FbfecqjXx}cLY4VJVlHyCx2#A&iH3UZoq9&s@V-L7yld*RHKHGASS0>j3hOIDdl4n4 zS)2i>{fL@QuATSk*)~aJKWv}GVKE2itntgML6n zM%v;%n>canGSoRXZN$L#^q=#DS5~Kr*ArjT0H^gB9ZES_dBgTd|gj`kIEddgqqC!tw_n79quJDJdQD zw3U^mJ5xC%4B3ERU-c#LXeGqOl|+&wtQRyKNnJZvb4Htub|f<(1?+{004PSX z^L`s(7Lk$f^7sg<>X4(~@U-yTSyZ_009DC0EO-gRjaerxA3#GBIS6McDyM0A$h8D0 zB~JNxEdqhFuh-TUi-6xk71^1q{;q;BuH`DX0l8nqQ&jdpPrzKx`}71REIrX+yDxG) zA}p<};&S2^U1rYHP`MU`Aa}3z@g)PwI_uB#UFOWx42Z*A%)7)ZQAl_wLe109oJEwdi7)7(@w$#|29p*DCZ|bl+^$Y*eMR_v6YnyG|K?CE7O7q8 zOpi=KGmnz=XfOTi%}cWViEq}tFv9})5}G$6 zoiKH3XQ74{wOh(S|-nv3F}*+G?mnq%e05Je;mcLXxHK z{t9=>$7$yWn{}mKT|YZleweD&EeGs?2M}p@Fs^QF?f}5+T#4f#T?*4)FX+wR5BE=w zFz_eq{pxlOxUy_M2j`*5UsGw` z(f$q9(zr1pkFn0?JGF%Ip5|X(JuX5WG;7c(@K^77*FO@e)?V~*s|V@6Yct*e$r?_gAPiQF6=%#P@xuLNs=I``+Z6Z!2Q) zw2AF;!&S1S+$N%}x=HMX+&t{~gV&Q43kw`RHuM`6tNoIaQPlk>9kG{oQBHpTJ*+$v zTy(TG6ea&%g;W+N^jWY&Rl<#7_LugpM;wj}np+s3A*YVj+Xx2g>Ivf<5qSB}flo=! z(-&%qa?$KNVTE`8|zhkD`JyQXHIC{d*c0C^7-}ILt>Fm#!%^m2B}`A3WkrI@Jsi%82c#m z7Xf3tXV_U4ikr>NBEOmMa$2$@X1mx{$0_ifPy+V9PKuuoo?WGJTBx@~>EGI%3;~94 zkPp6dCV<2I{gsmDxFVppw^#$Nb9W=|9Pko9?&J#hv|6FYe;#xZj)ucQiYW2AZItjJ zYvv<3Xfjck_IU6HRE;5M??VlL+=dG6b~=2K0_woXg(QA}ouuRX4Ca;ww9g_&ER-vW zwpW<$`|B=RI6l6xYi$~yWH=-wvUK?oBt$WMq`;1l0C|24&bW28=%ZBmy)h%*uJxKOz|Oqc8jq7OvILKjci@ioI&IdI6S=@#FgLnEb>xxOas# zvaCM7&qvY=7JG}( z-2-wdyakQL5+Sf8zGIgJSJg@wUp5;vs;?Lv-kqp;BmiCh0E)@|ma@1^oCvU>|xCS+&?lb-~6GXr3^cRPtTa#tD*oeP9z&@GqI(U9Gdq&|eF^xF- zMK(tKFM@XGCRz%oM4#~Db8BAHnqgvYq;>)F$e>YP!L}aC7=^1weMM=;_EQy^z>erq zmjuISQu7|lzK;b_Ni~DPGhhP`Cvsx)!=&tF&f;*icru=c0fsOLeDsb&hxZS!waoc} zo#D0NWUrRycc~RG1XtNIt>`p64*d@*oM1ULHQyJ^cJ&c+cB9%*LaFIZU!9j@wdQFv zf%iBy0h2YF-{Vm+bC>#TSyY(T?fZVWZZtVqU1qHClHg37m9zO-Y2>nr5RYzFeuc_e z9#H-vb)R|}?BNiRp@$vCDI<11*4i7n2))%qDW02abP_rrx>b#;ns=L}STCq4k&VR2 z#+HrG&P0ije_e{ieHzz2Mr(2Fe~_i`obU?2`fRAt-wfU+*sIIiKWFe^y7tcD&#C^; zUZUH1&zTN;ML)zPubTmK zxr|@l0VHr9l9|m}s9Tf@*_8m)!8o@2thyr+F_(1i=mNAB>j;|;2qVoGCam9L!-!M$ z?$610n}tROFDIP8-KxMWKE^EHtr>u$ulia81A)oD&2aJopW%=i1sg8Pgv)!hA+7*j zHh2N{_Na-c)AyOz%I}#3URlP!Qke5mdOI8mfNWEsu^6{)scX?w2Zhwc*S8>*oh5|y zo#M7~zx*NOXSX0vxdjS&sronP3%n)RAvj|SJDFd(_8t@Q_;mgAx<^pQ#H#UvQD_#YSnWza2%iY8->J@)nM=>Q z!+8cTmVHMV-o4TJp;kdnq*f)UFbe5=dh9`qNB!p`HKUlM+5V__jDZSiu>!u$vzv!q zaqAhFPI7C-CbFX);h15N%wlG(@vT&ORoQL1Y*9NJ!Akj@goJ2?yWfRcN#J~rK`{}2 z;bi3H3ORjC!5`ue=Un?DP3#ZFb`07L6H>7VHMx+vi(x zyAeC!5ub_O9DtUcLTvX=0~p}BBjIgbnUF0N39py%i<{0k$Tc&>VDixsh8oHKIjb`Y zapVNWD3tGLNCDF%yjkf8l!PNyv(-Lm!-$cnpK>O>tgOwKn^M4d6yRSk*`-brKrZO( z1GlQ=irU!k9c~$cY;x}VHY6qIM7|JGBw3m+v7FODjcH~+@Y!&v(;!M|EnvoeAu z95FAQxi<*Z0OLucb@R2$$_sP7%RBKt z{N-$KA-jbwVV0{f#d2qUpIxT|Q39*)*~QOF%Ctr3*ehaWK8MV<_N13>Ol{r3X8y8Dq{~aiv0Hd z8o9gG)IeLG$y)KnZLPdKtrzupn2oK`di**kE~a9*Nb>Z2U#a8Sh2C&HV-}#sX`_s_ae9of9szzB-_x>pwKF4j?8AegmFK%s}D$dCnyU{~x z`J!3eWTOJ!Y&=(cSdrfpZH41_-W+NU(%50D z!=D<)$lKAbIcZI$#Tb<_I?F-cWm>L{LAA1an zim6%fe>8n{TvP4;H;s~t0vnBll)ykr5Kxd#>F&;fNS8>D(cLOYcXy5siGhHGgCR_T z5du=rxxdfr_vhKhHqP0uU7vSuT>>>FOoDrSq4yEOf_&O>k7fWA7k^d>D6X9e_pDlI zb$}H7yheYxqCwPZ_R7Qqfnw)(|CUs;e9_?r`l_GY=&gzPu%G|j1eQ5}>pu{h(&TNe zD)9P>386TlpCE0@P`QvKq|Top2&l*rO6o(NebS3Dq`7fg)E~t(AvGv*)QX#oFB)RT zRdS57GsI<>^W;I#Tt-O*-1_bMf0NiO5{woXLXySj@2gDTtL6zN%q{om%-_lfH>&ld z|F+SAh z(SmA`ski0$)%JX)b)Zqe{Zt<#dJp@)9e-t9LyUE*y~BsXDM4eWA)&$pWPn<%et^L_ zr_{P0E7E9nd9LMb z8nulU{!U`FI5+iOL63r&BCguu1Go!fP}%iGHZpj1t_f;oa`IfQHU4<6>wd*-qV|nMXNn}J5p09#B^WEb^J0&64gQxEh)&)Efif|a-s>+ zWa%t!{^JfC$&v{=+}N0GlWa&%un?j^hwG4UQottI-qRwcX3rV3n&F|qevL8!*zTRY z2wg@4j}`x^wtGR1df3+!UoG$sF7`u?VN|&$bi7T{r=Z#^eq-7Xj>Vtq?ahXYm1a|P zpU;41WCQ*BoEvZSrlG!YH`JRDxP@TB!jGuSA0V+N=Do`s16XJ7w@+CPZ$2;5O%5^0 z=?e-{zITBLlbtyi>gYQ};#c8T$hsxaujT29D@QI{+OftGDE85Tb@V!3u)793RxcBa#lHC9(05zHS2{{RsoijZzm#>yiWGVg|X z>P{92j0s>eZ11r@UkZye7B&0bJmwvogD~nv+D)DMGxXX7XNYb<1Sd#8du}if@SVkK z?@5uPysYTt2~@-ur=X?<$X%~VvLD%8y> z$6*+a=&VBjh;(6ny_2=1=_K=oer@yO<}D6*#HXVP>lz0-n`-XO>noBoFj*s*BQh@v z)$X4>F)IJQ3dn_8opzXO8w4p_Jw`34H}<*Dt!N#q57+OW4Pm|GCTvO zY@kdJ9TT79{7tw_bMIL(*4G~Xx0vN>VOC=*^fDbVZ#r1M?j3OKu1zSZ=rrJ}l%0LT zBmofy4PZ+X;^;M}?+02QydBa#(2tb%zCYW^+eO0>yO43JrNZ`noSq6A*Ur}by`b3E zeL<>^hnk2avtUcF^Lmf*1E|cQ!jrx-rGLWW}VA`We_X)JyHO$7y0522o=q8=M^{#fq9%eNa=7J?!4@@>XMjcyt+L)1N-7g z=Eh#fLS-45Z!p3IUGjsgh2WW_2qIsHYp?dTOsrB#$weV}iAn24r$r9bUwUbIT}V12 zxnZ()rtNay>F6m!xc=^MLcwY6bX&NHNcCMd_6v*LB-9s?i1LR?RzuYJc!Hkr;v)8k z$t>#($smyEF2PMo>5;CgM_5k7%bNDv^{Op#qLmg_YU#2!_%@@@t*t|YWR1|Wspkl7HN?5h!cCUF6oL% zlOHq9kQA+5!F#==H}pBOuEaRxDqw=tOh_wD)zQ_`2V#n57}N$uiT zk^#q{Ee6a7R`l%8{&MD3-Q_Kc=O+JPBamsRAT{UqePwDxoRUkY2~{fa*Yj5{U-;(G za8!UDJekiE?(-R4j!u0OpC@ogU$wZhSo-TXawrYQ&E4+EVvZ374Insvw z7rf`sHQ5w)Z=sBEPk?0_XZr@pXS{LQhbtA zn{ZPATe9-?MZ`xQJVmi4_??GRpdNO}?~aKVt>fPm4*C%U9lAa`a65w!D)GWox+m=*^(=^q2J~Q0+U3&B8%(oY3EVD<`?<-z6!yRj=7VVpS(W z-I)N2Fp_u44?A4FHAMs)jfl|k(mEZ_b)8cj=2Fdq_gU&vaAUc}-__%%{z#7P5$OZH z9rMTOC)66)Sw-$SO&CV<0_bRKeu3Z#wO8!DDDE{wt$S{_cG(MmS$W$l)V|+v;*_n- zi-Ws)hn^Eym}+FR4Sq&?wGy!c}gj5a&qODdsX8H z&ewQ<8ybSg7Sl8!gU^t3#x^l=cR%#s24{9CIP$5P$B?kxzBM!cjUS=w#%!#x56s{Fp`H*^iOKCn9r9Qv4yv_i9fdYCp12bS znjWLgG9i7;z5yB=3D{d{*of&HbnxnI=v5R3dfhmUEpnhuyc+McADRK6+FNrNzHTrC ziDzq*w#hsqPBu^NCWyZF3p@7C#vCFOp22Ki_hi+_!aNtx*$knI~kKjy@k#AoL!Eqywl zuQ3oW=98M2Y4%@(PqcWL3YZu??n9pE(-R`C)wdhMFfKyv597wp9Dd8nlcvo+PfNOf zp6Yy$^0PB>AX@h3toFD=knf8_MbAk?)0EMJSsr$RLFB@vGlukS%b+^-``Op-^e1#z z2=##JSUn?ifqQNNJWuwoTDl%T&dyY1Yu4t9t|T~b*In74O?yc8W_|PBbogy`-f4_3 zzY+i8jD$f@Y0ZRzEp;K9YNI!p^M-vN=e+dq8P8mqU{MAT{5L4I#3NR}E403Ne;?Qg zDH`ICgS@+hQC&*iq$nG~$yLA6Ya4Lkt6F2pll;467~41IGClH5Mlkc?gm@o+rzGj_ zMke+$1U7^J%hlo~998HKr!28~hm<)DzSt`a7V`M$=%}caD7@ulR%=W!V8gT9 zlpr(@vFXD z#+JJjXyyvHm!iud-zz}ukCY-3`r5o6?TVF;@|Lt$h&=FSc?MlXGeZ^{o+FE$a_&Or z@n{-sw;rPtC6EfnZv?B4QPdiAOQhYz&EM^X@{DJ6T}4>hc35^lvOy?oJb1pdlesa9 zX8B8}f-N_3|EeJX;T$tcg?vCwNczMKd`Ni%L?nbMT__1j^V2$7(=?237-Bxk;``4EDGw^o2*bOl=~XnsOw_(N@K&Wk3= zaEy8!lKZkN^+_8@p6zGy<`pPo%0&+iXSsACGoExZntJQb7>Nkd+GBrfDy?a7^$@a2 zHmZvgm!a1}FytrHGf*bt`UiOFWZQ>@4Qfg$R5Q56 zJSa|;5!Js|iJ~av6-2zcln0u9No|S5z~J7r>{o6?kPlTPN>76yu7z%Xw|aiuzK1_IJ*Aay*p{=OHf4@KDR_gW&@qOS1%4TkTI2cv>#d z@hhG92U^SAhDP}ZK;V@+Q`EYXx&i&{!hmL)&Z}HMPFk1G%_jaa>U%^4ZD`{ePc zJLJRjwL&cB+UiFS@Z);S$@IwHUkIL)DxdQs6KZCCFz&Y#4j1kYYh|vG&1$75U%Glo6gNXGMwV4k`s9RFqS6B?PZy?zueggw)*d)YwQQZ<2H1 zkH$ai`72>gyP~$Nbc%k85|Y*Dzs?8GWXn`t0>s)u_FQrrX{gcre?=-irMhZ;YV@vZ zX@9?@i`dLs9^o1!%e{1LNc7XQM9fn^Ox0I<<{Azj3HR@=(IUX%h+J|g$T(^_4A{f> zuKPUG;vsg)U*7Njt9$L-&F!8Ic~V87NS2;s-#BvCFfTI<{GT2XH^S;=lpBs(z&)pG zbwkgtC-}h_m+-~FVXe{WaP{u3`;=m1Y3U{wy?j4jsrtcUC7upGT3d0-*E{az>x7iC zO2BcwQw>^C`TCbC{|8}0_b`mkpG76fUum?UO^11cU7CKKptE0Z_1fTh^IdX>%*cD>E0prP z`y@q)O1GXousS<>3ULR*QlSzVnfsJL>Lx0s<6i>|n2=Cc@7_$JW?&8}Sk%P|Oi@Vf z1=Wtx6+Y^|5L25Z3LxA@E)pOS0MwY*it~JV$-awUK+|9wCL>HC&4##Mfz8Bbg=4RL z@)<)dgD8af^?UhHL=0obu}LM^S4_&LQ$D@I>U)W!U*Vf?MjpTDbAocq&$W{G z$XGI=6h1d}d8uVkDt}88vzd+{!GUa*ol8becQ@w}_LDnPi~TcNV@XXu!S&IaE7jVn zQbMDw)Fx3y6zqoeWcVe?liQ5ij`H#9>lA6S{`M>*uSf+sxu&NR_Y#QJpK#m^p6Ny_ zqKz)es0*^tS(lDCYtNfDNAfC-#dgx`vSToYn4p(9aS5?*8<&?W+m@w{#p2M<+K;Kd zekz!mjqe+{adCXt@m@B@S9`-hcP#aiheFa;+?aa-G@qZR)?#e1LXe4e&7=DqHt{-? zA2o6VS}L?EqhH>D)C7q}1IWpZRWBv##q!T{-mr^61g=oc304}Gcm?4Xpn~_ou;;*s z0@_qN=7-6fL6HgHaiEIM$#>MRoMH5AX>DbK*h3KUXqz!rs08A2DofMg;jI{KaMbT7 zCLfh;Do1?MVN`Y_1`A|EDXwK>q0ES6SvoWjnR+LQut~vYTckqG`rL*BW_oQ+XCku; z2ij`$`rE$UPNtM78!-`GI6;l(2A(^9I30AsB|EEYMJA79%RdHGj!kXm@jlmK3XJGC z9?Vk%_u1m==}pZQm0oop?jO*)YCAhSnEETbSN%Q90inWyz2DKr#XW-qt;#y(N#Wn@ z4_wqLc)qVS^>cVKK3>*0pJtG|zgyx$ic>H3-~`0$;BX@}2qJ#;lbVE7PaZ>DGi*dd zqhlHr`R(rDVv)dhm`YgUZE^q_XHk8K%lj`u zoSG5bzI&t~jf%eo%@X)z;d<*vCjUP5*TFw7yHuZ5zZi$A*^tpF_zglCxE}h*3ptS6 zNgzLb)ur-zc6l}0*JgUQevCJEvMxg8EwnL3pnJ$@^7SLbW%5vB&tfGNogu5#P{Ih) zu5dGYw2Wai+!<>ug4=fVQjOj&^60M{O0@j!$HMXIBgcexk5E6(u`{Vc?0aSe>)=I& z%3lizMG_Wrh`89<+xr7k#7h>xz4=0XM~E836AX|)=x_TGjeTKMV*|O-K?sjsz-ov6 z%;Mnw0Vg3qhMsNLlRS$^EJ4D?=bSfyHr9;|mGf0#&`&Uw+CTvhApcTenV%2_;v+s- z=^A3e3-?}IsSmKklMiR_5v{Gl?nLrJ#Eh3Nh}~C+Eg-@F2l)w)`fm%s0+0-5o^Bi2 z86b3x`dIAqp82Qs;P`NP<;y?ndh6qHksNb)!m8Gh8LzyJmF*-H34UhPEv73K(m%TI z4y1)MO(;+2J@SoGeEL+n8T8QEsl3jxAKxfHP1UORc=ijWY9F~%)P(q^i5}&-@N;y6 zRX@^SISOi!6;9-7ZT~63aIxLQ10c~XzE(KXoiQ{*n)(uPNsV3}kbUJQSX=<@{L_tY zer=W=S|$`Jsg=6E63{v-CCSxZF7xtaq)Gyv#miuTdc1`H5)gD~@RA+-;Z^9q#~}gG zFfp7Ec?ntM2^7g!(7UQqQXaPiT))CA6Acv;3VGQ>gxWk=`G_18 z2Jfc4nZBTdb&=kzxFRX8K(Lr%Lxd({zNZ`n@rsASd5D*`g5eb`Svz;eZFBHnQPYd=Wq|9);J z5ufvRhcFwLjM~d3;wq&Snwb^MUh>|$$loDL&89~>N#TiUwNpZlEEnLVf4*y@{|zio zW49>k{|={z_~N09ut!R|>Vvcod_o|^0-dMX_bwk8if1B?9!Czgu;3bETv`p;nAiat z!f;iu9%gK0s}i0@!~L!B!xwUDpA?k7|MYm)!=+k_`BZIWxdo2AG}XI!MQZM?*Y4HO z!G>4U{K(tVT;SIg94QIVbP0Pd;ON*BT-&ZZsNjO4-1l{a`0r@3t6Lt#u!erlj4C+M zU;h_o;Ft$tMp##CC)GbXIbS?b0=O#jbUgBMTLs}ml%Ss8IOqq`h48Dlh=c;URzypG zt!*BYD)rm$C}_2>A(o-svUCM^W@&MQJ$F1j}1=@Xnf34y2`aip3eo{LB5hm`AOKh zj62`!6V%YF7ywE0Di<~!x#(CLlJM#Z?>>-SQG3*P#xj}19G5WD{BSW#xAPY)_U+@? z6?OYhKU{f=wG^A5k`KM$x+rkqDi48b|C~&WGqz9}*23CVHh=ZeJ9H$j%rn9b3ShRc zW-BXkA+nDQ?taH7fh=elaI2@8jim(D=@n)V=jgjg?## z|I6k5p)*6`MvMc{#fFsdCcWIP95-xt(ea99j7nPP!YT4~P7EPHCD7ZIyLIJ2XJy^& z3kTb{Ut+v0cNltrOl{cA1q0$TvTxL<3~>K}z?q8ZK`^nUlcUqGlFKVPL_V#Cd@nXG;O)l!N#_EMsow~z-kZ4F9dDuLOSIqdw=@^XKskJ^ar`k*9d zj=)_b1k{bM2K75@X>vKFE)9SY)z0uJ`9t&6Z5$_h=jhhnU*s+ z$l&)?k7#L@x6vmCQj22A_dIVGtAIQzT;DRUY$RU-{jb+BLe0n@mQgp@hdL(+Pg^fD z*ci>8M!wtpg{>O87q_x|7iy|)oRh>RE92QsDd+XrZsR=qOigc0awHt~QPDbd87Zu; zCyyVC3NRz2OQWbR>tVzKZvHRp-2VK5sj^#|!xQcDTAlp#-4E%(Voy=4xAic^PtI9u*!KuM z7Ky?d=7~1tL*oip4|}Opm_v^wiYdA5L!_LL;G`-~y~}G|yg%*~9-N6p-I-TCavt#w z^2|)VR`9<0yK@iz3xY|*NIGw8I5%m$JGP-Gm*(Ispv+PB$wqdYDgSj*b{M}pp@xxW zwJ%=T{fb%Y=r=T9AdiWRz}ew0MyH$;<7J=QhfoIei#+m4#7zrCg8r_!h%C77`BnV%ZHfC72wylmH(u+G6PN7b1t z4H&+y)UgdHla`FwZuS7MUxJyj5ZFXu#>f}|Oo=5ytD6C0Z}0W)#M$ZQdL;DdZI(?C z8R{%sQ3SsoNbc7_ut`Tjz5S2cIRTHzY=o*_4W%XUe-_s8zJSsq)T0PjI)!@djR!Sd zioR7?noPA&RkLMvia2n686tiG=Y967Kg)ab_%O7#6n`;(jZAgD#G`7?)}5qt@N~UQ z0MtbC`L)H)eW8FCx%6^0sk!aB)o&owqPb$8edG9#eyvidS~4}^NZg~Q+s3O6s*!lg z$LKGyZ~w_?4magVI{PzC{6WF-EiaQtbFD4x##BY}Gh_^!29s}DJgbIXkEI34@Qm|V zzk{a?5W4SR?b0?H`Xf>AD240K;Za1Acn{?=FjG0g(@>Y5s(Lq@+=&HF-2U~nMjw7o zkxp$Tcrj1qB7sL#v_~(l(VUm*EHyGG2lIg~J(Gs|Lr%SD4w9}UUx5YDA0#$*?dd44 zQLM!ndE^rJmPOmIXTX&}6v>$}A`8P`jC6!4&%oxMSRbd1(v+UU)}pfAiAC9f2`MYk zA9j+xKLKxlt(FXxPK{&OU#h4|Y`?AgLodUoD^Z(K4y*~k1FqD7%XA*P#uMV6{`Y$IXj#=Srxi)jj#&I`AZHsPv^PHH5`G_@EE2uVu4z zuP|za1(jTD86;H*byO30E72i_>Q2TQR_@*Iwsq}8$(ph!$^i9vIe(V$dII#YGDVw; z*M{W>4)yVnxYmJNo6VD*4@=um2dkiJ#$C}X7SmsJJbr8^ydmkoV`^xcHynPk+XqzT z`0}fM$KxXrkK)T7OBmc zWMebzb)6B>&WuXC(}tHX^;t8du4d`K7#J>2ScYE28?6B%GEPv*A|~OP^KrZ$mbaFz18%DcO~FjF|+v+-;S%Q^c%+$CbGil5oaVM zsuCSK^liTGo84C=^H>&1No(-0Zb4;YG(*MfkxMn|fhuSdkvP&&E5ljR;1jrJiTC17 z5GPFzrze9SEuuK+6{92YC4D1q-xY(sG)3U*uQL-%gbE;@&J({i-uHEoN-?jOv${FA zmXbv%0*^rj1T&$u%LPiPfrUbH)iHWyVj~~hui?~2Axh*gfcP=m#vkD8u$FzEXP_L@ zO^fO~&RD-;Ag+^9GDFRZchRD$A_f(p0{AsTGwh z-K2in=9qO0!f^?z3)s^t;}J2sw&|>&b>sLFh@0O|G@ZAYKRW^aLd8$o!`IW|qdzht zt2go}>BI~(!zrh;Va?0aR_&);1-68cTQ$#_S~ zMU#?wT?@{>?_VRlRI=v&WhA@`H)FOS%$H}nxm3LZPyks{^Om2m}Poq%(eAn@x zQ==7zr5{{Wiz>~0htA<9GYsBb1f#plV(2t~1KK_X#<6ueBFYJ7@ znr-O|ubs;tgiNhSarzfAaj~o8xFeT6Bd2`2>flh>Uo(L&Qj`&Grwl!PeZ1^Md{hsT!Htpl1C$Rm7`11M_mjqXXEI8lBdkIY6iNgY04k zM7*Ry!DN0o-F9m0ZAMVg-*%Z;cX6wO@OgA1;a}7vhMHR;^aEdVpeil^6zYMAk3^^k zqI)mhe=C>p2x-S``J8s^vBpTBG^R){~c)5!* zf+b#uA8Y_GI}dUW-*F2zKnO3{eP5ZfvzWQ5@HWjf6=UHyP_SOl#VU*q+*A209S!|* zr!;t8CL_XusPV`wK($0mX!@{!WE9l^tWBv2F4r4(~6~ z^7egf54aDDsvel#7vc6{O*zfT7JU?D@vp^-DdJL%?y3G}!@Z&bNj`HeKX*0PY3cK` zt*UF+7?c|C?DT+C*}6XOM3t!+yN?oEScDsbnTbilotKt-X~sg})08N*^aqaCS?x(j zvHH`fb@kco?M>?nJB*Z^M@`bheammg_kz_q>)hx|NuI5VTP!LO+^=Y3N#7qhb6Rh% z=kd7TZaz$H{oY$eg(E3l;2CcRh3EniF_UF6L!UT0AQ5v`p`J_M-=ovxQKt0C*PvM8 z=67yBcl(s2t4{~dW_*1>Voqj2W(uSAvOkyD(uFtm`wwDd{yCUzIHvx%2kp~`e{N-( z`|bM17Yt?|^7{a*jJsKawH69fIAaiJasE2XCkOvw)GtOi#{ImehUcjPBQf(x+dxB> zgZrOc5OI6G&0OG>HcYYR9MA(+zl?yI6&N2=9a#Zh0L#|wb1SJwCv8s(Y8` zUfu0p&D;4=Gzo$Dc^##duj#{#q7zI94%DgSfjszoU-(3BdQWT9OJd3BG*=cF5gH6E={xpU!2nw5cbf;vN)M4B)->`#jKD=sp>(W&( zMgAOw!?zV6S^nagO>sw4H+9rchk}Apk~_h(ohk)1N0!XSl%S$>)pX<=4|Qc)T=DTT zJ^{jM+}4xq=ilOaqlSj`f)7%(e;WUN?+l-#_pkC*Wd|3YxWVKK60$Ltw_1o~+aUBR z$b&ose)(=x?yMh1Y5v|>+I*_b7sT*v7^Nt@&b5_p)0F^C@HM4qL!rQl>?kK0J1MjP z=xK{%|K+tOLfwVu*bTOnrCBpf=@6upk9q+h7o$0hps$YQi92jx4{(a3I05??edW><9;^V*fR~;AnyZ+5Y=S@k$-NUj zLSuyo84lqYUXw|gDayYv;D+ZMsv2C$jTOy0NO~EWopeKgo$&vFkTkVvl9zg*-{NA5 zSza*&p?ZCD%6;Z%*=brisjP`qasr28_rI((tst|rHdM>M{LNSa5j->e{aPY-HeLYu|%m%#?mId>nC@!Q*m)Xh><%tZU&~8B3}Dc#1mYY^abs-2}iqY=sssU~Zlx^!R8Y59@jz zg0=y`>Mj;)=8p2h$tWE0Gvf~zUb|iMUc(WNF6p;t*~R+9*bFMd&;Pc<5+}|SS69wu zAk&2HIWL0gP?lEz81Rw*EQD`;ciS2ngUQf(OJ*1y5V1uaSxK)=kjtNuQS6N-Y=R|E z(?HtcrMQX2+x?Q~^zBb>LU{<5GYJ2nM!EA}o ztK!I#1kRn{?HzMsqN3-?74AE)ry;*sNeAxlj4sG})tgv-s0dMD_sl;I16h;x-AsbL z+(Ulvyt#`~sfnEq9~_qek>9s~>@_lbSBCu>rWe2<1BP4V-95gOR+ zELD2-FYM1lqg>vx96g*Ne=ZCupa7sr)z<2~Q67b|1BKRs1CFKVoTS`pEMhXb_-%0v zG%-{92j+*2&~AVzRgK!(H+AB!NAArUe#6gn=rjQH-+Lc34$LK|nm)W3lfjnrGqq}n zE`mIc7@5~!YcwyrW|LXC^3@u1qSZis=^(pRAZSJNR1oe3#;+t@}? zQ!-=Ez=E2H2jnt4eiZ{Xnhp%6fOZtP`m zFb`!1(-c{{ycsyZaz)^ll)!rJuEjOZQiuJ@_GahPuSCh*JK6&=X{*_>{_U1zEgw#i z2J7))TEw_Sb~x6<`9%Y503ISv%eLqo=&aBF$qVN#>Nr%^iQG&*kjX@#9m33Ky|<6GDM8)HIA8|jzqTmuOg{)g!<|% zD_`SH##V`D8D(~x=05gr@&m7M$cDnnE7y0wd@b_APLhqB_1#{yRpebE0R>1KeT~6* zXIhZie6Q0-=ZH>*Ux=yqnEWj=>pkMxQZN2ujya_6go6||V;y^5vdQ`Fua5OymXHklY2Q^Bf)VF{=E^Z@6B$ASb_Nus&a$ z&YVdbi~rSS&JjH{z86rcCTdxf;cVg!b=M+$Wp@j`jgsOslQ^Apn2$1tMR0>oHhN_e zvG-t@BIx%&7(sUh#M$)S*u`z#O)?bXC=5YheL&Hv*if05iC8TP4D^@Q%@bInGGee` zqz(3#q2pZ$HA2|Ks}o>IBz$9HFRIpnaSeblO z`2x8&Y(qe5sh8wGc(d;Wr0IEMRuXlr2RclE2)sm^+cg$Mit=91dqGU0B3^BaTlya$4n$9j+ zOJ7AU**NjIRq1}4zti!tAT8x=^a>W*^Kn)e==d{=;=$yZISJ~}7PN~#=D#;`7BCEI zI+z0DpoNKqIK?<4RsJDq*#-GX%WuP0K9Fa{24kvzQSOtAx=g58&={ks7@pc*v$wXy z@y`?%3r=hOdimY`EWq@kH`jT25ea%f>b@wymIhzAE!S7Rv%a%qphE}8?9+Mrfwnph zm4nryvm(i0-gQS(bMK$U5WSz<$TW&C>Xp8JctEIT+IHk7Q5@kjuO}m6l>W2AVOh%o za_1zHJIsiukEaQo|CCK=qgRfgsB*`tZ!P5BUJ>-E?H=oNVnVfeIVg0X&dIi^P9}bg zF8yqnf1Kj-6CZV(l6ZOY;uAcjKTor(}MdC3Fuq_Q3x*-=1*`k<)uB3hcE&7phOuYk3@!~mZM=R)u^Jrqcl>4J|=!yBCoOP2PudZxb^L8MxIqom%86@?% zmJ{n^TJrrbzaF=x7C&h74&N};uy-gXKItVpDV<-Cs$n>lD$ML<*IhT&=REOOQSj`} z)#JJ+&TkN<_Kw@;m9{dg-Y@-B$y&qCG8*Q|^g#O@o`la=cwdK3zoXOB$IArOs-i7O z3$JnoWO>%CHNyRctF&zHA21tmdrw*#l17o7MGmkkUCHT$8JDr%r$et7FlEMAx>$9O zkbJYn(Z5tbevqc>K(0jqrXl0-xce%XBca*Rh>4l zle)~)-Xn{LCiEALC(Sf+9Aw%u@EuP=ZgZf)K2k4nV`?YFWf6nG;ku>nXQ;V&FHi)L zjGfr21ur#z&M^woL+qI1{;mbra{Wn{n6b!!rbeCSiNSWq+K|pV@24{D7}SK%nt&X! zFW-YN#Iz-oS03*A_KcV=Et2Dg9SoEswngACbtVg=LFRqI^%Gra%jm? zc}g?6>4R>ci~eEnZqu#cS~Ke%niAQHYY>+MN7^#EaQ8<(D9(Dv(5gfWA*;2J499b> zj=EhbB&QyY0Za2JyEm#y>hJo)5!^-udw?%B3ptb4w8Ptg6472IQR}g= z_U%J=vMAx+Ju-4_ZdZ0A$gkCim1Ez(pTP=cVpKXcf-y4@BHbb*C|&vZ!gr= zMcb|_9@Ioc%_*gt)%zu!5~bEkPycPI(Rg!kG3vL&XAyYj$X&M_}jqe7sUXCZqO}oY`Y)9>u+%B15KbvOQWFYal~Q@Kzp6js#Tj2n&6P z{+LRz=@}G{UEkVs#C>lWaQI)#T?eWXxtJT!C z^+BOrX7fjce5TP>;D|A+lX!vGllEKnT&;hlI+}APIzG?D*rqtRo|ubT*h0sr(yqr@ zYxJ;R8>ATUCmASMgf!O;9Jhv9Pmz#l{^fwEM!$$BtLu_FXmTr zxC!kHE92s_n0@i+tWb3eR*>h9;H`cCCMSjo=QnTRBa6vD!b6NF$R*<{>jw$pD~VAl z`&JV(;sTXt5-Vw~344l$JS4?2I0wil)X)bpKS~N?yxFQmWZz;M-%%T!%C-DKkJ6Jq z+Ak`PTPLGdm#tMTeb6Y~T5lY(Dq7|2p~ItkUGXT%5LK-q4^F}5S#8ht@Bj+99@f3x zu3Oo>U{fIf883F{D#vZqEK;qZm$V``ecvTNnZvB1vcWguzM4(Dfsc@Y*1D)dqI13r z+kBT^AD+Hhf0o9ixQ<)z;6;nTs%k6s!!RUj&~nXHZ|o~B2s<2jm8YT@3W8xiy=6e0 z`Mli3^xfcqmb^z_Y<2UgV9K4qiL}$!JGD|NesP1cUoLhymuo2>G(R1(!e@QyPXa zz#M8efl}p^eoLauHf92p)~;67{eRY@GfdQw8x|1lwD7C+hZ6pxAKss73%Xkh3iaFb zgbO5Jg2C1^*DkQY1orXO#ps+4A+x*7N)jH zrVVhKFgv`6IAfT6{L4rO3?6Tcd1>>rjq%hT{W$E;!KT&DVOp}$>^&2@BRVT>u)YTD>zEfz?z=^>tuf1RbmLjBX%H7i}OEQ1Hyi~wc`~-)q`|TL- zl<>>#_jn;bxIBr?6xw=pn$WmO*KZO@W2Z3{J(Y%=*A0ZS`ukpaU4qG19f!0GHd;ml z{=BtKKaQoL0mtiH)dnZq)BATNBJCB3ONIlOb4F|K%21$#_DYF|=U_@p`Gg$yC za*DJJswyi=WatpWvDjic?7gDzBZK0!TDywJDK>wxf)s3sh_$6IbzS2NIV%Qbn8Ptc zFFE^gfea0T{4LmuoVdm}J3H|s)aAuYy(a@SND78u`JF^)i|wKRfgUpvDw7lvVx!Ma zX|HxmhI)V5d)IoGp~Uz+pqPhI4v5^tXS=idaZAGfQ*^6v*=bj+m3_VPD^1yYEf22~ z85n=HXY1lDE;{r|YzQQ-OQ036kjQ=*axP7!#VUgf(THf1GWG0UpM8v∾sHZ_T2I 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 z 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

bL&&oMLYVG>h5u(M_$7e6OI?J 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

dyDTxxsf%o@@T?q{z5n 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%0Au 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�B=q?fha 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�H?f@Wj*J1N1i{I(;MO+h`$V$nq|! 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/club/10_club.png b/web-clients/hearts/assets/club/10_club.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd0692f6b7d1fd2794432cf4c5c247505c6d3c3 GIT binary patch literal 2664 zcmV-u3YYbXP)#RoN3eX_=gFRmAaLSq6ppiS`>1w)J3 zq@aPuYXp5Lxp=9mmvp|#Sxq*3&YsK6IdgXZ4}Rlrvb(eYH~(d3{+S7BLkJI(u}sD= z`G83QlN=@?CPhpZY6K^^%;XZ2K_Hn@`A~8CNE!nlV>_X+IS`tnH1yi zH*DB2c=P7XL4sUB$I!KIF~vFu;6lrU0WeGGyL$C1Y06_j=g>Vk02gpsZ!`Im{bDj) z6v2DIh0UEix10UeI?-?}nm0#VvwFFdb|UC6UApvl5Yo?FS*F#-7Ong;VMCja?iuy>>#KHa z$4{QI+$dN|-L6f(Sq$1*wY_%K_lw7rN$+SUYPSh*XDAeU7|zblwnRotYkNX6j8L`X zfGsj&)>pE2qp3B?0zTUc8L^JJZu4%-y08jx5w;RL;C4zYzqj0gnAtmxH9Pkm@stdF zW@+UQwiFBk*H!%}JeGvn0L4(LAY#^sYq^5#G}ep^m^)k?#LRVgX(h>GoDqI)zRZac z1#l5gq>Q4K>s}Gzq@fqDM2+JFO8^jWAPDA$R_URY9Irp)%WD%MoX9fVvTpYJf|)ah zku$^a@7k|*c}9qv?<=~UVHs(o-%1KHlqJMVn7PiRug%I3+Lp2LPi*@>fZdV8)u>sl$lD__ek1J9E=vc_AkO_*gW+Wf61VqG0 z-jd5&v-*>iAOjiXtfgys=aS)CTUw)hcA}*08^<2S5+QDUtSYcG5*I-XK1+$9uBw}| zI}#URjZWNrS`gxNB<>bY;#8Uta>lpMwmYYn7KHdY$h13>PYXiQdZeCeBXQTCZF3}_ z7KF?eJeszH#U{%PX-f!3&wgRWvLYg66d|jY`?5}tDJLw*5g`eH;t4ykB%VMh*3RqE z2{2JhLES{bml_XRn)pM{u4Xb~wBP@Tzy8x@3zH@g2WmEPae}ewlv1LXLs69#tNCCt zevE+nGQ=B@hkAk$ggkuAGNy^ziT&I7TKcKxOWN(YQ8<<@5Hsw$DXD~rTCj2RrL0(s zQDNWf0o~uDo@==h9B2nwD{$~H=Se^|(0 zXOAmqDN0r@;#?9O+AI^WI-H=b;<1HFS%}fu^0F|rGq;W`#0UuBUiMm8WBhJg8W`$; zVnk(Awmx^?5gxOMkT{=Sd-xaMK7WVDhyN>2NTSPAyv^#O%ABOF2q9;v4XO~r@1|0q zcY3i0JrIO+TvNkUkjsko%vLpeW^9IlVhDi?}X(0d@dFd5{E_e z3Y1uv@bkbMr3k^4yPpRg54Thm)<-;B55d6eRP$v%B5qM=>|t)bbF{_0a%G_>OTN;V za7EwuQ>m8P`l$!kgw!6c*9f{UBK7_ff*z5s7ttqzh*Pg!5ppq& zQe3MY)UDfcMTjaDBPzkIPFxYvPK1os$#owIA&3VNLWB^c5t2_=OpJotLJ3!dOqrZV z42Wo8BfuZ_IJF;VksInj-gurFly+GdW=c(kXY6Mw_(2+VC)^u#IbYD`C^vkM zh@tOiqg{TYs6iTOrzo$#^Ebmzf>TZ5`i!hCJ1c{?1MTrDr4Qug#3)(aY4P+PxR)S} zj{b zYL}KO=kf-g5K(*IG3643L89`Pg5Bx9&(}6Y#Uc?4RWcE{>GxDdAgA9`9U$bvty{N9 z6Fx)d-~kBfYHMpFjra_mgDw!#*3i&E8u1xA2W<%IB}{(q>FLSH$;lzj_<-KtUM)8_ z7gGtJ!$SUHa;T!Bf;8h3blo2U7h~8zZ!zia?CgBR{Mft&3l?Z(Dc%KgkkQ!KxSu_2 zWYPyhGMV7#T}DbrBoZll`t<3z!oosr!h{K=HAyb2uC7iiEiHW#jYhv?Ph9{RO!^T+ zux&J(3Ctpw$uuS?4P2g|pa166sZ(FEdHeQl(xwA2J!)}!e1bU61T&sDnDl@rkP_0# z$j~h%OBXzbd5qVsC!`C(IR}upugZHljr*5CpsbHw4wPf zB18-!FLgqmG5J^5^J87`cwnsl%fUE8@CR?`WQ-v)gyE$w&vYvp&@E*^fBgJ^0R{kC Wd287uW~x*G0000Bf(DG57(pLOzKl((CO!X~yOQi?&E9)w?w#2^e>ld?W_Rz-Z|2OLnKN?(#<+qL zY$n+ZvNy@{$wFiSvO==e2Fr;qk+qSHk@bbIFSE z_uIB@8@qk`_83d9P{t^0tHl&q48X$3L<69f(0}#nRW2!yg)&Fkg8^8;WxY)H7d^26 zE{f&7;KG(KU*1FieFObRc|}D9!|+ikdoTbCw2i%cOk=bo%Spum1x;2FR6Vig?p~KOHmn{rGdj z=XZVjk+JKOa%EwlLhbyvCJscba_7HdoUGYnEPZ{k(9aJ90)xTq?CeZ-8isN0MrTqm zqOEAl7YCC1TRQ@aAom@HS+HeQ-`FZ(0Nk?kJK=pvkOGvn2ZH_rwcf6NYrbTH5hbt) zva>RtI}nli+Ns1qEcfG7?bkaQNGgkgV04q2;rz8(84N_Ua_7%;{M!5_uL`}Endvyh z#i$C=xRa4pTrf<5a5NYe5y__&kYpoqr)s?tF%2UxMDk8tVcNJXJCV2uF!(I)Lj*?R zLR#bALkvV@B<@yD`l&Pl(&XD`0}2BX7>T=;-AJC}5RTOKio{)iw#`UBEr2W)98KHN zS_&2!NQ@9Y`=yN=3K>WokWIzH*T0hyatN^g&OoM6?fxCM`jS|HC|EnMMDAEoBa*oA*E>&kij7uG0inj9^7NDrJrtYGrD4;@QnlueTH2(B?SmB_~Mm_Hm#+4 z_tt3wx|?yoYrPyXTS(Mo$Tbj5prNL9-@EV2e32}n@Z%s+#4ihkus#GZFx{L|Fs`&u zIWv6mvV0HVX{YYSw|Xh`4^xARNT0&@3<&(T>WS9V0h#VOZGd1Xc;@&I+PJIdxnJ2p zTzBdiDo!_TfuW$E6MXji#G7WaLc-DHz|i;*Skm{wb_DFKGFbjA5D4&kh-zXW41~o% z7zm4jFc204VIV99!a!IIgvCG@2#bL*5EcVrAS?#LKv)cf#Xz)>R%e|cfendj$g)Q= zbfUCQq^x3Z-2h1dA z5vr;vHFrm;+G3OjBI_t6S%)B}G!P^_my~ap_Wo!gf47`auB9lMN{Vwy%BsGW`Wa|- zB_D40^tdK1J9YFKh3|drSwW5O%&p}Xl1S*ly{xrpjj_9JIWV+@f@$?(7cUO5M4!b# zVtjhd(O-T0{Jqb)#YS2Jnd;^#-j3=bz8-R>Adn`$233HdWvEa)z1V}U1(0jk)o>N; zvZ6Ipq4QBx7;W)-h+<+O41}dL5S0$3QQ=yA2a@OFW-1Isg4V3aS7Kd4_Q7P@0Kt^I zp9dXJY^f@&k9f8og23x^^CdGPZq?*$Mw|+?*34X4?a7j_^d(%;_j~eF0D{aFnQ28* zfgni%YYnM%7Gt#IudV*v?EAC;f>wc>_BzR-(n&}un(nAsC4iKaf2K_z;Z~yW4=;R8 zeXGEvHXQ_)4A-pWuor9MqAyMdjaNc(v&2GNmh8kf)g>zNPMFI=C!Ws2K*s5fB!#;y zxT#bd+WJ`zu7T7Xtv6U!S=8103j{Snm9=OUB;wR-S3oYN(GWM;3hLHvxdNg}#)wLC zTPCi6v@?+SGP&U+5SDl`5C+1M1|(0DTNrsMw}}$2faETi#{}Xk={)~{*u4{SI>_xx zV$kh}=d#;+CJ{G1bKR+PE16J1S1$7(h{{J*cqvi01#}GrE~~2Y{j>+N|H~?M;t*tD zsD9Fp?7l-(T96PRa9MV5An*3`RB~0-f?9{rNF5i3yLrkkEWCd*1+XjT2KBOFi2lw& z(HGd(cvzbIioSm+b8b?jzca_=RS>u-85L0YToyWcT&U<95l3qy-anazvGH4|=1VCw ze78f@a$Iy!mRrFE!`udr(f7isJ<$S4W*sKFatDxi|7U!vBQot0r;2d>AfA-(d4U`{2ZtnN$l^d7huo#G=c?-p(6 zOcEW}{IvsOC%eA&a)g1%g<&ttT*tgIt$^6g3>1;L#y|uD(Xo|i1H@@<*R3B3rgH0W z^Ew7Hjhvo|h#*j>9l=@val7q7r&gi`5Vr+tckYUTNOD&b-Igw`M0p^hc4?_{F0b}L zMD2aYl#32QqVhKd>+ZR4u5F0wi$p9`$&_}}@2M;;r{7au0P^6@ojY6-KFeb806;p! z;V_qo&$1YF0!X-_p@B=pXITuw=+sNde(CM)%?O1;TrxhWudmO@$;rV~!Ut#}|BxN2 ztgPgc@kv(M9|4OQ^v_FVJslk#56O?MShZ@E!7atRjvO!=8ygSO!$z`x0Ldi7&$|TW zT3uaT;qdVAtb&39W6qp8TxybBRBdgoQC3#=C=!W$MZdZL7-R$JL$GZ$n+(k&hinlU zQUixNzY!nq6I8T$&C<RCwC#U0qC6M-;w`KQ%?zr4KEM z7K}D&O%yO~)Cd-7Ehf~Yl{QTXT6imxHa=Kev`rfys#xoj6*0buVoaJ8A+aP-8y1@NA-<)&i%$z&pQ6`ZvP3AJ0 z!{kjS8BBakJWR5gtWyYPaG6OvlL;mROgflcV)B&96DH$9@n|G~fO$-oGTFnVAU8MH zo0XNN_=%pS zq6qc_E^O7RRrlF{Uq|dHD=8`Yu&k_%%gG0aN0e)UTgu(P`lbZ%CNCt-M?h+7s?yWb zlN<;H`d}f=EiEl?TM5{w&o(Ki>zbJIA50MtinK*9DQBwoDl1=GCbe>K|5Y`0?0L?s zjcYn`R%a^3h51VHmV6OG;wUuqwW* znn8qJjmzWl412s@?*zJHX7KVG@5j9PaPTH2D(wx&)CZFVXjBDTcj|r~kkMFsNPQMw zK#GxIHjtw=nIR(>XW$lO0q&=${98lMqk4ym@44OwxPZ$-@5}JPE8f}~F<$7!y=(Pc zTbNm(aa8O(YUsO_`q%i7v_8&eeN9_es12F9rf>8uLPutA7;^Uv)g$>V%>z^oWqJDW-Ag%1&XCO=1oo{ zLUQL5=0F@s0EFf#&R^ty3ENRwmNHacb(7lb&O zfEvx@DG#Ac-CdcuKl|A5 zG!K zs+fVP!NrW_%hd52tFXK31lNP2%1aB?WHB^Hz;hwqfV}-bo_dy$;SqJ>?aYzA$}i2A zm2=JQN^eLOzL}AQm|^9)OcA1YMi8wkx`I+2vzE#|+hZhjf6n+>+m(Q7AwiKQ56OrT zAX_!-X^mk;Xpyp_EzEp>hYcCOsWKp#?~1%)%cG|}OK7-~akWD!*tT=V&oKejcvxV40-(o& z;HbA((Rk{RN`_1|z2V$dv^fmXgjk+aM|C0u1R{h8 zArK*iNO09!Cn#V;p&E*~Q4AfatP_QJc(*TSO{Q9KA;U6)df|#Wb-a&Jd-lBgX%rv> zq~M(p+1CuloVwJ6z#_^j4sv-p2tb7;io9jD7^w*nwUm;~D{Mt5Y{CrD*s04HDGl{R^HL*KTg#83ki z!>c!C=(>kbsxgZQ3GwMwCw_M9`uikV@?081!fl>nZ?7&O%_`fH5Yj~VAPXU|3>jLd zEE@wjPDtlXIa~#~tYFK$Do4u5-l5MpHU zGPeUYUOd;1cYgID1lHUuHFV} z)oocKM3#yXnP62XmI&z}LT2jZmV<;4_=5-`LI}bLNtbwI7N=mfP{I-+X^T^dffs~V9nrCaS6L7jLg2EDZXj>0|nHB-lpHP#*yt}L8ij{wKWz0Xs)4{wiD-b_$FdOQaictX9N}6c&aY=; zY;p_L3?WLxvtb`#5o9Nbax1uDh}Fa~crL8k6I6hnd6?kL9f-VltzPYT@Mvtf58RI^ z2!9>HYy~_XzPNCc+8RSiO@8$q9is>{H>1b=KZ-Ii_if}|5IZX0RWj^eQEvJ>A`yK* z%XZZjMI&@0jTGfY+V~h`U{zDNzDU-F{e0JJ?}ymcrI&sY%y2-->VBQ8_rSflDL-=M zPM=2BByr=Mzv~DwQeEG6B|wCTCBs;ixf|=oTt$e{%0M24YeWb~LfmL2t|7#1Yj;~5 zNtn&nVdXd?BnHf`iHIc7O>YFdf)J~(J-EqATtSFcg&G~ZB0>bYtLbjbEmk5uA-vww zl4V_9*Av3)-FFPRxFJcDep9f!_aCTp8@yr>kBKUgaNY3xY=$d`-)B2ONMBD+4{5?- zXdLu`kZ!- zND>o#-eaV6*3{HwkB*Mc%gV}97A#mmS`*}=s;jG&qN1Wlfk5DE_M=N6gUJwL2wofY zGJ#p7Fj>k3rGfeB>FLieS+Zn`&EDQ#(xwS8Jt`r3e1tg81S6iene>AvkmAwENYpGP zSrdGRdCb?W$D;|sJSH@G%H&@rqf8LUhcp?+cZ_9?X$Oomd7^!Pq!BVtnH=vTLii9e zt`YK>$v>K&M>N6rvANnWCqf9pA3Ud#F^9m_L9rx-rc*qGdr_zzT~Lu{hK}CoO9;PoS6-1QwYXL z8j}S~USpEOB+Mkhq=3nKjo<`Vn6xvQWHQL4i^(M>PnbMrG7*)4K>`R^$YceR{Y;7q z3kySed3jnm9M->a)22gM))wBofgsUc5NOF3&QlVseYgBZDCADJF}V z6yp86ckiCOef#z#K`fwS=-RNDLW2Wvp=H1Tm?aEdyLOE<)VUB zYTMu4I(@yX^03zX_x*(L-MBVa+xJnaGRo;=?X0P9)EXMkX+tBUGhW+}pF8W`cn1E> zn>YUkLWY?u%dqp|qS8;awvNuEukZW#gJ~t>248u7N7DD!R__&ZgHF(J`n*>8bl*ov7vYnqDPU*dN z04{=}W5=16_N1@9y=A=?%1D<^1{7OT@s%wFgTS4Y-*As5L6)Ehz0qGFd8|db6?!Ni`F9JgQ_#Fa+KKnYXYlT4h8HCENC zHSAS|5T}{ATR4eRo)cn~y{ndq^B_fOLab(gRm;TP!fqz-IU!~NpCEw{_*AcZtjr|T zZYD2;5F|*ZZp-61vYK-?Z3i1Ibm0jhSSMF0$Rc}|1-qk4VJ^$eO5n1*9EM^lgZKJ( zDnM-k*58#N#L7y%9&Obf+G{J8#1ja`+W9;>fs<+)afDd-POnE>P;h(m(Ud0s(6je5 znUU=eKhQsqsUNEW1S)ADP9SWycSC-T>FZ`|?V^BQ4nK1aw|wNj5aAn)K0 zCuR~dGRj6wi?vfn4(M%1hl;N?+s4R3%&_aGJRv07E6s+uxG}39C#qf5`*&F+bblqB zWk7qQ;=4S=Dvqd}Bqo~T>GB|d5=%(FKM85;=t?*<>_z@0l#mS;7J{3WInQLbqhOsw z^c22OLNMa68vo0jiFIPRqODr^T$W`%B4Ik-%3YZyt)dBWG|Iy8&}w)YJ9S_+1+5P$ z6{$kO=*n!CVQ6?%XnV080XwTSf_wx50q>{Z36f(7fe0Z&2t)`GLLfqj5CRcGAVP=` z0ue%l5Qq>Wgg}H4Ap|0XK!gw>1R{h8A@D$&pBjq-HWaF1vk!`)la+O%E(~?WC}l-m zm`W!PS-}@|S=hF4^7J`JdrCkCNWq>E8Qa=ykr4=}O^ALRYvp0nGlK1)qO4fo9i^(p zC{2i{qm)D)f;^`QLBVrT=^kO<4-5ITwLv*cQL>a2`$bABz7+Z!u)3lhdptd^$(KPL zF{9v}4?R=V)Xv;GvXEpz0Qa)j!W!du+frg^0E%goaC8$6utdxvLgIXS&GDb5{eG2k zswfc>9pWZn+){#uftv6RcUJ8d>da>jydTAxdZeQrE2Lb#5yc5y6f^8?_L z;hL2k_F_$(cjNqksZPjmmY9pn5?$D)I(QY{adTM+;`138$T)qFBzKnuH#OIWwlekL znvj~~jT*twMSY`OLS#H~O=a*n_1YC7m*>$CH`Na6)@`{WM3ssWmEcw?h_pM*Rg;C3Z3==R5#k=vR^ zDvxy)9@NQ7Vmj#BT=|5kd{l*(Kvjwo76O-5QU2b%C*;uQ73$<6sK8MDq#e<*gI8G) z7ee5&>^?x=?eD4Ns;W6z2iHs;4Lf`CJK@U0_ot$OeQ^({7exl|dk*q$V0-gXVeTvX z{o#zoDUJTlo)FhT;HE@$K<;x{2=Ztsj}b?r-iYr{WnpaU5vn;tl!kk&trp{=gQDCD z8VqrpI7YtGN*sToYQMg8ga3sW!R^l5%oc4CV#gX7#whlL+BSI|T^h`t~ zfqvQ%>PmH2`Xw+gj8cSVE@^aFQBpA9s z1}+w`Kb~dM-`(B)fcdffb?eq?WGUVSa*)y7+y`)VCV0zTz^!N~QoC#(;Z!sAFPaq{=kdba!N~R&WhIu??SWmzZf^$q7 z@`TBMOvacXkPjO&f@{oWjT;}BVDi|werOP~P@9_XB0~5OGGP$%h{?Z(o<|MA^>~`` z;$$2lc*D~M84HLEZkRCSkzpm{hNX-f*N^`fU;wwnE`r6gKED6}002ovPDHLkV1hQJ Bvg-f< literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/club/1_club.png b/web-clients/hearts/assets/club/1_club.png new file mode 100644 index 0000000000000000000000000000000000000000..f739465b1653bdc793becb325c774a4810fcce81 GIT binary patch literal 2599 zcmV+?3fT3DP)(RCwC#U0Y~WM;Jc4YPF5Iy|e)( z5nHf=iIIYW(Z*O!Ar*oa3L)C$t(vy@U~Rn=qz~0t>r*90d}*pu=tE4w3dR&~Q7~A{ zrJ#Yv7%!j?B^MhT>m{AH2sY0d* zc~?k*kSrk~Aw@!#S_~Cj5^_<=05`TwI)4 zSXgLfWo6k{T(M$>Eez*4d-kj?z`($O)!yE2ojZ4KP`o@TWVetTLLN(ktXG806jF@O zZ{EClw70i+lwlTVW3;u@m}1ERxUkZp074T6uU@^%E#)!L=4g9x04`v%UKjF*cw;t9 z6vKPKge_XM=#KdBJ9xdNs;Y{+s?Pui-~t-ba^}pL_f#GBvE$9wvBu_`+R!!A9l4PKBZTq%v3=y%&o%M$GbKN)EJ60$ZdJxXc%uIK4k-?#1XPpdxv5z(TJU+vTWEZ`#S){%Ez`^(YiFI?^*M+O?UqGp$)1_pr}w|%GeKEOp- zBq**Q#+gR_L(fzRe}P`_6fo5wMi;QQHhEr`63$*Y*cun96EJ_JJyR6<`TnYa#O@V7iQSqZg6_KZZf*~>^vB@@@8 zjk^zeM@XVbDL(~A=OrPknYdfPS2_K=VK==l9`dBADwt0r^wphBJ0-<;4auFIBOUup z5}~i3!!=Gbd36m*Fzg<2=JA}m-=Xh>%+wJ{#5Y+vFa7j8^mUVoyZ+k_GkGOKQkhXp zb~9d@k$lbBv=byskhLX-T}kX>s@Wd2SGj#i^#oqQjiVEbnqym9Kc?%dOsL3`#$ zL<3*^^-xMBJm}dwgv43}eE)-0OOpl=2Wz+5q5_lwp-#)umoTcS!zQE7>Ew~`J-6#H zT}T#Va|9%^@HZfD&w(RjOz-V0O?HE0F8xHyMXN6+3tuD1g3nMj!=X?}&4(l!cGu~P zOlk}2!b2!jb>LKsX46T)CZm=FdN!h|p(ObCMsVL}*82ou6!LYNQ+6T*ZrAxsE^31LDQ z6Pyqfu%S>5)srZOj#p%dVm++wLroZ#2l%<@b3zh=^%zHwpK`PvZ3G|#q|{WeBfVd6 zAPBLyW8Jn-+k#E(7mU?WR5gY)A*QxcGPMcvgeC+9&t)677`r|+;>1CPGLv-vbpwpcxc;CzT!U zd?%#q8VysyCM(i2+vx1QNFmxHm4`5x5GI5{oDeVeTny5^_)bWki^Eiy5Cd4YxPZhE zxTziD0!Ijj-2L3>I9gLF>`dg@;35*Q6D^nQjJUNe82i3s&~dq4xw6!gDPQ9gROoRS zI8-@DgBm~xDpyRF6&WQ2MGBZ}m}qAf!tvMFerfx@KoA10z@fb=HB>B2VZ&{cS+ z&1AuePi7#HQ9Vdfd!`N>%Exi*YX{ea;N%*HY>S3Qe+fa4pnSrC*U+)+wJSm{wDDPl zu^rT{*>Xh)m5LEcaN8!X2XT2NS}CFpLqBN2p?i3fvY-xFRHSZaO2n zljitGh|`mhCj;D$`i9;9@mw}rFObTyuEw1@Ye`fGUE;niT+fGiy_A_MbS$yfG9Lny zRa5=pq}PtUJ8S6VA*jHhzSE9r-=V84NZXvcS6gBLm@1`WB6V)jp|$G7tGz>T{n`}F z!}gd1>Zy~V)nvWw*bW&pUya?3 zUyh(!0gs2TT=%}+8)He$n72BGQG~Jkmmu&!Q3mF|odgA5RK7=?x~H4ZM6VHvYx_mE zYwsu;CyaDblsD9UI&LSyuBI@3@w6>7Bh9`K+>ciweIWPkbyBhl^Ae=|h};Hdsldse zBte|>4;&#*s_R=XcQ7Gl$#Aw8Nf7JC0!4_^%0L~3YfOknLV~Czfgwb-w+GFSgeS6g zxcMFvk_4)IA|eS4(u&|f5aM>(Ly)v25QMmGP^V*8Oo$YYHq9x=B(X~p8%D%jT zCq&o6dn>TNAYxoSw!F>?Y z)85|BE#fmI2R$I9y{V~*Tf}Eb4%*>E%7pyV-`}5>m6gRU;{yf;2CVGtYz!rQ1P%FH z$l>bhYHk^yAlv@1&qvLDwtMftzg$%)mVA*J<5IB%*A#;VG zG_W);FYmQEbLPAV%li8IxHT0Z+R=(>$A|FaLNMZaLr6b(0x2O$Mw--=3@LaG^>{^U zPe=+w9ivj73i(gSh!8mPAt?{=IwTu@x{y~T5ou9`OtYSkcQGM)2ze$6c`W2#ArB=f z!}9f`kko*wQX8g65j0)?ehQPJ4bP-JmRj;iYRV(|`pN$S3;>!!&0zvXqyqo|002ov JPDHLkV1hg}c8qyEAycMz;q__n3OZg&CbqF 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 Qt^fc407*qoM6N<$f`O{)K>z>% literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/club/4_club.png b/web-clients/hearts/assets/club/4_club.png new file mode 100644 index 0000000000000000000000000000000000000000..91d2782e5c2dcb9be754dee40759a7f02938d3f9 GIT binary patch literal 2494 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 D7cKbn literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/club/9_club.png b/web-clients/hearts/assets/club/9_club.png new file mode 100644 index 0000000000000000000000000000000000000000..bbf9678c3dc860afc426033e0b794cc3d5339226 GIT binary patch literal 2647 zcmV-d3aIsoP)wE zHUgSdlA?k%(T9eMmqJzOe224U1@`QoIWyHuKL+fQ=#;Ayc_b z;qn%jOfIQh0$g&qtY8EYT;bBpWrRx~mv%0fxjf_Yl*@2f0wxI{U>cWsT=sCu&&$gT zWoKuz)YMet7gw!XWeCAOE?&H72+-Hp$68xk*`-UD`uWQ`E~Q*Fmh|xdeG?A6u&Ag=3K>mT+b8^cC?$z4etkZ*d=#MV!9itZWg#@AzM-Mv z9Z`qf{r7!#@Vg(_>9gl8KNm_)V!J>4h?Nv=)Vgu-Jmr~!@ntpCBI7v9TVn#DG4 zT*o%OzfOtcU%h(uuOMWAo3dn)9{~xw4wR3(aVw;>{#QQv|o*@tjJP3qB zp%H{)BIYT-aJ$fjp)GY)N3l@(<{D()|0Jx{cD z05P%vE`lOoY>#mhb*GMSIc(TjE1auu)`XDro_u#A2ociVb1#N=WIlI(mc;(qsRbcU zdb#Xp5F(^YK)neH36TZ(5gp(pQbN+3FofuW^x3n7zni&efz*4MI@uZ@p)H~+WaHfu zOfN<$AhI&~Nkxdr$bwxH3_;|D2vfuqP8ySiNJ=FcV~N4F$cISG#HDCs=`kWiW+v_w zB7Q2U$~+heq$c@_>}=XDDaxIC2G78oEZ&EC*tGFocJ6{6LnAWBn^b4=LWC?{G@r4v z(cceGS`l1w>gfG4=K*xi#2sJTW+opLeZVv2U&nk<6;qvJ8oj`?Yp>+VqAN}vBf6L| z%Z+lu_tvanWqV7sAOzX7S6II$$JXaDr;hRWNrt4vZBuC@H`K*t4F8YXAM z7T29SiaK_GS{OeWfq)!Bte^`aB6H@E1Y&Ndf8b%<--o$AR<^^Qc8C&!4Ad%|!)&2$ zghWPvu}YTEvokp%1)uDD!EZL#9%nmC%Z;g9EB^{pE#f~xh)~!IGGxqUxLtLEUXET{ zQoPYf7RPp~Odig|-{8Iuet&A*@JlFVCOdO=CdJ|oslsq{QV)}#y` z(37Z(H+b2etuZ>?U*rDP)Y4`ID`C+l4~aD?6SlLl>@9kvu0Z3DBguuJK!}i7v31Ud zj}4W_5Q@wg-8C|>IpmFBA^#L=8OVr}>V#P$dw ztukSlC=5zsIfBjulZdWzEqq)5z@yO+Se4n5nW>K*LJ1>W$w<&(=!D>sQzvNV)Coig z5keqBh!AQ5B7{JM5FrF2ga{!JAw&p)2q8iULhKv@edSg|!E80xR*;57101-Uy%yRycC{@fh9=N3UThnSwJo}Ad9Dp1(2DYt zKY4cjQjNBf(t?nQ4o`76s%!IflQRtoIZyYX3n9=99eSr5YtVf`$n^v`At9j%Y1Cvx z{_qF^`49pTLWB_fLx_{jz7p|XJSQZ>!C@*yhyq~S4ISnsRP7MwJ3=tz?&U_uk(#Q* z{D^DwAxON=)n73(;wFu94{PnsVk?cxl@+c``6{2nm3`immjEHCTv1t8q?8a8DPXRl zJHgI8gyXL$`$EZ~Wed8mX!tUPg@em?4%GxTi zsLc?QqR>>0}~}lcyzVhty0RH&$15M0sO{50H}L+jzQN|& zMrXr);C@s=`Emr&3i$A0#^{Y> zNljU}HjYsQn5@Gu{0;N}D9XUxx1F^hZdAS-WVpSfT;v*&sJ5SHyT*>9QNl<&MR@}q z7ov6&>}m?r7fstjDM`kC;C|c+>3w-PF-les#<_bB%!{A$BVQg)Y-djrKhF94ju1Q5 z^-V2pM2K24>{Xfjv2M&)gxIYNlu@`wgh(XBk6PjzLPUGJ-~320k+s9g_lS@f5Zx0I zNuZxr1p9&zr^_Dvq$R!}#A$=t9lIhz6q&0?v*i~p(Vh@ltF(04m)G}%$Xff3As0U+ ziP|3u*4=Z@nA?!$i)2hxsf6!_-xC?W9DYx9fROul?%bi4@E9fs_d!T!YildDh{rHF z=ma6HH8nNVA|Au!pcPI%pUaQEy}e1Psj1X59-yzUkENxhVJP84XvjZYP81gxQ_FY+ zv+YlSiz)m+uW;$<=;(OJ?by=g%a=3K6!#oC$f&KYJ<4C!a_I*l$z1U7T~5mN%F4=| z!NI|4+1c4_#*7)%YKlx$MMVWGC@6T`*4FkV|I=lV!DRqG1j|N4T%ZY2dny zjEtA(&Yk<5&91I4YE1#~c4TAP@iF{37mRq`;?fJAKuW+QBgxd16jSgT>M`Bao`5L? zag3PqjLUyq2D!kI518@*uQ8T2WPV|o%Tx39W0R0+Y;?Sf2$4g`ut~@hF8`YC{Kyo% z9-3;tIWmS2eBdRMj44EhGz^>a#MF`@Q&Wb_*H8Z!U;qOqZz7pl+F$?x002ovPDHLk FV1g~J=otV2 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/10_diamond.png b/web-clients/hearts/assets/diamond/10_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..92ab7b67d692853e63a204f452ce81231bfd08e1 GIT binary patch literal 2549 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 N002ovPDHLkV1h_zL974( literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/12_diamond.png b/web-clients/hearts/assets/diamond/12_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..f4c7d85425bdfd53100a68fd83f318a0158c0e8c GIT binary patch literal 2489 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/1_diamond.png b/web-clients/hearts/assets/diamond/1_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..50712b2014d88292b8381dc16876c061f34ee902 GIT binary patch literal 2468 zcmV;V30wAwP)WYE6BEz zeMMG7mLl6i_KoKd2Y-=WBU>b!BKwy{fS#lVMTl}x4}`F$ zrl!aAWi#@}&wKXlab#!&#vUAi3wX%T@bK`raTE6aD_6YxmoFFn`Q{@>yxI*LtQoAK z?r!g^o*r*?b2EG5Z*On^6NJ2^P*xT9Kx2mvd5?#OBN5Wj)nx@4H;x_iCtG<{mG|Ab zbLA(MCS<{kLwG?@^_xBxEFNoNwbN2vrt zk{_BvCJn+E!WkD55fV2a%shQ+Bq8vOVkQhoi!&M735h$~XP!JUQc*pRkl%drD7;zY zA+-$+)`YF7*HWCyi_JsUwzpd$eKE^(6;+h;zaH~vSqKRWJzs3vWW4l6E*sjnFVQh@ zQ9OR?l=+0<>egiGi%>I0c|gYBGI8O8H06~}GP}ZnGDF3hHOA%;gc_ND2g06=B%kK= zj(mjZmc9rvQR;8S0^u*|dBr9qY<7hyEZx!p^B@9yd^TS{Q5MD63l6tGmg&S!O z4^e#_ok<>{4Z$L^MprV~bQAs0YS`s0qRDBU{T27pZtf)3e{2Ajt z#H0le2s;hCcNd++x1K&NC5cN(>V*hF2nbgCU2JMHHivwWoDU!N&#h455$DGxMk0Gi zF(u~gEA+6d^+5WX1cafm(g#8t=L*I&N0`Z;Jp~CdY{3JL*ZO8FFD^wTC8=WoSBETM$c?}FY?w?odGR&E z6GAE~xEzXVIpA>wJXz&A=tnA*k{_}h49g)7ju1zPgCoQd;@}8zaD+HQ92_Bz5C=zy zBgDZG;s|kYgg7`t93c*l5J!lEBg7Hn;0VcsJ7>=LRthMy{RFTxL+}V4R!wrRy>%WE z0<6RzKY4QLHNNK9+bK3I*9RqHWg#J5%_l!`-$aUlz2WtpO=A_)$~yQV57M0RI170OF>%}W^}D2s4(MpL1@t}D!UN(jkbe`_OT zck|RrNbdSuTOqTXr#6+veWOVSw)OR~-PmGRS-J~`T<658yx0gSwEossa4RnsLW*5~ zYb!XF7YiXtI$hcVu5)A|1m%VnMVr^_K+qQ(kd9G^+r2H&3HN zR<`movAm+9o2QY4_zEUMhh`;8P*FEe<8nwYhPu18FDZr4P;n)0WDdziE2$Zs%1f7` zGA?9gCwb%(UF8+d{^(W`5+r#Yo}`dOsY|pRLEMI?R9m&N-7qc4J(V393g%_D01B})R~Ff_>~+Xf$|C~ui!nDU~Gi7 z?J9uf$}1>~Y`b*HPBLt6R{`X%8^+frFP_OJA^L;bur#>fs zV1ewdc>P)sQtrL)x$X#&L&$<4WS;ClG0ro>@OrLHyt$Y|2tM$MAY+9iLmC!@%?mG? i6P_|BUcdccfB^uzR}_8&LQUnj3j>Bm z!$P{zU@*;C6MoX4L=tTmO;KFvLLxh((M{86V9|{xu9{$U<3a=N1~lS^1|hM!kT~e3 zn24Af4JHk!V4*1VeAoBvWMtl(dGG$d+%GxGI5SV){q8;IyXW3_Pr`YJf;3x0R!G)J zww0`cEJ3!D>_@WJrlzLy`ucjO zqN0LbvAMaKnMMA%apMLvV0L!aNu^TG$jHbGdO1k;Gub5Bl1q?NOjbhHgwG#2a%APv zqem+iVu3bBTe~Bs$>jiCIHec>G!kCiy?fWTlw_dI(e~f~T)<_mCmW+TYT%+QXb8i<%&~OTFQRs%FUaF{(p%? z;#EO;d3kBr3yd5+nim-WJ|8ribim}*tBefR@m{@hZl65KI-p2^i-NF$9B%6Qojc)f zmTvTktIKr+Vj&2~>`3Txd4P`Nl-%nzG!R zH@eqv-|p1z-Yw*JC_o=1{iVh4B8QLFJN?hN^=!e$wertiA$HnxIt20 zqa=r;D6aw$H|(e9F*>$zSbLGJsAMTGu7sdx1Z8sJs)Ah5ds#xJd2o{@y0=W*OBOP!nyyil@$lyW<0(p?Cz$O7zfjr2C@<`vX z>u_3ck4y+$m0uvoVvepmO?U)(xIUhXRgnlmAP<_6@96G!bcRPt7$7e4R*jJe37TZ7 zoO9%>ypnl#9Jo3Woh>vWn34M>=isVT&N;#;ueu!bYZ&>BXU_^r|Ab1vBarvEw)(~n z^dLXq%ryJ)~ys!ri zDHd4^YQi=-ScFqq)@5l1ONb@J!V+Q$v9N?#LM$vHmJka|h$Y0r5@KNqv4mJyLM$N` zmJmybg(buiVqpofu!LAbWa0j~bIjs^HKyMH9*gkKRlx>6(R*+02=M`);7Wh`7eAYF zXj(QHyK^zyGb-4%{@vi95eGGYK!(XX7qcDZihpD82|o1Lx~w$dz)HUdf=oF*I~IiC zMD1J-ti)$bR9;3Af`ifW>G@D!P+^u3L5eEO+3Th$FCz%aP^coF|WMZbSB_X*S z-4O+{YD$G6L_3$|9RV(i4BeHNc7(8bgM@QZbX8tj5rR}lzI8m}ro6Nv1P5sb9pEoS z$x#Q;DZQdaP!Fn%CIblastc595!4Y_S%6hY1|X`YlyNQ#4WUDkFz2fLCxwvo{kJB9cQsF?gk*L@O^Lgyg#a)>Md8UP1^l;TUmU?@i6MB_Pj$_7Q6ocSO-A9##p`?b#wNIneq2sUauFF*JRKVcGI&+FH=FVbTcKG7L|60F%4MZ1FCEh>GOBrMNeELgc~oeYq68&X z^VBYeWMZhJL;03c2n`uCaV=v=CYngis8n966qR-^D?P{~o~TN%uzXu}wH9tundY8f1KrMO)b1(Vy7qP{=@nGFPIh%^C%d&h$wB18mJW(aYn7EP z(25B1xF!=2njVs=Eg@cdg*PcoVrzD!h7p8#%8O@^$H-9q=(Ev;FeOAPh{wW~j*7}i zLI5mmAA*`iwZ~+NhJQ!|YzsDMuA6m-W84S64HYlq+^< zmKKQ}AuJx`xNjKhOvhvVVn>Lly!_HDcn>KU6Jcz*3ShPL3eqCGdV9?z!{l-mK<2(- z{H*iliP*ZV)s&ZsiYj(4%L9%F1WXL#nJz09gv15L$B;MzgiKFOP1%-E43~px5b`jU zO4$}s43~q4ASBh_-)~z)F&K)UbuHiL? zN3lD460TW<$BJuj$^Iol literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/3_diamond.png b/web-clients/hearts/assets/diamond/3_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..6d596c5260cf4d5d868e1bd26c4f8aee9cf887d0 GIT binary patch literal 2538 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 Aga7~l literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/4_diamond.png b/web-clients/hearts/assets/diamond/4_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..e6f44bb253bc0e76ee56015b307ec4d8e5b93920 GIT binary patch literal 2313 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/5_diamond.png b/web-clients/hearts/assets/diamond/5_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..fbc0c39f9238f379a5f1fd1536bf134a275f8ec2 GIT binary patch literal 2479 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/6_diamond.png b/web-clients/hearts/assets/diamond/6_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..55511e200a0efc957dbba2cf8b6f74b6c884ff77 GIT binary patch literal 2521 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/8_diamond.png b/web-clients/hearts/assets/diamond/8_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..5d7b3af34a5b1154692b205c813d69fe17ea1d54 GIT binary patch literal 2569 zcmV+k3ikDhP)R}_AOVoiYpU6^8Q zG%UnT4F=LcO$1WgL=tUR#h(~mNOWg3x@j7XF1pd^stE=+EHu&;Xv7T-LSl6xajYB1 z#J@-|m^9!I7DS=vd)^__Df4FDefRfqzvL+6FwZyld-t60o_F6l3GX9{GHfZ?60%KX z>&Ys}5@Z|6zVRG*@F&>~vN^H|vcJfN$Ucz0C!0-Mf{_3Mipi?UekN;eYHBL4t*!Mc zDk}UVHa9o><`5p&uV42Kn3$OGlF6huI5_x{UiOjwO7@6sh7sf~BP%6q!tWnEcyR9V zH!zF zVZ(+I`mqiHeD|I`dm@uD^X82=o=W9>e??uL8~Gf-*n@+vuCCpfA^igb1K;un>=6o9 z_c}TP$pDJW%DgXITD+QFyS&P^Ypofq{`Pin{ec70FDL~4mX?-3K*%d{Wo0}E89sg5 zOI^4S`g32=7yN4fe&flwb^N&Z=<;R%V%mKEyz~nxkx0BQDlacD=VnG+>4lavasb%qZlXKpNbdF@(esa7A!Q zp~xfm<_M9jsKN*n8On=`kbJJlCg3W+#i)lh2=f{rmPs zI>yMrfWJW2N=Ws#ZT{*t7si+`9t-fvkj2HNrCJr$5XFHYMO7%UKo+IEkUBvYn9J|- zPIb(TO=r)}t1%rII(*o_xvgLORKSixEu* z0QUzss6}OA%0roio$_#FV6tbxL{a1advBi)|3KCDl#7sjCymthy>sXC?!D4|gK8nb4F#PS zT${`tj9ke@W6+9It-Fgt#@dez97f)qNwUv?%NE)BCt8X3IFMflEj1^U~dE74TI z9c3#ocmk331RA)Ex{A>JE+&M~H(X#1Z0#z!Bo$2yuis zI6@pD4vr8B<}-5|O%iv7myL_#GRSmsNydcYT;EAL>hH(c?u;NKgsz zAlRn7tRSS265u&ME1=4oBP0u`jT@zM5T5LcS`O9`l6E zQ=zMrL0t0P*k$xMm`|O>#o0IL{Jym$0G`4^^~&C zWnmz6RJdM9d8z2;X*3~WJEN%x^0K>m8cPUIXEYU%-ObZTLZWm=i@WktuCj8~Gc*yZ zm6vjrWs0H-B{(AXlrq|7MZM9aLwTvrc_||VX^|1d9d$%0ubT?vof1Ma_utwG(cL_? z5|X|D)>eq@=BZ6($-dE~15vwqYE@af6Na+BlT76$jgWl%Z*7Ha_#Mp@w9S?Yk=;DC65{(^`XY@M2YJ!mJhc-7U~{wR4$ZbJ zDy@Y0SDL^M&2dmv+6kHW#TG0aWp?w_Dti}#4Ow8BSzWENH<$9_?a-_Ovb%X2<+3uB zmx<{W^k&pqQAq2~#V{S3l_)_)-8_wpA=&6}Z`Z!16hcGAO5Dg8l8q)(Gdh)*E=6UW z%gPM$h$p(zD>D0|TS-Vd$m>Y2=u}ij6XFNe=4PcUV`L3XtI=rOQ@Cggt|Gm%qQ2g1 zIB~)_*==kk2bnjvOi)xttE^msRz{G=F?|7HXpu}~2}!3{M3dr6Y=e8d8(j?u11B=b zV`k`n^x0}cd?iFGNW_gT6BU(}gaEj)g*;Q-6qQvfD;w!5L1C2_cD%H9cUw{E+N#Rd zJiAv+%2CD2WzAphRaL%9Din=|rA1;#h#wCM+&2t$W?~t?*b$OeUP0*^s5568htFNcmJM^@jY|*9{E~o|`G^ z0y)U&?d|=IUiOl`1R=P=fWMy+Dfha%x;9QtO%>PH)_TjAFL$FR$whT^ba*>!}1`+oK6)t|0evu2*nr%#`{(c}P)qn9;~ZxP4I zZje198wXDyCBeujVKe13W_XS1v5d{01TzPI%rW~w_Ks|d41xR=Gd$lniGJ$S>;to8 z@7e3OjF4jQW6yO*h!{d<86h)d|FChMWQNz%OWB)qS%lyhK4D}mabyU?EVCIlOQzXO fnP#uw|0}=%KHo&|AF>}@00000NkvXXu0mjf{Q9#{ literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/diamond/9_diamond.png b/web-clients/hearts/assets/diamond/9_diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..52ed6c54bf5bc7f14cec29fe66dcc424d595c6e0 GIT binary patch literal 2531 zcmV<92^{u`P)R}{W8f;9ySbV19+ zM8g8Q(O@7A)=Dswzf9MEP~_u_3MrS)6>%|oldi{v9Z_mbeQZ{vPrT9mms#9temVB?>}_;}90msV7;>iT-y@_B%^2M7KA{rfROMn*?RzYQC(XJ5Qv z_j`NUBWhgS>o^GEw5r_nfPkqjFFB6dWWXi)xna05xHC}*MTqa{a1}{eZEYlCWdkFlm}3HIqDFTpLS}pjF%fV@ za7ls46Cg~IDjOk41ISWTL4=72<&|VB9O&h@Ln=nNwWI$Bzpe8BxDG8Mddj z_VoCY0^)Q;-OinCLw7gd(dS-OMB6A)S;*+(0C3$S7uL473+stI0Jp-c!|);_bWqP6 z{Rr0U125Wkk{Iyp>nW>C=HGjX3tr^cmg=71URAlDs-e zXSkh)efx?&ZmbvJ5yYiT482^AUrtAt5waYdj~#Q|kRRaUM8(WdgnW@l>UtO^e|-Pk zIp1|me&3@4a6^SU3S65=1&O7kSQQ`mgF`!Z_^v)FsLWC+_QTbyS_XQ^cyy|4l-;G&SK_=<+T2z4R~h=n+A853W)tjL69lanj1h`zTXF5pgxg~Fh2p;=J3u!LAb zEG!|G5ZeTn5DQC)CB(uKVhORZgjhl>EFqQ<3rmQFCBzb9VF|H>SXe?VA^HPrr(khF ziRmYRof)uD4{#RaalD(!j*x)B&J3Bmo8qzV+t2#J*oAVq_axW7fml2IZ3sc3G4Dc?R3#_4rj(H?3yMl~-0*|5!>ZyP zC$tFaJnMKwfvB2N#mCWi%NOUCmQVLS)qO zFjaX;S6TV?Gt?2Xm6vptrHi5pBse5j36e?(@5*R0l$Y$Bmo!3<7SXK)QnAYGmc)1` zg^=TT>xYc?lszx4IxEoud#!kZx#^w0XS>M6KqjB!=K#KV1t;MjaU<>oW>Z zE?(QSCpN)d^zCv|l8a8grc^2xWbmrysdT1}6WCfr-CW(lvzn(;LL9$KC$ib#AkVv+ zr*c97ENME7J`IJ|7 zoj{!+x|*j}E-O=c>6l(YHBXg03MpN=7^Fh86eTFBnx}R#BpV}LUCNh~LTJdCiE9}{ zvf-3sRj9mFDJtz;R%Vb7Q&*Q4MAk<)k`OP*t4Ob?R8(3M;sn*UHmNgXWDRuNqfxuN za2q;1rKDGCnwwe6sZ-j?Zf$pR5P4xs2Suf|%E}jLMFe?#rz0RV-6T_6LcH_}Z&DnI zt=X0uMiAmDFP=djBSZDA&qfpCC?QfoJT7eMsHlu21i*zYw$@Qe#bUE&X_43w;>3d@*9}9R>9~zw>ODH0?3tKL0V+{rAua#VRE?&AbZ^~9_ze#BDO9om+~@EQN_+>dBFC7 zfQdmo+hxUqkhsA37!pT-ke81iKejEQ7%m4dLCC{&I&E7-FY-DTJtg)>o z$VK(`_OiWu_rAM#@7^!;ryC%H>V>7#7uJb!6X>eZOwqx=+`yU%$-elP6DX zYlZ-|Bg<;XcZlO;H_0Z+roa*YF&}W3@Ya60TW<$C7Iw$o?gpBSRp6 z;~MVon?*hKdG`a0WbfVQ?_5Gk*~gmemJmLKEV_g&kp1Jf^Q>!lK40R#xRgZ*-tdV_ t#wtq&H!Qlg;Es}cccjd_&)@$izyR^dIkG2R!}kCH002ovPDHLkV1h|6sL22T literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/heart/10_heart.png b/web-clients/hearts/assets/heart/10_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..0a8623f7c24f7c6c59ed34149834b45fcdb3a1e4 GIT binary patch literal 2612 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/heart/13_heart.png b/web-clients/hearts/assets/heart/13_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..96ea5c87cd1abacf6d251bdcf7c6db20ace69d57 GIT binary patch literal 2475 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/heart/1_heart.png b/web-clients/hearts/assets/heart/1_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..6773ef45c9c1b555bc33b8ca2e7c71ed65ac8067 GIT binary patch literal 2547 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 JPDHLkV1la6u73ak literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/heart/2_heart.png b/web-clients/hearts/assets/heart/2_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..0d8be749a55ca936d0f0edc823873513c15e5879 GIT binary patch literal 2611 zcmV-33e5G1P) zVxnRs8cYoMfmKoH`42PpiM;u^bHC=j^G}ZYq`Z&a{fMYz|p5SrgfE zvMRC+*($Pc9F~awCc8>DMK(rugX{{~JF>TAlfGp<2mnw*wuJ0wvexG2=F0l|dZ((Y z%KeS2SFd)B6{CmoGo1mlw!>CA&*D;Q?|=$;!!^@%~-Ac1_*8 zcW;WNRw!eXwdXO-9s{s&=D`8T6P{kbew|B7vry(JdoTbCgsd8}KKj8zgeaDNA%v}1 zv0|A1*?`>9wsq^)AKTj6693}IeSOaOqemZEX+?!oTw2N{pF{KK&v%A~hAIXI21ei^ z7kheozD<&_2Tz}N`VJimd{1>9dZ%vlX5$5bN^-NK!+Frt<4in%{{H{V7A$b@ z@yjh+oRac#>7NZt{4Fgle*wrd3T5*|zSzWz7tY1)+nv$D!N{Khm^CL(2;H;{q4M0I z0?jVWnL^=y-QMohG&D&2Y!qcOndh0x%E~D;#YA**#}4Q5wQI3Ihnm!Q@St`W!&D2e z?A{&ey(RPJIjxGi5#^>1O{~X>{<5<>JC%??B5^V`^gKk-yar| zgFYKoV1bZ@)>rHg|IyTx({5dRrg zY`vhu%%z1bE&qE#NDLhj40$4jD%_N(dkjkAffa$uY4rAO^+3i0fY_*EYNDD_+&o*P z@@C@J4rTWt7;m1>q0a2r1Y z*OUq*%2+{I>r7eU&~VTj-R0b++-+^Kx9Ssu zk;$kBf+_xC%if}Z!J<*oLg_nvICRN&6fjsRrE;RRQXudOY$TAhAhK0Qo`MCWQN6|A z8uqcIy&X|8aD7#4CY1sa-DEjTm{Yvw`0+>;B5YBSs1U+btPWEGL}dH%xC&c>jK!$9 z2Nf`Uso0%c$=qHfZq=)&@cVBCgu*>*imvITlv zAwMA^SPP_AV88Pu!shtd1>!d(bP4?^+1HZ>JX zyfZNn?3HDDbADXk^gXy|Qb}lW70GZ{)^zBUar{PNAiB-~NrQ|7anC7C*;yhg_1HKN zhVkK(3JLwNBGWFKcV3e4`4*3? z_AZ~H;Jc|h5>VOW_k4w-VzH+dAo&PIH4NoI@(GF#7?8FzsIKhUliH;V+Fm*x$ zZrqr<$#uG5_&~IdsblwrG>tN1d_xxuZ8_wFo-K8v(gFpZ(RAd9_Ume&b>c&*v3R7> zglA|^>NBNdlNu34-EAl@a)|BW3-{7|^r+E$Fgj7rCMaQBJ{1HITcFqi!wMj#q1Xh& zXj0FW=r3&8plx-pbuer@EgA*m9we_}DA+a_R)s9xQ2Z@lZG&MYknEhI0*db$Wwo_d zc1o>XAA$mt4F$ievAx||7}h2A*(7VrSIiJ`L!r$ubU%I<6*jp+>q`_$8emx2$_ff! zC{Pq^zQV9RhvdpBaiHM6HYe~@194kOOP5B5;=@pRnnA$>i3%mHFj5J`hvH7-oCQjn zVWbuaglU{JJ;k5=oK_gA=!Zn@r$A};j8yeQqCoLOS(=qMK=MVY=@=H00AyrnXoyR~ zusjAM0CK0lzn@FQusjBL0HnXGtBXs-usjC+Nb0R*zmJZNmQ__%amg6a*w~m;U0pp+ z|NIFa@`UX8wr$(EWDLnGdrX&nQcQn*Mm9V+IQW9%*jJ5>jShQ?zC;cf-QC^4(aUbK zrvQRy5BU25LAiPI?+w^JZu0bK*@M8 z$~;f0@C>iv9;Kf5WISVuYs#~CWN*k`ks*;k^9J z1|kQ@qz7bz>|d{($34UA*K@odPR#&QNcHuV4i002ovPDHLkV1gp#)F%J{ literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/heart/3_heart.png b/web-clients/hearts/assets/heart/3_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..5f9df2401f4d69e80c38e3192b71dee37132bdd1 GIT binary patch literal 2576 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 Q<^TWy07*qoM6N<$f|f&wx&QzG literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/heart/5_heart.png b/web-clients/hearts/assets/heart/5_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..fcbddfba36b720c85463e9374f7523122dc49c1d GIT binary patch literal 2524 zcmV<22_yE2P)Nt3pIKE+W`fqF^_cn1F2;hKy$8 z2u4M*M36*HY(6yU`MX3iguW|DdH-rV0k=iK|={YW^=N@iFY*($QF zWShup$P#2*$i8t{BKnK$CfO3%6xkiJVY0VmZ^#yXOL!0fpq#9M>}Rsh_V)Jb=H_On zrl!XI#BJNQxyA~w8#iva22D*(IjL0285$aTK`*b7{Yo}Yw%`GBR+Ckdwd4Iqj~-om z@ZiA`ORZ4GC~MDS+C2tf;Z(r^$P-?Sj*fCkX%@;HWe)~mfsj>4HbQ?`hY-cmFNCm` zmX;^MOu`<&des@fawXD5w4ONO)HXI6DS(-O z|8>TCd!5IFgU-UMSMPpbv39M~uyd#L<-UDRd1a;aV+$qzj*gB$0pulxvZ^o#kDWW` zUQ`rqzi`2+Yi-pIBYo+TbBC@yvoN!T!u`6t`-AI?a%>PK5{XyI>gwvMQV9)Ds1}Z# zKApEfT`ze0)EVmPa=k&uu|WkE$x_K3D4@Sjo(%kc6ny6U0YmiIFu5d29hA@qPNvhb z12R@1)a25$TesYNi4cvNFLG=cfkm0fmz&S?#gN!wg;d+rq}4k_8zDGOv;v|MH0;Xqm7p@58Rg?Gbg=$SEOCp(56V;T$0xeT@Aq&&fAGmsXRh5yx zhsm5bK|q@J?llV}Uwa)P4V|Yj7a3>Ghiphl2XeQsFK=rGaTQI-y3L!7_0(;a^c)hj zY59*pJDq_jjLG;6v_NzSVbYW;L!LXS!VA`QbT}K294Xk>(AE0U+2@IRZY9m$tvx-? z#>0o*JGzD1={ocoFi0wFZ& zBZIKQIgPinY!yPN&g2fS6lvC%3=lWBojvQ`Ezpt33*}D+f`XzNizk&Tp#X+^4uQwG z!a3wpOUsIXLl1oW`SaF8xqk3q=;tFr`a4lzl$?iTLTRV)Ws_%=G!VZ@{=?s#^f7?Xs;E;P8nc`H)Ktyjt;QeT7s&aW*!XS(`uhJk)$!<+a4_WV8Qk1|kumQte z3WYF)DU;I>M1(=s$aS*%8HGYtWFXmaR(jr!TBhSm#aYsUunZ=3mSstu#XuMci-9l@ zE&>L^Vjv8J#XuMci-9l@76V}*EC#}2APj`XKo|&%ffTvQbe;^ugs{9SR&c;@p{$RR7D+Of>qa3l6ljvHw z*&r}aJ?!dos34ec9(JidAs9NwWntiQkmXeifx(DJ(LxzHb0+U-{h(k}4zyMd1YUtf z%%T=Vrkco8Hc@R2>Mj1#uu(?oXIBiIU)ADkN`XY3uCS7VPGdlY=5KJ^(w2*b({ zu>gXCz#MRu>l_xEf{eM1D(0bQ3QK3SojN5Qi1cPJ61VC_C-M1r^Mt~vIV(_Zq{hLs zkrBK5A*h+UR@}jPa?SF^0-P#BWiBB<1)Wc61c>f+6o72L2qs19T3s|>E-`%#?w(Wkfx1w&$90`a`D^uGb8RZcP2nMQ| z+_aH_aM;SLuzMCN0fGV0tmT2&GUk#*27-|m9JU;Ha*;J1Ly-*>i%qg3g%lu|NK?vQ z;!c5+G?7PI$FP*WM068Lr9ev6OE6C)YG+Uh5Xj~|K~%M@WO|2mAgC#&)C@)ils#=* z`pw1Ga4@q)%l)iW!QE$(~w(6eASXFq8u+CMY^! zK-#uE8a{R`wo@0h!O*=2)gQZe$8K<)E*L%#tcU*rlHsb!)Q`pDbZiswM*OVUh81kwmC5h#@$F>!=qr^U|1EhbVKo% ze6?|ZcPpnO_&G%d6yGx{>g%oSlv+DK1O+A=3O=i?yW3hA)+O~^lC|V3Mu@nf&}JCA zZ@-HQi`<~~B?=`DFsy84|5naffl{fD&gIu>}HQ7-zPp_=BJ03L_T%kf8k(D9)Y{tA0ojD1Io5 zvx){tu_!hj!%`A}Ogwz}kW0d_JO&d0azB+yafuj~$KXDIr26~&xkL=hV~|2p?~MB(Ll-T=MxU`sY)!C+T#0n&Q}3 zZEbB1dy2k94j2Oi1HaMB0kRhWf_o46|1m)syLj>9mf6|a^5*7dXU&>5TxyC!RBvyu zvuDqq*SBxq{)K)u3>aiDkwZQwt0se6)RHxjeMk2F`t|ES-mqcAJDQIkJ>t?75S62o zRgSNb$H{JzjpJqmH~~t+gHhpm$|s)THQZyh=RFC}SmIjp>@C?m*(@0n`Ag66e0m1E zw9R=3ERwzPUcdH$lsn5ixiJtqKo&h93uOO!4 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/heart/6_heart.png b/web-clients/hearts/assets/heart/6_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..f324522e9d20d4a35dfeaa341c7ef72cb0a0d843 GIT binary patch literal 2519 zcmV;|2`Ki7P)q*Fwsq) zV2mh=0ZIIbjft9`|70dS)0a1I?%c0=@BHE9U3Pz`%g$?d^R|Z@bBUB^x4}@&So*vP!aM{QZFg2d3}e zzdy~=E0i(H+V_}dp8;5iDmVan!t-0VZgEK&7RnrD4+da?CTlTSKmB4knkbfep$S{J zZrvmLwgG*|{$0Cv{kVVs{@DL`^zL2pa(GybKY8*$E3d8=rRC*Z`dPGO$r3R z`K{WzReZj4rzoqeRQ}npj=!a)4K}}he?1l9mJSaxf>AXKvR#hd|pEx0wTN<&Y zFI^J1sX#LeGh4;MIWBH!Q1;n;luD&urfO{*^WG{ri7`NE)GylHdBA+(X7r^IJ&mXzwbYJQu?#`3M@)! zf+E#9&g-8@<2;?CK#V*K%Asn15Lq{N~`=HiAf zU(Wgajc3k?&F9W}uQ{6#LqOmiVdtFdTK~yW`NAqeR7n8|>%{9;um0e5K0T#cWJ0nq zf|@SdG{dXVnrH{2N^$z2NS(RCrZF4PC|aQVguYNP;fy_DjW8@%Ewln_cIvOP<8U0Q%(et~g#wzj)&%^Gj?#b69}>R0#dnYSZFd*0pF z7J2j$N4e%hx>XtR*jj*ub)pzu0h+0qI=s@Bq8{7YuoqBdCtOkWX=9@`Aj?}?+yH{5 zld#%hYGR0Gaa%B=_LW+IeBa%j*V0MU^&wf|{)CPBkjyc)010YESnV(cB$yAG?A+m% zVM|9&^&vI{kHx(T6CHWOkt6O5dtDW3EN+bHgaR1eF(hu|799}XP=c5NSr|nLB!JQ! zGT<=n8AT1m8Yb z<|^!bP~a(H=dAO74nj#06(9M7eTNRk3LcP+?lU38Q)P=)hGzhV%#ui6Fj6V`J_HMA zafXa&9$dX^n63H3wW68Q1tYeH1bqaWr6`MpxG-ESF4}bko?_~@Gdv^~kU;1!5R8@! z3_u`MAN@~~?x!Qj8aKF9%`=Pu$<#=Hf7XuB#04c?T7a+^2m@g;5C+0xAPj_oFc204 zVIV99!a!IIgn_Ua2m@gt41~o%7zm4jFc204VIXQ1q?APnDzZIfi{nDLCc=iW#~VT2 zs>6p62#(`F^v@w%&Mq83I0uv2Q;h)u2xM)5MM+u~1lP&t!kr5ODfgmgmqP_X*sO_2 zOCvxKj){z(ak9t74L|Kabt-4l&V0e>47An`1YUtuvT23+OxBR6tVNJ_p579qh8f$q8XvpsY{~*UZ_uORtXoOT202Bk1-I(nynI>2WKe;GHGeKgn_Ua z2m@gyABfFI3Aw7cWx^i99#YssmTYT4TuX#(TPn&U77zrgxs)!v=z(yv^`W9Zvrr2V z1VFQ90C5a6Lkrv!+g+DRE=&;v?huGVes+K|t5NxC=W-sx!z$x0uqikYW%w8h< z5J{~-iq%W7PbBVSFjGo5?BISfHp&#!$m)mgZe=@#m2cQVO(~{f@OnH*O!2mD<%^3A zhYwqOez{4Z&(yJpUE8M58^?}W4}jL$Z>Zj17&KX0_o){m6kRZk04X#mI$;HdLWf}-2=vFcZHWu6GX=v65EEG*R0{VuHl99h?08lZm?Z^@NzbqfB!JR; z@Sw4b3$A;Hbs#Q#O1{~K3J!>iP{Ohd6+94^pxB1t3=kKfxB$Z`AU2`60>e2V0hI2x zHeC%Nr90#ATrGtU|=-mYM+sKAW@(s z4Mt*t zA_n3h5bO_mIy^kgrD0h* zPche#14dU@*KhQ;i|jdoRFUEJAwjuw;lhOt6B83<_4V~)(V|6MYMPp;_V#wMef##; zgM)*=(2x26gX{(RkR@a_WN?c*vQ=c?kbS#i#fpztu3R}w^TC4$T$&Q1aujpQ@iqE! zvg>3+SZn|%KuP&9Dtu3=_6_gh9_7CGqAi1LzL&i5 hJ>`x6{_TGP3;F#+2y3>nSF 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 KMNUMnLSTa5#jT?N literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/spade/10_spade.png b/web-clients/hearts/assets/spade/10_spade.png new file mode 100644 index 0000000000000000000000000000000000000000..b00c992a8eac9473b84788f728c31dcd0471ffbc GIT binary patch literal 2693 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

H?7dn>TM#Nw_S* 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 Te7|+{00000NkvXXu0mjfd|B&y literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/spade/3_spade.png b/web-clients/hearts/assets/spade/3_spade.png new file mode 100644 index 0000000000000000000000000000000000000000..0e81ef230dd45d9cb6bd6d08910731430fa4c636 GIT binary patch literal 2708 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 O00004 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/spade/4_spade.png b/web-clients/hearts/assets/spade/4_spade.png new file mode 100644 index 0000000000000000000000000000000000000000..e4385924cc09aba615421db4e72012f61a46fbac GIT binary patch literal 2559 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/spade/6_spade.png b/web-clients/hearts/assets/spade/6_spade.png new file mode 100644 index 0000000000000000000000000000000000000000..04ead76510c21bf9be30d9579bb34dd12fe1e49a GIT binary patch literal 2657 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/assets/spade/8_spade.png b/web-clients/hearts/assets/spade/8_spade.png new file mode 100644 index 0000000000000000000000000000000000000000..2362b0c408332831b66e853c44caab9287902324 GIT binary patch literal 2720 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 o+4k73C6DZy^2mPth($07*qoM6N<$f)%O&XaE2J literal 0 HcmV?d00001 diff --git a/web-clients/hearts/dist/assets/index-w1daCLpV.js b/web-clients/hearts/dist/assets/index-AWEoIZL7.js similarity index 61% rename from web-clients/hearts/dist/assets/index-w1daCLpV.js rename to web-clients/hearts/dist/assets/index-AWEoIZL7.js index bf9cd767..c752def0 100644 --- a/web-clients/hearts/dist/assets/index-w1daCLpV.js +++ b/web-clients/hearts/dist/assets/index-AWEoIZL7.js @@ -2,11 +2,11 @@ * @license * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT - */const Gs="180",Zo=0,ca=1,jo=2,po=1,Jo=2,tn=3,pn=0,yt=1,kt=2,dn=0,$n=1,la=2,ua=3,ha=4,Qo=5,bn=100,ec=101,tc=102,nc=103,ic=104,rc=200,sc=201,ac=202,oc=203,Zr=204,jr=205,cc=206,lc=207,uc=208,hc=209,dc=210,fc=211,pc=212,mc=213,gc=214,Jr=0,Qr=1,es=2,Zn=3,ts=4,ns=5,is=6,rs=7,mo=0,_c=1,vc=2,fn=0,xc=1,Mc=2,Sc=3,Ec=4,yc=5,Tc=6,Ac=7,go=300,jn=301,Jn=302,ss=303,as=304,dr=306,os=1e3,Rn=1001,cs=1002,Ht=1003,bc=1004,wi=1005,Wt=1006,_r=1007,Cn=1008,Yt=1009,_o=1010,vo=1011,pi=1012,Vs=1013,Pn=1014,nn=1015,xi=1016,ks=1017,Ws=1018,mi=1020,xo=35902,Mo=35899,So=1021,Eo=1022,zt=1023,gi=1026,_i=1027,yo=1028,Xs=1029,To=1030,qs=1031,Ys=1033,Qi=33776,er=33777,tr=33778,nr=33779,ls=35840,us=35841,hs=35842,ds=35843,fs=36196,ps=37492,ms=37496,gs=37808,_s=37809,vs=37810,xs=37811,Ms=37812,Ss=37813,Es=37814,ys=37815,Ts=37816,As=37817,bs=37818,ws=37819,Rs=37820,Cs=37821,Ps=36492,Ds=36494,Ls=36495,Is=36283,Us=36284,Ns=36285,Fs=36286,wc=3200,Rc=3201,Ao=0,Cc=1,hn="",Lt="srgb",Qn="srgb-linear",sr="linear",Ye="srgb",In=7680,da=519,Pc=512,Dc=513,Lc=514,bo=515,Ic=516,Uc=517,Nc=518,Fc=519,fa=35044,pa="300 es",Xt=2e3,ar=2001;class ti{addEventListener(e,t){this._listeners===void 0&&(this._listeners={});const n=this._listeners;n[e]===void 0&&(n[e]=[]),n[e].indexOf(t)===-1&&n[e].push(t)}hasEventListener(e,t){const n=this._listeners;return n===void 0?!1:n[e]!==void 0&&n[e].indexOf(t)!==-1}removeEventListener(e,t){const n=this._listeners;if(n===void 0)return;const r=n[e];if(r!==void 0){const s=r.indexOf(t);s!==-1&&r.splice(s,1)}}dispatchEvent(e){const t=this._listeners;if(t===void 0)return;const n=t[e.type];if(n!==void 0){e.target=this;const r=n.slice(0);for(let s=0,a=r.length;s>8&255]+gt[i>>16&255]+gt[i>>24&255]+"-"+gt[e&255]+gt[e>>8&255]+"-"+gt[e>>16&15|64]+gt[e>>24&255]+"-"+gt[t&63|128]+gt[t>>8&255]+"-"+gt[t>>16&255]+gt[t>>24&255]+gt[n&255]+gt[n>>8&255]+gt[n>>16&255]+gt[n>>24&255]).toLowerCase()}function ze(i,e,t){return Math.max(e,Math.min(t,i))}function Oc(i,e){return(i%e+e)%e}function vr(i,e,t){return(1-t)*i+t*e}function si(i,e){switch(e.constructor){case Float32Array:return i;case Uint32Array:return i/4294967295;case Uint16Array:return i/65535;case Uint8Array:return i/255;case Int32Array:return Math.max(i/2147483647,-1);case Int16Array:return Math.max(i/32767,-1);case Int8Array:return Math.max(i/127,-1);default:throw new Error("Invalid component type.")}}function St(i,e){switch(e.constructor){case Float32Array:return i;case Uint32Array:return Math.round(i*4294967295);case Uint16Array:return Math.round(i*65535);case Uint8Array:return Math.round(i*255);case Int32Array:return Math.round(i*2147483647);case Int16Array:return Math.round(i*32767);case Int8Array:return Math.round(i*127);default:throw new Error("Invalid component type.")}}class Ge{constructor(e=0,t=0){Ge.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){const t=this.x,n=this.y,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6],this.y=r[1]*t+r[4]*n+r[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=ze(this.x,e.x,t.x),this.y=ze(this.y,e.y,t.y),this}clampScalar(e,t){return this.x=ze(this.x,e,t),this.y=ze(this.y,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(ze(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(ze(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y;return t*t+n*n}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){const n=Math.cos(t),r=Math.sin(t),s=this.x-e.x,a=this.y-e.y;return this.x=s*n-a*r+e.x,this.y=s*r+a*n+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Si{constructor(e=0,t=0,n=0,r=1){this.isQuaternion=!0,this._x=e,this._y=t,this._z=n,this._w=r}static slerpFlat(e,t,n,r,s,a,o){let l=n[r+0],c=n[r+1],d=n[r+2],h=n[r+3];const f=s[a+0],m=s[a+1],_=s[a+2],x=s[a+3];if(o===0){e[t+0]=l,e[t+1]=c,e[t+2]=d,e[t+3]=h;return}if(o===1){e[t+0]=f,e[t+1]=m,e[t+2]=_,e[t+3]=x;return}if(h!==x||l!==f||c!==m||d!==_){let p=1-o;const u=l*f+c*m+d*_+h*x,b=u>=0?1:-1,A=1-u*u;if(A>Number.EPSILON){const C=Math.sqrt(A),R=Math.atan2(C,u*b);p=Math.sin(p*R)/C,o=Math.sin(o*R)/C}const E=o*b;if(l=l*p+f*E,c=c*p+m*E,d=d*p+_*E,h=h*p+x*E,p===1-o){const C=1/Math.sqrt(l*l+c*c+d*d+h*h);l*=C,c*=C,d*=C,h*=C}}e[t]=l,e[t+1]=c,e[t+2]=d,e[t+3]=h}static multiplyQuaternionsFlat(e,t,n,r,s,a){const o=n[r],l=n[r+1],c=n[r+2],d=n[r+3],h=s[a],f=s[a+1],m=s[a+2],_=s[a+3];return e[t]=o*_+d*h+l*m-c*f,e[t+1]=l*_+d*f+c*h-o*m,e[t+2]=c*_+d*m+o*f-l*h,e[t+3]=d*_-o*h-l*f-c*m,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,n,r){return this._x=e,this._y=t,this._z=n,this._w=r,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){const n=e._x,r=e._y,s=e._z,a=e._order,o=Math.cos,l=Math.sin,c=o(n/2),d=o(r/2),h=o(s/2),f=l(n/2),m=l(r/2),_=l(s/2);switch(a){case"XYZ":this._x=f*d*h+c*m*_,this._y=c*m*h-f*d*_,this._z=c*d*_+f*m*h,this._w=c*d*h-f*m*_;break;case"YXZ":this._x=f*d*h+c*m*_,this._y=c*m*h-f*d*_,this._z=c*d*_-f*m*h,this._w=c*d*h+f*m*_;break;case"ZXY":this._x=f*d*h-c*m*_,this._y=c*m*h+f*d*_,this._z=c*d*_+f*m*h,this._w=c*d*h-f*m*_;break;case"ZYX":this._x=f*d*h-c*m*_,this._y=c*m*h+f*d*_,this._z=c*d*_-f*m*h,this._w=c*d*h+f*m*_;break;case"YZX":this._x=f*d*h+c*m*_,this._y=c*m*h+f*d*_,this._z=c*d*_-f*m*h,this._w=c*d*h-f*m*_;break;case"XZY":this._x=f*d*h-c*m*_,this._y=c*m*h-f*d*_,this._z=c*d*_+f*m*h,this._w=c*d*h+f*m*_;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+a)}return t===!0&&this._onChangeCallback(),this}setFromAxisAngle(e,t){const n=t/2,r=Math.sin(n);return this._x=e.x*r,this._y=e.y*r,this._z=e.z*r,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(e){const t=e.elements,n=t[0],r=t[4],s=t[8],a=t[1],o=t[5],l=t[9],c=t[2],d=t[6],h=t[10],f=n+o+h;if(f>0){const m=.5/Math.sqrt(f+1);this._w=.25/m,this._x=(d-l)*m,this._y=(s-c)*m,this._z=(a-r)*m}else if(n>o&&n>h){const m=2*Math.sqrt(1+n-o-h);this._w=(d-l)/m,this._x=.25*m,this._y=(r+a)/m,this._z=(s+c)/m}else if(o>h){const m=2*Math.sqrt(1+o-n-h);this._w=(s-c)/m,this._x=(r+a)/m,this._y=.25*m,this._z=(l+d)/m}else{const m=2*Math.sqrt(1+h-n-o);this._w=(a-r)/m,this._x=(s+c)/m,this._y=(l+d)/m,this._z=.25*m}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let n=e.dot(t)+1;return n<1e-8?(n=0,Math.abs(e.x)>Math.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs(ze(this.dot(e),-1,1)))}rotateTowards(e,t){const n=this.angleTo(e);if(n===0)return this;const r=Math.min(1,t/n);return this.slerp(e,r),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return e===0?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){const n=e._x,r=e._y,s=e._z,a=e._w,o=t._x,l=t._y,c=t._z,d=t._w;return this._x=n*d+a*o+r*c-s*l,this._y=r*d+a*l+s*o-n*c,this._z=s*d+a*c+n*l-r*o,this._w=a*d-n*o-r*l-s*c,this._onChangeCallback(),this}slerp(e,t){if(t===0)return this;if(t===1)return this.copy(e);const n=this._x,r=this._y,s=this._z,a=this._w;let o=a*e._w+n*e._x+r*e._y+s*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=a,this._x=n,this._y=r,this._z=s,this;const l=1-o*o;if(l<=Number.EPSILON){const m=1-t;return this._w=m*a+t*this._w,this._x=m*n+t*this._x,this._y=m*r+t*this._y,this._z=m*s+t*this._z,this.normalize(),this}const c=Math.sqrt(l),d=Math.atan2(c,o),h=Math.sin((1-t)*d)/c,f=Math.sin(t*d)/c;return this._w=a*h+this._w*f,this._x=n*h+this._x*f,this._y=r*h+this._y*f,this._z=s*h+this._z*f,this._onChangeCallback(),this}slerpQuaternions(e,t,n){return this.copy(e).slerp(t,n)}random(){const e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),n=Math.random(),r=Math.sqrt(1-n),s=Math.sqrt(n);return this.set(r*Math.sin(e),r*Math.cos(e),s*Math.sin(t),s*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class N{constructor(e=0,t=0,n=0){N.prototype.isVector3=!0,this.x=e,this.y=t,this.z=n}set(e,t,n){return n===void 0&&(n=this.z),this.x=e,this.y=t,this.z=n,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(ma.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(ma.setFromAxisAngle(e,t))}applyMatrix3(e){const t=this.x,n=this.y,r=this.z,s=e.elements;return this.x=s[0]*t+s[3]*n+s[6]*r,this.y=s[1]*t+s[4]*n+s[7]*r,this.z=s[2]*t+s[5]*n+s[8]*r,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){const t=this.x,n=this.y,r=this.z,s=e.elements,a=1/(s[3]*t+s[7]*n+s[11]*r+s[15]);return this.x=(s[0]*t+s[4]*n+s[8]*r+s[12])*a,this.y=(s[1]*t+s[5]*n+s[9]*r+s[13])*a,this.z=(s[2]*t+s[6]*n+s[10]*r+s[14])*a,this}applyQuaternion(e){const t=this.x,n=this.y,r=this.z,s=e.x,a=e.y,o=e.z,l=e.w,c=2*(a*r-o*n),d=2*(o*t-s*r),h=2*(s*n-a*t);return this.x=t+l*c+a*h-o*d,this.y=n+l*d+o*c-s*h,this.z=r+l*h+s*d-a*c,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){const t=this.x,n=this.y,r=this.z,s=e.elements;return this.x=s[0]*t+s[4]*n+s[8]*r,this.y=s[1]*t+s[5]*n+s[9]*r,this.z=s[2]*t+s[6]*n+s[10]*r,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=ze(this.x,e.x,t.x),this.y=ze(this.y,e.y,t.y),this.z=ze(this.z,e.z,t.z),this}clampScalar(e,t){return this.x=ze(this.x,e,t),this.y=ze(this.y,e,t),this.z=ze(this.z,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(ze(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){const n=e.x,r=e.y,s=e.z,a=t.x,o=t.y,l=t.z;return this.x=r*l-s*o,this.y=s*a-n*l,this.z=n*o-r*a,this}projectOnVector(e){const t=e.lengthSq();if(t===0)return this.set(0,0,0);const n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)}projectOnPlane(e){return xr.copy(this).projectOnVector(e),this.sub(xr)}reflect(e){return this.sub(xr.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(ze(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y,r=this.z-e.z;return t*t+n*n+r*r}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,n){const r=Math.sin(t)*e;return this.x=r*Math.sin(n),this.y=Math.cos(t)*e,this.z=r*Math.cos(n),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){const t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),r=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=r,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,t*4)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,t*3)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const e=Math.random()*Math.PI*2,t=Math.random()*2-1,n=Math.sqrt(1-t*t);return this.x=n*Math.cos(e),this.y=t,this.z=n*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const xr=new N,ma=new Si;class Ie{constructor(e,t,n,r,s,a,o,l,c){Ie.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],e!==void 0&&this.set(e,t,n,r,s,a,o,l,c)}set(e,t,n,r,s,a,o,l,c){const d=this.elements;return d[0]=e,d[1]=r,d[2]=o,d[3]=t,d[4]=s,d[5]=l,d[6]=n,d[7]=a,d[8]=c,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this}extractBasis(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(e){const t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,r=t.elements,s=this.elements,a=n[0],o=n[3],l=n[6],c=n[1],d=n[4],h=n[7],f=n[2],m=n[5],_=n[8],x=r[0],p=r[3],u=r[6],b=r[1],A=r[4],E=r[7],C=r[2],R=r[5],w=r[8];return s[0]=a*x+o*b+l*C,s[3]=a*p+o*A+l*R,s[6]=a*u+o*E+l*w,s[1]=c*x+d*b+h*C,s[4]=c*p+d*A+h*R,s[7]=c*u+d*E+h*w,s[2]=f*x+m*b+_*C,s[5]=f*p+m*A+_*R,s[8]=f*u+m*E+_*w,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],l=e[6],c=e[7],d=e[8];return t*a*d-t*o*c-n*s*d+n*o*l+r*s*c-r*a*l}invert(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],l=e[6],c=e[7],d=e[8],h=d*a-o*c,f=o*l-d*s,m=c*s-a*l,_=t*h+n*f+r*m;if(_===0)return this.set(0,0,0,0,0,0,0,0,0);const x=1/_;return e[0]=h*x,e[1]=(r*c-d*n)*x,e[2]=(o*n-r*a)*x,e[3]=f*x,e[4]=(d*t-r*l)*x,e[5]=(r*s-o*t)*x,e[6]=m*x,e[7]=(n*l-c*t)*x,e[8]=(a*t-n*s)*x,this}transpose(){let e;const t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){const t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,n,r,s,a,o){const l=Math.cos(s),c=Math.sin(s);return this.set(n*l,n*c,-n*(l*a+c*o)+a+e,-r*c,r*l,-r*(-c*a+l*o)+o+t,0,0,1),this}scale(e,t){return this.premultiply(Mr.makeScale(e,t)),this}rotate(e){return this.premultiply(Mr.makeRotation(-e)),this}translate(e,t){return this.premultiply(Mr.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,n,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){const t=this.elements,n=e.elements;for(let r=0;r<9;r++)if(t[r]!==n[r])return!1;return!0}fromArray(e,t=0){for(let n=0;n<9;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}clone(){return new this.constructor().fromArray(this.elements)}}const Mr=new Ie;function wo(i){for(let e=i.length-1;e>=0;--e)if(i[e]>=65535)return!0;return!1}function or(i){return document.createElementNS("http://www.w3.org/1999/xhtml",i)}function Bc(){const i=or("canvas");return i.style.display="block",i}const ga={};function vi(i){i in ga||(ga[i]=!0,console.warn(i))}function zc(i,e,t){return new Promise(function(n,r){function s(){switch(i.clientWaitSync(e,i.SYNC_FLUSH_COMMANDS_BIT,0)){case i.WAIT_FAILED:r();break;case i.TIMEOUT_EXPIRED:setTimeout(s,t);break;default:n()}}setTimeout(s,t)})}const _a=new Ie().set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),va=new Ie().set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function Hc(){const i={enabled:!0,workingColorSpace:Qn,spaces:{},convert:function(r,s,a){return this.enabled===!1||s===a||!s||!a||(this.spaces[s].transfer===Ye&&(r.r=rn(r.r),r.g=rn(r.g),r.b=rn(r.b)),this.spaces[s].primaries!==this.spaces[a].primaries&&(r.applyMatrix3(this.spaces[s].toXYZ),r.applyMatrix3(this.spaces[a].fromXYZ)),this.spaces[a].transfer===Ye&&(r.r=Kn(r.r),r.g=Kn(r.g),r.b=Kn(r.b))),r},workingToColorSpace:function(r,s){return this.convert(r,this.workingColorSpace,s)},colorSpaceToWorking:function(r,s){return this.convert(r,s,this.workingColorSpace)},getPrimaries:function(r){return this.spaces[r].primaries},getTransfer:function(r){return r===hn?sr:this.spaces[r].transfer},getToneMappingMode:function(r){return this.spaces[r].outputColorSpaceConfig.toneMappingMode||"standard"},getLuminanceCoefficients:function(r,s=this.workingColorSpace){return r.fromArray(this.spaces[s].luminanceCoefficients)},define:function(r){Object.assign(this.spaces,r)},_getMatrix:function(r,s,a){return r.copy(this.spaces[s].toXYZ).multiply(this.spaces[a].fromXYZ)},_getDrawingBufferColorSpace:function(r){return this.spaces[r].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(r=this.workingColorSpace){return this.spaces[r].workingColorSpaceConfig.unpackColorSpace},fromWorkingColorSpace:function(r,s){return vi("THREE.ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."),i.workingToColorSpace(r,s)},toWorkingColorSpace:function(r,s){return vi("THREE.ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."),i.colorSpaceToWorking(r,s)}},e=[.64,.33,.3,.6,.15,.06],t=[.2126,.7152,.0722],n=[.3127,.329];return i.define({[Qn]:{primaries:e,whitePoint:n,transfer:sr,toXYZ:_a,fromXYZ:va,luminanceCoefficients:t,workingColorSpaceConfig:{unpackColorSpace:Lt},outputColorSpaceConfig:{drawingBufferColorSpace:Lt}},[Lt]:{primaries:e,whitePoint:n,transfer:Ye,toXYZ:_a,fromXYZ:va,luminanceCoefficients:t,outputColorSpaceConfig:{drawingBufferColorSpace:Lt}}}),i}const ke=Hc();function rn(i){return i<.04045?i*.0773993808:Math.pow(i*.9478672986+.0521327014,2.4)}function Kn(i){return i<.0031308?i*12.92:1.055*Math.pow(i,.41666)-.055}let Un;class Gc{static getDataURL(e,t="image/png"){if(/^data:/i.test(e.src)||typeof HTMLCanvasElement>"u")return e.src;let n;if(e instanceof HTMLCanvasElement)n=e;else{Un===void 0&&(Un=or("canvas")),Un.width=e.width,Un.height=e.height;const r=Un.getContext("2d");e instanceof ImageData?r.putImageData(e,0,0):r.drawImage(e,0,0,e.width,e.height),n=Un}return n.toDataURL(t)}static sRGBToLinear(e){if(typeof HTMLImageElement<"u"&&e instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&e instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&e instanceof ImageBitmap){const t=or("canvas");t.width=e.width,t.height=e.height;const n=t.getContext("2d");n.drawImage(e,0,0,e.width,e.height);const r=n.getImageData(0,0,e.width,e.height),s=r.data;for(let a=0;a1),this.pmremVersion=0}get width(){return this.source.getSize(Er).x}get height(){return this.source.getSize(Er).y}get depth(){return this.source.getSize(Er).z}get image(){return this.source.data}set image(e=null){this.source.data=e}updateMatrix(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}clone(){return new this.constructor().copy(this)}copy(e){return this.name=e.name,this.source=e.source,this.mipmaps=e.mipmaps.slice(0),this.mapping=e.mapping,this.channel=e.channel,this.wrapS=e.wrapS,this.wrapT=e.wrapT,this.magFilter=e.magFilter,this.minFilter=e.minFilter,this.anisotropy=e.anisotropy,this.format=e.format,this.internalFormat=e.internalFormat,this.type=e.type,this.offset.copy(e.offset),this.repeat.copy(e.repeat),this.center.copy(e.center),this.rotation=e.rotation,this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrix.copy(e.matrix),this.generateMipmaps=e.generateMipmaps,this.premultiplyAlpha=e.premultiplyAlpha,this.flipY=e.flipY,this.unpackAlignment=e.unpackAlignment,this.colorSpace=e.colorSpace,this.renderTarget=e.renderTarget,this.isRenderTargetTexture=e.isRenderTargetTexture,this.isArrayTexture=e.isArrayTexture,this.userData=JSON.parse(JSON.stringify(e.userData)),this.needsUpdate=!0,this}setValues(e){for(const t in e){const n=e[t];if(n===void 0){console.warn(`THREE.Texture.setValues(): parameter '${t}' has value of undefined.`);continue}const r=this[t];if(r===void 0){console.warn(`THREE.Texture.setValues(): property '${t}' does not exist.`);continue}r&&n&&r.isVector2&&n.isVector2||r&&n&&r.isVector3&&n.isVector3||r&&n&&r.isMatrix3&&n.isMatrix3?r.copy(n):this[t]=n}}toJSON(e){const t=e===void 0||typeof e=="string";if(!t&&e.textures[this.uuid]!==void 0)return e.textures[this.uuid];const n={metadata:{version:4.7,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,image:this.source.toJSON(e).uuid,mapping:this.mapping,channel:this.channel,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,internalFormat:this.internalFormat,type:this.type,colorSpace:this.colorSpace,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,generateMipmaps:this.generateMipmaps,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};return Object.keys(this.userData).length>0&&(n.userData=this.userData),t||(e.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==go)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case os:e.x=e.x-Math.floor(e.x);break;case Rn:e.x=e.x<0?0:1;break;case cs:Math.abs(Math.floor(e.x)%2)===1?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x);break}if(e.y<0||e.y>1)switch(this.wrapT){case os:e.y=e.y-Math.floor(e.y);break;case Rn:e.y=e.y<0?0:1;break;case cs:Math.abs(Math.floor(e.y)%2)===1?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y);break}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){e===!0&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){e===!0&&this.pmremVersion++}}Tt.DEFAULT_IMAGE=null;Tt.DEFAULT_MAPPING=go;Tt.DEFAULT_ANISOTROPY=1;class st{constructor(e=0,t=0,n=0,r=1){st.prototype.isVector4=!0,this.x=e,this.y=t,this.z=n,this.w=r}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,n,r){return this.x=e,this.y=t,this.z=n,this.w=r,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w!==void 0?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){const t=this.x,n=this.y,r=this.z,s=this.w,a=e.elements;return this.x=a[0]*t+a[4]*n+a[8]*r+a[12]*s,this.y=a[1]*t+a[5]*n+a[9]*r+a[13]*s,this.z=a[2]*t+a[6]*n+a[10]*r+a[14]*s,this.w=a[3]*t+a[7]*n+a[11]*r+a[15]*s,this}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this.w/=e.w,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);const t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,n,r,s;const l=e.elements,c=l[0],d=l[4],h=l[8],f=l[1],m=l[5],_=l[9],x=l[2],p=l[6],u=l[10];if(Math.abs(d-f)<.01&&Math.abs(h-x)<.01&&Math.abs(_-p)<.01){if(Math.abs(d+f)<.1&&Math.abs(h+x)<.1&&Math.abs(_+p)<.1&&Math.abs(c+m+u-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;const A=(c+1)/2,E=(m+1)/2,C=(u+1)/2,R=(d+f)/4,w=(h+x)/4,U=(_+p)/4;return A>E&&A>C?A<.01?(n=0,r=.707106781,s=.707106781):(n=Math.sqrt(A),r=R/n,s=w/n):E>C?E<.01?(n=.707106781,r=0,s=.707106781):(r=Math.sqrt(E),n=R/r,s=U/r):C<.01?(n=.707106781,r=.707106781,s=0):(s=Math.sqrt(C),n=w/s,r=U/s),this.set(n,r,s,t),this}let b=Math.sqrt((p-_)*(p-_)+(h-x)*(h-x)+(f-d)*(f-d));return Math.abs(b)<.001&&(b=1),this.x=(p-_)/b,this.y=(h-x)/b,this.z=(f-d)/b,this.w=Math.acos((c+m+u-1)/2),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this.w=t[15],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this}clamp(e,t){return this.x=ze(this.x,e.x,t.x),this.y=ze(this.y,e.y,t.y),this.z=ze(this.z,e.z,t.z),this.w=ze(this.w,e.w,t.w),this}clampScalar(e,t){return this.x=ze(this.x,e,t),this.y=ze(this.y,e,t),this.z=ze(this.z,e,t),this.w=ze(this.w,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(ze(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this.w=Math.trunc(this.w),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this.w=e.w+(t.w-e.w)*n,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this.w=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z,yield this.w}}class Wc extends ti{constructor(e=1,t=1,n={}){super(),n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:Wt,depthBuffer:!0,stencilBuffer:!1,resolveDepthBuffer:!0,resolveStencilBuffer:!0,depthTexture:null,samples:0,count:1,depth:1,multiview:!1},n),this.isRenderTarget=!0,this.width=e,this.height=t,this.depth=n.depth,this.scissor=new st(0,0,e,t),this.scissorTest=!1,this.viewport=new st(0,0,e,t);const r={width:e,height:t,depth:n.depth},s=new Tt(r);this.textures=[];const a=n.count;for(let o=0;o1;this.dispose()}this.viewport.set(0,0,e,t),this.scissor.set(0,0,e,t)}clone(){return new this.constructor().copy(this)}copy(e){this.width=e.width,this.height=e.height,this.depth=e.depth,this.scissor.copy(e.scissor),this.scissorTest=e.scissorTest,this.viewport.copy(e.viewport),this.textures.length=0;for(let t=0,n=e.textures.length;t=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}intersectsSphere(e){return this.clampPoint(e.center,Ft),Ft.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(ai),Ci.subVectors(this.max,ai),Nn.subVectors(e.a,ai),Fn.subVectors(e.b,ai),On.subVectors(e.c,ai),sn.subVectors(Fn,Nn),an.subVectors(On,Fn),vn.subVectors(Nn,On);let t=[0,-sn.z,sn.y,0,-an.z,an.y,0,-vn.z,vn.y,sn.z,0,-sn.x,an.z,0,-an.x,vn.z,0,-vn.x,-sn.y,sn.x,0,-an.y,an.x,0,-vn.y,vn.x,0];return!yr(t,Nn,Fn,On,Ci)||(t=[1,0,0,0,1,0,0,0,1],!yr(t,Nn,Fn,On,Ci))?!1:(Pi.crossVectors(sn,an),t=[Pi.x,Pi.y,Pi.z],yr(t,Nn,Fn,On,Ci))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Ft).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=this.getSize(Ft).length()*.5),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()?this:(Zt[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),Zt[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),Zt[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),Zt[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),Zt[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),Zt[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),Zt[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),Zt[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(Zt),this)}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}toJSON(){return{min:this.min.toArray(),max:this.max.toArray()}}fromJSON(e){return this.min.fromArray(e.min),this.max.fromArray(e.max),this}}const Zt=[new N,new N,new N,new N,new N,new N,new N,new N],Ft=new N,Ri=new Ei,Nn=new N,Fn=new N,On=new N,sn=new N,an=new N,vn=new N,ai=new N,Ci=new N,Pi=new N,xn=new N;function yr(i,e,t,n,r){for(let s=0,a=i.length-3;s<=a;s+=3){xn.fromArray(i,s);const o=r.x*Math.abs(xn.x)+r.y*Math.abs(xn.y)+r.z*Math.abs(xn.z),l=e.dot(xn),c=t.dot(xn),d=n.dot(xn);if(Math.max(-Math.max(l,c,d),Math.min(l,c,d))>o)return!1}return!0}const qc=new Ei,oi=new N,Tr=new N;class fr{constructor(e=new N,t=-1){this.isSphere=!0,this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){const n=this.center;t!==void 0?n.copy(t):qc.setFromPoints(e).getCenter(n);let r=0;for(let s=0,a=e.length;sthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;oi.subVectors(e,this.center);const t=oi.lengthSq();if(t>this.radius*this.radius){const n=Math.sqrt(t),r=(n-this.radius)*.5;this.center.addScaledVector(oi,r/n),this.radius+=r}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(this.center.equals(e.center)===!0?this.radius=Math.max(this.radius,e.radius):(Tr.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(oi.copy(e.center).add(Tr)),this.expandByPoint(oi.copy(e.center).sub(Tr))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return new this.constructor().copy(this)}toJSON(){return{radius:this.radius,center:this.center.toArray()}}fromJSON(e){return this.radius=e.radius,this.center.fromArray(e.center),this}}const jt=new N,Ar=new N,Di=new N,on=new N,br=new N,Li=new N,wr=new N;class Ks{constructor(e=new N,t=new N(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,jt)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);const n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){const t=jt.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(jt.copy(this.origin).addScaledVector(this.direction,t),jt.distanceToSquared(e))}distanceSqToSegment(e,t,n,r){Ar.copy(e).add(t).multiplyScalar(.5),Di.copy(t).sub(e).normalize(),on.copy(this.origin).sub(Ar);const s=e.distanceTo(t)*.5,a=-this.direction.dot(Di),o=on.dot(this.direction),l=-on.dot(Di),c=on.lengthSq(),d=Math.abs(1-a*a);let h,f,m,_;if(d>0)if(h=a*l-o,f=a*o-l,_=s*d,h>=0)if(f>=-_)if(f<=_){const x=1/d;h*=x,f*=x,m=h*(h+a*f+2*o)+f*(a*h+f+2*l)+c}else f=s,h=Math.max(0,-(a*f+o)),m=-h*h+f*(f+2*l)+c;else f=-s,h=Math.max(0,-(a*f+o)),m=-h*h+f*(f+2*l)+c;else f<=-_?(h=Math.max(0,-(-a*s+o)),f=h>0?-s:Math.min(Math.max(-s,-l),s),m=-h*h+f*(f+2*l)+c):f<=_?(h=0,f=Math.min(Math.max(-s,-l),s),m=f*(f+2*l)+c):(h=Math.max(0,-(a*s+o)),f=h>0?s:Math.min(Math.max(-s,-l),s),m=-h*h+f*(f+2*l)+c);else f=a>0?-s:s,h=Math.max(0,-(a*f+o)),m=-h*h+f*(f+2*l)+c;return n&&n.copy(this.origin).addScaledVector(this.direction,h),r&&r.copy(Ar).addScaledVector(Di,f),m}intersectSphere(e,t){jt.subVectors(e.center,this.origin);const n=jt.dot(this.direction),r=jt.dot(jt)-n*n,s=e.radius*e.radius;if(r>s)return null;const a=Math.sqrt(s-r),o=n-a,l=n+a;return l<0?null:o<0?this.at(l,t):this.at(o,t)}intersectsSphere(e){return e.radius<0?!1:this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){const t=e.normal.dot(this.direction);if(t===0)return e.distanceToPoint(this.origin)===0?0:null;const n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null}intersectPlane(e,t){const n=this.distanceToPlane(e);return n===null?null:this.at(n,t)}intersectsPlane(e){const t=e.distanceToPoint(this.origin);return t===0||e.normal.dot(this.direction)*t<0}intersectBox(e,t){let n,r,s,a,o,l;const c=1/this.direction.x,d=1/this.direction.y,h=1/this.direction.z,f=this.origin;return c>=0?(n=(e.min.x-f.x)*c,r=(e.max.x-f.x)*c):(n=(e.max.x-f.x)*c,r=(e.min.x-f.x)*c),d>=0?(s=(e.min.y-f.y)*d,a=(e.max.y-f.y)*d):(s=(e.max.y-f.y)*d,a=(e.min.y-f.y)*d),n>a||s>r||((s>n||isNaN(n))&&(n=s),(a=0?(o=(e.min.z-f.z)*h,l=(e.max.z-f.z)*h):(o=(e.max.z-f.z)*h,l=(e.min.z-f.z)*h),n>l||o>r)||((o>n||n!==n)&&(n=o),(l=0?n:r,t)}intersectsBox(e){return this.intersectBox(e,jt)!==null}intersectTriangle(e,t,n,r,s){br.subVectors(t,e),Li.subVectors(n,e),wr.crossVectors(br,Li);let a=this.direction.dot(wr),o;if(a>0){if(r)return null;o=1}else if(a<0)o=-1,a=-a;else return null;on.subVectors(this.origin,e);const l=o*this.direction.dot(Li.crossVectors(on,Li));if(l<0)return null;const c=o*this.direction.dot(br.cross(on));if(c<0||l+c>a)return null;const d=-o*on.dot(wr);return d<0?null:this.at(d/a,s)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}}class it{constructor(e,t,n,r,s,a,o,l,c,d,h,f,m,_,x,p){it.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],e!==void 0&&this.set(e,t,n,r,s,a,o,l,c,d,h,f,m,_,x,p)}set(e,t,n,r,s,a,o,l,c,d,h,f,m,_,x,p){const u=this.elements;return u[0]=e,u[4]=t,u[8]=n,u[12]=r,u[1]=s,u[5]=a,u[9]=o,u[13]=l,u[2]=c,u[6]=d,u[10]=h,u[14]=f,u[3]=m,u[7]=_,u[11]=x,u[15]=p,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return new it().fromArray(this.elements)}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],this}copyPosition(e){const t=this.elements,n=e.elements;return t[12]=n[12],t[13]=n[13],t[14]=n[14],this}setFromMatrix3(e){const t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,n){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(e,t,n){return this.set(e.x,t.x,n.x,0,e.y,t.y,n.y,0,e.z,t.z,n.z,0,0,0,0,1),this}extractRotation(e){const t=this.elements,n=e.elements,r=1/Bn.setFromMatrixColumn(e,0).length(),s=1/Bn.setFromMatrixColumn(e,1).length(),a=1/Bn.setFromMatrixColumn(e,2).length();return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=0,t[4]=n[4]*s,t[5]=n[5]*s,t[6]=n[6]*s,t[7]=0,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){const t=this.elements,n=e.x,r=e.y,s=e.z,a=Math.cos(n),o=Math.sin(n),l=Math.cos(r),c=Math.sin(r),d=Math.cos(s),h=Math.sin(s);if(e.order==="XYZ"){const f=a*d,m=a*h,_=o*d,x=o*h;t[0]=l*d,t[4]=-l*h,t[8]=c,t[1]=m+_*c,t[5]=f-x*c,t[9]=-o*l,t[2]=x-f*c,t[6]=_+m*c,t[10]=a*l}else if(e.order==="YXZ"){const f=l*d,m=l*h,_=c*d,x=c*h;t[0]=f+x*o,t[4]=_*o-m,t[8]=a*c,t[1]=a*h,t[5]=a*d,t[9]=-o,t[2]=m*o-_,t[6]=x+f*o,t[10]=a*l}else if(e.order==="ZXY"){const f=l*d,m=l*h,_=c*d,x=c*h;t[0]=f-x*o,t[4]=-a*h,t[8]=_+m*o,t[1]=m+_*o,t[5]=a*d,t[9]=x-f*o,t[2]=-a*c,t[6]=o,t[10]=a*l}else if(e.order==="ZYX"){const f=a*d,m=a*h,_=o*d,x=o*h;t[0]=l*d,t[4]=_*c-m,t[8]=f*c+x,t[1]=l*h,t[5]=x*c+f,t[9]=m*c-_,t[2]=-c,t[6]=o*l,t[10]=a*l}else if(e.order==="YZX"){const f=a*l,m=a*c,_=o*l,x=o*c;t[0]=l*d,t[4]=x-f*h,t[8]=_*h+m,t[1]=h,t[5]=a*d,t[9]=-o*d,t[2]=-c*d,t[6]=m*h+_,t[10]=f-x*h}else if(e.order==="XZY"){const f=a*l,m=a*c,_=o*l,x=o*c;t[0]=l*d,t[4]=-h,t[8]=c*d,t[1]=f*h+x,t[5]=a*d,t[9]=m*h-_,t[2]=_*h-m,t[6]=o*d,t[10]=x*h+f}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(Yc,e,$c)}lookAt(e,t,n){const r=this.elements;return wt.subVectors(e,t),wt.lengthSq()===0&&(wt.z=1),wt.normalize(),cn.crossVectors(n,wt),cn.lengthSq()===0&&(Math.abs(n.z)===1?wt.x+=1e-4:wt.z+=1e-4,wt.normalize(),cn.crossVectors(n,wt)),cn.normalize(),Ii.crossVectors(wt,cn),r[0]=cn.x,r[4]=Ii.x,r[8]=wt.x,r[1]=cn.y,r[5]=Ii.y,r[9]=wt.y,r[2]=cn.z,r[6]=Ii.z,r[10]=wt.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,r=t.elements,s=this.elements,a=n[0],o=n[4],l=n[8],c=n[12],d=n[1],h=n[5],f=n[9],m=n[13],_=n[2],x=n[6],p=n[10],u=n[14],b=n[3],A=n[7],E=n[11],C=n[15],R=r[0],w=r[4],U=r[8],S=r[12],M=r[1],P=r[5],O=r[9],H=r[13],q=r[2],W=r[6],X=r[10],Z=r[14],G=r[3],se=r[7],le=r[11],Ee=r[15];return s[0]=a*R+o*M+l*q+c*G,s[4]=a*w+o*P+l*W+c*se,s[8]=a*U+o*O+l*X+c*le,s[12]=a*S+o*H+l*Z+c*Ee,s[1]=d*R+h*M+f*q+m*G,s[5]=d*w+h*P+f*W+m*se,s[9]=d*U+h*O+f*X+m*le,s[13]=d*S+h*H+f*Z+m*Ee,s[2]=_*R+x*M+p*q+u*G,s[6]=_*w+x*P+p*W+u*se,s[10]=_*U+x*O+p*X+u*le,s[14]=_*S+x*H+p*Z+u*Ee,s[3]=b*R+A*M+E*q+C*G,s[7]=b*w+A*P+E*W+C*se,s[11]=b*U+A*O+E*X+C*le,s[15]=b*S+A*H+E*Z+C*Ee,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[4],r=e[8],s=e[12],a=e[1],o=e[5],l=e[9],c=e[13],d=e[2],h=e[6],f=e[10],m=e[14],_=e[3],x=e[7],p=e[11],u=e[15];return _*(+s*l*h-r*c*h-s*o*f+n*c*f+r*o*m-n*l*m)+x*(+t*l*m-t*c*f+s*a*f-r*a*m+r*c*d-s*l*d)+p*(+t*c*h-t*o*m-s*a*h+n*a*m+s*o*d-n*c*d)+u*(-r*o*d-t*l*h+t*o*f+r*a*h-n*a*f+n*l*d)}transpose(){const e=this.elements;let t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,n){const r=this.elements;return e.isVector3?(r[12]=e.x,r[13]=e.y,r[14]=e.z):(r[12]=e,r[13]=t,r[14]=n),this}invert(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],l=e[6],c=e[7],d=e[8],h=e[9],f=e[10],m=e[11],_=e[12],x=e[13],p=e[14],u=e[15],b=h*p*c-x*f*c+x*l*m-o*p*m-h*l*u+o*f*u,A=_*f*c-d*p*c-_*l*m+a*p*m+d*l*u-a*f*u,E=d*x*c-_*h*c+_*o*m-a*x*m-d*o*u+a*h*u,C=_*h*l-d*x*l-_*o*f+a*x*f+d*o*p-a*h*p,R=t*b+n*A+r*E+s*C;if(R===0)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const w=1/R;return e[0]=b*w,e[1]=(x*f*s-h*p*s-x*r*m+n*p*m+h*r*u-n*f*u)*w,e[2]=(o*p*s-x*l*s+x*r*c-n*p*c-o*r*u+n*l*u)*w,e[3]=(h*l*s-o*f*s-h*r*c+n*f*c+o*r*m-n*l*m)*w,e[4]=A*w,e[5]=(d*p*s-_*f*s+_*r*m-t*p*m-d*r*u+t*f*u)*w,e[6]=(_*l*s-a*p*s-_*r*c+t*p*c+a*r*u-t*l*u)*w,e[7]=(a*f*s-d*l*s+d*r*c-t*f*c-a*r*m+t*l*m)*w,e[8]=E*w,e[9]=(_*h*s-d*x*s-_*n*m+t*x*m+d*n*u-t*h*u)*w,e[10]=(a*x*s-_*o*s+_*n*c-t*x*c-a*n*u+t*o*u)*w,e[11]=(d*o*s-a*h*s-d*n*c+t*h*c+a*n*m-t*o*m)*w,e[12]=C*w,e[13]=(d*x*r-_*h*r+_*n*f-t*x*f-d*n*p+t*h*p)*w,e[14]=(_*o*r-a*x*r-_*n*l+t*x*l+a*n*p-t*o*p)*w,e[15]=(a*h*r-d*o*r+d*n*l-t*h*l-a*n*f+t*o*f)*w,this}scale(e){const t=this.elements,n=e.x,r=e.y,s=e.z;return t[0]*=n,t[4]*=r,t[8]*=s,t[1]*=n,t[5]*=r,t[9]*=s,t[2]*=n,t[6]*=r,t[10]*=s,t[3]*=n,t[7]*=r,t[11]*=s,this}getMaxScaleOnAxis(){const e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],n=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],r=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,n,r))}makeTranslation(e,t,n){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,n,0,0,0,1),this}makeRotationX(e){const t=Math.cos(e),n=Math.sin(e);return this.set(1,0,0,0,0,t,-n,0,0,n,t,0,0,0,0,1),this}makeRotationY(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,0,n,0,0,1,0,0,-n,0,t,0,0,0,0,1),this}makeRotationZ(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,0,n,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){const n=Math.cos(t),r=Math.sin(t),s=1-n,a=e.x,o=e.y,l=e.z,c=s*a,d=s*o;return this.set(c*a+n,c*o-r*l,c*l+r*o,0,c*o+r*l,d*o+n,d*l-r*a,0,c*l-r*o,d*l+r*a,s*l*l+n,0,0,0,0,1),this}makeScale(e,t,n){return this.set(e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1),this}makeShear(e,t,n,r,s,a){return this.set(1,n,s,0,e,1,a,0,t,r,1,0,0,0,0,1),this}compose(e,t,n){const r=this.elements,s=t._x,a=t._y,o=t._z,l=t._w,c=s+s,d=a+a,h=o+o,f=s*c,m=s*d,_=s*h,x=a*d,p=a*h,u=o*h,b=l*c,A=l*d,E=l*h,C=n.x,R=n.y,w=n.z;return r[0]=(1-(x+u))*C,r[1]=(m+E)*C,r[2]=(_-A)*C,r[3]=0,r[4]=(m-E)*R,r[5]=(1-(f+u))*R,r[6]=(p+b)*R,r[7]=0,r[8]=(_+A)*w,r[9]=(p-b)*w,r[10]=(1-(f+x))*w,r[11]=0,r[12]=e.x,r[13]=e.y,r[14]=e.z,r[15]=1,this}decompose(e,t,n){const r=this.elements;let s=Bn.set(r[0],r[1],r[2]).length();const a=Bn.set(r[4],r[5],r[6]).length(),o=Bn.set(r[8],r[9],r[10]).length();this.determinant()<0&&(s=-s),e.x=r[12],e.y=r[13],e.z=r[14],Ot.copy(this);const c=1/s,d=1/a,h=1/o;return Ot.elements[0]*=c,Ot.elements[1]*=c,Ot.elements[2]*=c,Ot.elements[4]*=d,Ot.elements[5]*=d,Ot.elements[6]*=d,Ot.elements[8]*=h,Ot.elements[9]*=h,Ot.elements[10]*=h,t.setFromRotationMatrix(Ot),n.x=s,n.y=a,n.z=o,this}makePerspective(e,t,n,r,s,a,o=Xt,l=!1){const c=this.elements,d=2*s/(t-e),h=2*s/(n-r),f=(t+e)/(t-e),m=(n+r)/(n-r);let _,x;if(l)_=s/(a-s),x=a*s/(a-s);else if(o===Xt)_=-(a+s)/(a-s),x=-2*a*s/(a-s);else if(o===ar)_=-a/(a-s),x=-a*s/(a-s);else throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+o);return c[0]=d,c[4]=0,c[8]=f,c[12]=0,c[1]=0,c[5]=h,c[9]=m,c[13]=0,c[2]=0,c[6]=0,c[10]=_,c[14]=x,c[3]=0,c[7]=0,c[11]=-1,c[15]=0,this}makeOrthographic(e,t,n,r,s,a,o=Xt,l=!1){const c=this.elements,d=2/(t-e),h=2/(n-r),f=-(t+e)/(t-e),m=-(n+r)/(n-r);let _,x;if(l)_=1/(a-s),x=a/(a-s);else if(o===Xt)_=-2/(a-s),x=-(a+s)/(a-s);else if(o===ar)_=-1/(a-s),x=-s/(a-s);else throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);return c[0]=d,c[4]=0,c[8]=0,c[12]=f,c[1]=0,c[5]=h,c[9]=0,c[13]=m,c[2]=0,c[6]=0,c[10]=_,c[14]=x,c[3]=0,c[7]=0,c[11]=0,c[15]=1,this}equals(e){const t=this.elements,n=e.elements;for(let r=0;r<16;r++)if(t[r]!==n[r])return!1;return!0}fromArray(e,t=0){for(let n=0;n<16;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e[t+9]=n[9],e[t+10]=n[10],e[t+11]=n[11],e[t+12]=n[12],e[t+13]=n[13],e[t+14]=n[14],e[t+15]=n[15],e}}const Bn=new N,Ot=new it,Yc=new N(0,0,0),$c=new N(1,1,1),cn=new N,Ii=new N,wt=new N,xa=new it,Ma=new Si;class $t{constructor(e=0,t=0,n=0,r=$t.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=n,this._order=r}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,n,r=this._order){return this._x=e,this._y=t,this._z=n,this._order=r,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,n=!0){const r=e.elements,s=r[0],a=r[4],o=r[8],l=r[1],c=r[5],d=r[9],h=r[2],f=r[6],m=r[10];switch(t){case"XYZ":this._y=Math.asin(ze(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-d,m),this._z=Math.atan2(-a,s)):(this._x=Math.atan2(f,c),this._z=0);break;case"YXZ":this._x=Math.asin(-ze(d,-1,1)),Math.abs(d)<.9999999?(this._y=Math.atan2(o,m),this._z=Math.atan2(l,c)):(this._y=Math.atan2(-h,s),this._z=0);break;case"ZXY":this._x=Math.asin(ze(f,-1,1)),Math.abs(f)<.9999999?(this._y=Math.atan2(-h,m),this._z=Math.atan2(-a,c)):(this._y=0,this._z=Math.atan2(l,s));break;case"ZYX":this._y=Math.asin(-ze(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(f,m),this._z=Math.atan2(l,s)):(this._x=0,this._z=Math.atan2(-a,c));break;case"YZX":this._z=Math.asin(ze(l,-1,1)),Math.abs(l)<.9999999?(this._x=Math.atan2(-d,c),this._y=Math.atan2(-h,s)):(this._x=0,this._y=Math.atan2(o,m));break;case"XZY":this._z=Math.asin(-ze(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(f,c),this._y=Math.atan2(o,s)):(this._x=Math.atan2(-d,m),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,n===!0&&this._onChangeCallback(),this}setFromQuaternion(e,t,n){return xa.makeRotationFromQuaternion(e),this.setFromRotationMatrix(xa,t,n)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return Ma.setFromEuler(this),this.setFromQuaternion(Ma,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],e[3]!==void 0&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}$t.DEFAULT_ORDER="XYZ";class Zs{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let t=0;t1){for(let n=0;n0&&(r.userData=this.userData),r.layers=this.layers.mask,r.matrix=this.matrix.toArray(),r.up=this.up.toArray(),this.matrixAutoUpdate===!1&&(r.matrixAutoUpdate=!1),this.isInstancedMesh&&(r.type="InstancedMesh",r.count=this.count,r.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(r.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(r.type="BatchedMesh",r.perObjectFrustumCulled=this.perObjectFrustumCulled,r.sortObjects=this.sortObjects,r.drawRanges=this._drawRanges,r.reservedRanges=this._reservedRanges,r.geometryInfo=this._geometryInfo.map(o=>({...o,boundingBox:o.boundingBox?o.boundingBox.toJSON():void 0,boundingSphere:o.boundingSphere?o.boundingSphere.toJSON():void 0})),r.instanceInfo=this._instanceInfo.map(o=>({...o})),r.availableInstanceIds=this._availableInstanceIds.slice(),r.availableGeometryIds=this._availableGeometryIds.slice(),r.nextIndexStart=this._nextIndexStart,r.nextVertexStart=this._nextVertexStart,r.geometryCount=this._geometryCount,r.maxInstanceCount=this._maxInstanceCount,r.maxVertexCount=this._maxVertexCount,r.maxIndexCount=this._maxIndexCount,r.geometryInitialized=this._geometryInitialized,r.matricesTexture=this._matricesTexture.toJSON(e),r.indirectTexture=this._indirectTexture.toJSON(e),this._colorsTexture!==null&&(r.colorsTexture=this._colorsTexture.toJSON(e)),this.boundingSphere!==null&&(r.boundingSphere=this.boundingSphere.toJSON()),this.boundingBox!==null&&(r.boundingBox=this.boundingBox.toJSON()));function s(o,l){return o[l.uuid]===void 0&&(o[l.uuid]=l.toJSON(e)),l.uuid}if(this.isScene)this.background&&(this.background.isColor?r.background=this.background.toJSON():this.background.isTexture&&(r.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(r.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){r.geometry=s(e.geometries,this.geometry);const o=this.geometry.parameters;if(o!==void 0&&o.shapes!==void 0){const l=o.shapes;if(Array.isArray(l))for(let c=0,d=l.length;c0){r.children=[];for(let o=0;o0){r.animations=[];for(let o=0;o0&&(n.geometries=o),l.length>0&&(n.materials=l),c.length>0&&(n.textures=c),d.length>0&&(n.images=d),h.length>0&&(n.shapes=h),f.length>0&&(n.skeletons=f),m.length>0&&(n.animations=m),_.length>0&&(n.nodes=_)}return n.object=r,n;function a(o){const l=[];for(const c in o){const d=o[c];delete d.metadata,l.push(d)}return l}}clone(e){return new this.constructor().copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),t===!0)for(let n=0;n0?r.multiplyScalar(1/Math.sqrt(s)):r.set(0,0,0)}static getBarycoord(e,t,n,r,s){Bt.subVectors(r,t),Qt.subVectors(n,t),Cr.subVectors(e,t);const a=Bt.dot(Bt),o=Bt.dot(Qt),l=Bt.dot(Cr),c=Qt.dot(Qt),d=Qt.dot(Cr),h=a*c-o*o;if(h===0)return s.set(0,0,0),null;const f=1/h,m=(c*l-o*d)*f,_=(a*d-o*l)*f;return s.set(1-m-_,_,m)}static containsPoint(e,t,n,r){return this.getBarycoord(e,t,n,r,en)===null?!1:en.x>=0&&en.y>=0&&en.x+en.y<=1}static getInterpolation(e,t,n,r,s,a,o,l){return this.getBarycoord(e,t,n,r,en)===null?(l.x=0,l.y=0,"z"in l&&(l.z=0),"w"in l&&(l.w=0),null):(l.setScalar(0),l.addScaledVector(s,en.x),l.addScaledVector(a,en.y),l.addScaledVector(o,en.z),l)}static getInterpolatedAttribute(e,t,n,r,s,a){return Ir.setScalar(0),Ur.setScalar(0),Nr.setScalar(0),Ir.fromBufferAttribute(e,t),Ur.fromBufferAttribute(e,n),Nr.fromBufferAttribute(e,r),a.setScalar(0),a.addScaledVector(Ir,s.x),a.addScaledVector(Ur,s.y),a.addScaledVector(Nr,s.z),a}static isFrontFacing(e,t,n,r){return Bt.subVectors(n,t),Qt.subVectors(e,t),Bt.cross(Qt).dot(r)<0}set(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this}setFromPointsAndIndices(e,t,n,r){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[r]),this}setFromAttributeAndIndices(e,t,n,r){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,n),this.c.fromBufferAttribute(e,r),this}clone(){return new this.constructor().copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return Bt.subVectors(this.c,this.b),Qt.subVectors(this.a,this.b),Bt.cross(Qt).length()*.5}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return Ut.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return Ut.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,n,r,s){return Ut.getInterpolation(e,this.a,this.b,this.c,t,n,r,s)}containsPoint(e){return Ut.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return Ut.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){const n=this.a,r=this.b,s=this.c;let a,o;Gn.subVectors(r,n),Vn.subVectors(s,n),Pr.subVectors(e,n);const l=Gn.dot(Pr),c=Vn.dot(Pr);if(l<=0&&c<=0)return t.copy(n);Dr.subVectors(e,r);const d=Gn.dot(Dr),h=Vn.dot(Dr);if(d>=0&&h<=d)return t.copy(r);const f=l*h-d*c;if(f<=0&&l>=0&&d<=0)return a=l/(l-d),t.copy(n).addScaledVector(Gn,a);Lr.subVectors(e,s);const m=Gn.dot(Lr),_=Vn.dot(Lr);if(_>=0&&m<=_)return t.copy(s);const x=m*c-l*_;if(x<=0&&c>=0&&_<=0)return o=c/(c-_),t.copy(n).addScaledVector(Vn,o);const p=d*_-m*h;if(p<=0&&h-d>=0&&m-_>=0)return ba.subVectors(s,r),o=(h-d)/(h-d+(m-_)),t.copy(r).addScaledVector(ba,o);const u=1/(p+x+f);return a=x*u,o=f*u,t.copy(n).addScaledVector(Gn,a).addScaledVector(Vn,o)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}}const Co={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},ln={h:0,s:0,l:0},Ni={h:0,s:0,l:0};function Fr(i,e,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?i+(e-i)*6*t:t<1/2?e:t<2/3?i+(e-i)*6*(2/3-t):i}class Fe{constructor(e,t,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,n)}set(e,t,n){if(t===void 0&&n===void 0){const r=e;r&&r.isColor?this.copy(r):typeof r=="number"?this.setHex(r):typeof r=="string"&&this.setStyle(r)}else this.setRGB(e,t,n);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=Lt){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(e&255)/255,ke.colorSpaceToWorking(this,t),this}setRGB(e,t,n,r=ke.workingColorSpace){return this.r=e,this.g=t,this.b=n,ke.colorSpaceToWorking(this,r),this}setHSL(e,t,n,r=ke.workingColorSpace){if(e=Oc(e,1),t=ze(t,0,1),n=ze(n,0,1),t===0)this.r=this.g=this.b=n;else{const s=n<=.5?n*(1+t):n+t-n*t,a=2*n-s;this.r=Fr(a,s,e+1/3),this.g=Fr(a,s,e),this.b=Fr(a,s,e-1/3)}return ke.colorSpaceToWorking(this,r),this}setStyle(e,t=Lt){function n(s){s!==void 0&&parseFloat(s)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let r;if(r=/^(\w+)\(([^\)]*)\)/.exec(e)){let s;const a=r[1],o=r[2];switch(a){case"rgb":case"rgba":if(s=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setRGB(Math.min(255,parseInt(s[1],10))/255,Math.min(255,parseInt(s[2],10))/255,Math.min(255,parseInt(s[3],10))/255,t);if(s=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setRGB(Math.min(100,parseInt(s[1],10))/100,Math.min(100,parseInt(s[2],10))/100,Math.min(100,parseInt(s[3],10))/100,t);break;case"hsl":case"hsla":if(s=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setHSL(parseFloat(s[1])/360,parseFloat(s[2])/100,parseFloat(s[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(r=/^\#([A-Fa-f\d]+)$/.exec(e)){const s=r[1],a=s.length;if(a===3)return this.setRGB(parseInt(s.charAt(0),16)/15,parseInt(s.charAt(1),16)/15,parseInt(s.charAt(2),16)/15,t);if(a===6)return this.setHex(parseInt(s,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=Lt){const n=Co[e.toLowerCase()];return n!==void 0?this.setHex(n,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=rn(e.r),this.g=rn(e.g),this.b=rn(e.b),this}copyLinearToSRGB(e){return this.r=Kn(e.r),this.g=Kn(e.g),this.b=Kn(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=Lt){return ke.workingToColorSpace(_t.copy(this),e),Math.round(ze(_t.r*255,0,255))*65536+Math.round(ze(_t.g*255,0,255))*256+Math.round(ze(_t.b*255,0,255))}getHexString(e=Lt){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=ke.workingColorSpace){ke.workingToColorSpace(_t.copy(this),t);const n=_t.r,r=_t.g,s=_t.b,a=Math.max(n,r,s),o=Math.min(n,r,s);let l,c;const d=(o+a)/2;if(o===a)l=0,c=0;else{const h=a-o;switch(c=d<=.5?h/(a+o):h/(2-a-o),a){case n:l=(r-s)/h+(r0!=e>0&&this.version++,this._alphaTest=e}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(e!==void 0)for(const t in e){const n=e[t];if(n===void 0){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}const r=this[t];if(r===void 0){console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`);continue}r&&r.isColor?r.set(n):r&&r.isVector3&&n&&n.isVector3?r.copy(n):this[t]=n}}toJSON(e){const t=e===void 0||typeof e=="string";t&&(e={textures:{},images:{}});const n={metadata:{version:4.7,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,this.name!==""&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),this.roughness!==void 0&&(n.roughness=this.roughness),this.metalness!==void 0&&(n.metalness=this.metalness),this.sheen!==void 0&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),this.sheenRoughness!==void 0&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity!==void 0&&this.emissiveIntensity!==1&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),this.specularIntensity!==void 0&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),this.shininess!==void 0&&(n.shininess=this.shininess),this.clearcoat!==void 0&&(n.clearcoat=this.clearcoat),this.clearcoatRoughness!==void 0&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.sheenColorMap&&this.sheenColorMap.isTexture&&(n.sheenColorMap=this.sheenColorMap.toJSON(e).uuid),this.sheenRoughnessMap&&this.sheenRoughnessMap.isTexture&&(n.sheenRoughnessMap=this.sheenRoughnessMap.toJSON(e).uuid),this.dispersion!==void 0&&(n.dispersion=this.dispersion),this.iridescence!==void 0&&(n.iridescence=this.iridescence),this.iridescenceIOR!==void 0&&(n.iridescenceIOR=this.iridescenceIOR),this.iridescenceThicknessRange!==void 0&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),this.anisotropy!==void 0&&(n.anisotropy=this.anisotropy),this.anisotropyRotation!==void 0&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(e).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(e).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(e).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(e).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(e).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(e).uuid,this.combine!==void 0&&(n.combine=this.combine)),this.envMapRotation!==void 0&&(n.envMapRotation=this.envMapRotation.toArray()),this.envMapIntensity!==void 0&&(n.envMapIntensity=this.envMapIntensity),this.reflectivity!==void 0&&(n.reflectivity=this.reflectivity),this.refractionRatio!==void 0&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(e).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(e).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(e).uuid),this.attenuationDistance!==void 0&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.shadowSide!==null&&(n.shadowSide=this.shadowSide),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==$n&&(n.blending=this.blending),this.side!==pn&&(n.side=this.side),this.vertexColors===!0&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.transparent===!0&&(n.transparent=!0),this.blendSrc!==Zr&&(n.blendSrc=this.blendSrc),this.blendDst!==jr&&(n.blendDst=this.blendDst),this.blendEquation!==bn&&(n.blendEquation=this.blendEquation),this.blendSrcAlpha!==null&&(n.blendSrcAlpha=this.blendSrcAlpha),this.blendDstAlpha!==null&&(n.blendDstAlpha=this.blendDstAlpha),this.blendEquationAlpha!==null&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),this.blendAlpha!==0&&(n.blendAlpha=this.blendAlpha),this.depthFunc!==Zn&&(n.depthFunc=this.depthFunc),this.depthTest===!1&&(n.depthTest=this.depthTest),this.depthWrite===!1&&(n.depthWrite=this.depthWrite),this.colorWrite===!1&&(n.colorWrite=this.colorWrite),this.stencilWriteMask!==255&&(n.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==da&&(n.stencilFunc=this.stencilFunc),this.stencilRef!==0&&(n.stencilRef=this.stencilRef),this.stencilFuncMask!==255&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==In&&(n.stencilFail=this.stencilFail),this.stencilZFail!==In&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==In&&(n.stencilZPass=this.stencilZPass),this.stencilWrite===!0&&(n.stencilWrite=this.stencilWrite),this.rotation!==void 0&&this.rotation!==0&&(n.rotation=this.rotation),this.polygonOffset===!0&&(n.polygonOffset=!0),this.polygonOffsetFactor!==0&&(n.polygonOffsetFactor=this.polygonOffsetFactor),this.polygonOffsetUnits!==0&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth!==void 0&&this.linewidth!==1&&(n.linewidth=this.linewidth),this.dashSize!==void 0&&(n.dashSize=this.dashSize),this.gapSize!==void 0&&(n.gapSize=this.gapSize),this.scale!==void 0&&(n.scale=this.scale),this.dithering===!0&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),this.alphaHash===!0&&(n.alphaHash=!0),this.alphaToCoverage===!0&&(n.alphaToCoverage=!0),this.premultipliedAlpha===!0&&(n.premultipliedAlpha=!0),this.forceSinglePass===!0&&(n.forceSinglePass=!0),this.wireframe===!0&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!=="round"&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!=="round"&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading===!0&&(n.flatShading=!0),this.visible===!1&&(n.visible=!1),this.toneMapped===!1&&(n.toneMapped=!1),this.fog===!1&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData);function r(s){const a=[];for(const o in s){const l=s[o];delete l.metadata,a.push(l)}return a}if(t){const s=r(e.textures),a=r(e.images);s.length>0&&(n.textures=s),a.length>0&&(n.images=a)}return n}clone(){return new this.constructor().copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;const t=e.clippingPlanes;let n=null;if(t!==null){const r=t.length;n=new Array(r);for(let s=0;s!==r;++s)n[s]=t[s].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){e===!0&&this.version++}}class cr extends ni{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Fe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new $t,this.combine=mo,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}const ot=new N,Fi=new Ge;let el=0;class qt{constructor(e,t,n=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,Object.defineProperty(this,"id",{value:el++}),this.name="",this.array=e,this.itemSize=t,this.count=e!==void 0?e.length/t:0,this.normalized=n,this.usage=fa,this.updateRanges=[],this.gpuType=nn,this.version=0}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,n){e*=this.itemSize,n*=t.itemSize;for(let r=0,s=this.itemSize;rt.count&&console.warn("THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),t.needsUpdate=!0}return this}computeBoundingBox(){this.boundingBox===null&&(this.boundingBox=new Ei);const e=this.attributes.position,t=this.morphAttributes.position;if(e&&e.isGLBufferAttribute){console.error("THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),this.boundingBox.set(new N(-1/0,-1/0,-1/0),new N(1/0,1/0,1/0));return}if(e!==void 0){if(this.boundingBox.setFromBufferAttribute(e),t)for(let n=0,r=t.length;n0&&(e.userData=this.userData),this.parameters!==void 0){const l=this.parameters;for(const c in l)l[c]!==void 0&&(e[c]=l[c]);return e}e.data={attributes:{}};const t=this.index;t!==null&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});const n=this.attributes;for(const l in n){const c=n[l];e.data.attributes[l]=c.toJSON(e.data)}const r={};let s=!1;for(const l in this.morphAttributes){const c=this.morphAttributes[l],d=[];for(let h=0,f=c.length;h0&&(r[l]=d,s=!0)}s&&(e.data.morphAttributes=r,e.data.morphTargetsRelative=this.morphTargetsRelative);const a=this.groups;a.length>0&&(e.data.groups=JSON.parse(JSON.stringify(a)));const o=this.boundingSphere;return o!==null&&(e.data.boundingSphere=o.toJSON()),e}clone(){return new this.constructor().copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const t={};this.name=e.name;const n=e.index;n!==null&&this.setIndex(n.clone());const r=e.attributes;for(const c in r){const d=r[c];this.setAttribute(c,d.clone(t))}const s=e.morphAttributes;for(const c in s){const d=[],h=s[c];for(let f=0,m=h.length;f0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,a=r.length;s(e.far-e.near)**2))&&(wa.copy(s).invert(),Mn.copy(e.ray).applyMatrix4(wa),!(n.boundingBox!==null&&Mn.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(e,t,Mn)))}_computeIntersections(e,t,n){let r;const s=this.geometry,a=this.material,o=s.index,l=s.attributes.position,c=s.attributes.uv,d=s.attributes.uv1,h=s.attributes.normal,f=s.groups,m=s.drawRange;if(o!==null)if(Array.isArray(a))for(let _=0,x=f.length;_t.far?null:{distance:c,point:Vi.clone(),object:i}}function ki(i,e,t,n,r,s,a,o,l,c){i.getVertexPosition(o,Bi),i.getVertexPosition(l,zi),i.getVertexPosition(c,Hi);const d=nl(i,e,t,n,Bi,zi,Hi,Ca);if(d){const h=new N;Ut.getBarycoord(Ca,Bi,zi,Hi,h),r&&(d.uv=Ut.getInterpolatedAttribute(r,o,l,c,h,new Ge)),s&&(d.uv1=Ut.getInterpolatedAttribute(s,o,l,c,h,new Ge)),a&&(d.normal=Ut.getInterpolatedAttribute(a,o,l,c,h,new N),d.normal.dot(n.direction)>0&&d.normal.multiplyScalar(-1));const f={a:o,b:l,c,normal:new N,materialIndex:0};Ut.getNormal(Bi,zi,Hi,f.normal),d.face=f,d.barycoord=h}return d}class yi extends Nt{constructor(e=1,t=1,n=1,r=1,s=1,a=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:n,widthSegments:r,heightSegments:s,depthSegments:a};const o=this;r=Math.floor(r),s=Math.floor(s),a=Math.floor(a);const l=[],c=[],d=[],h=[];let f=0,m=0;_("z","y","x",-1,-1,n,t,e,a,s,0),_("z","y","x",1,-1,n,t,-e,a,s,1),_("x","z","y",1,1,e,n,t,r,a,2),_("x","z","y",1,-1,e,n,-t,r,a,3),_("x","y","z",1,-1,e,t,n,r,s,4),_("x","y","z",-1,-1,e,t,-n,r,s,5),this.setIndex(l),this.setAttribute("position",new ct(c,3)),this.setAttribute("normal",new ct(d,3)),this.setAttribute("uv",new ct(h,2));function _(x,p,u,b,A,E,C,R,w,U,S){const M=E/w,P=C/U,O=E/2,H=C/2,q=R/2,W=w+1,X=U+1;let Z=0,G=0;const se=new N;for(let le=0;le0?1:-1,d.push(se.x,se.y,se.z),h.push(Oe/w),h.push(1-le/U),Z+=1}}for(let le=0;le>8&255]+pt[i>>16&255]+pt[i>>24&255]+"-"+pt[e&255]+pt[e>>8&255]+"-"+pt[e>>16&15|64]+pt[e>>24&255]+"-"+pt[t&63|128]+pt[t>>8&255]+"-"+pt[t>>16&255]+pt[t>>24&255]+pt[n&255]+pt[n>>8&255]+pt[n>>16&255]+pt[n>>24&255]).toLowerCase()}function He(i,e,t){return Math.max(e,Math.min(t,i))}function Rl(i,e){return(i%e+e)%e}function dr(i,e,t){return(1-t)*i+t*e}function ci(i,e){switch(e.constructor){case Float32Array:return i;case Uint32Array:return i/4294967295;case Uint16Array:return i/65535;case Uint8Array:return i/255;case Int32Array:return Math.max(i/2147483647,-1);case Int16Array:return Math.max(i/32767,-1);case Int8Array:return Math.max(i/127,-1);default:throw new Error("Invalid component type.")}}function St(i,e){switch(e.constructor){case Float32Array:return i;case Uint32Array:return Math.round(i*4294967295);case Uint16Array:return Math.round(i*65535);case Uint8Array:return Math.round(i*255);case Int32Array:return Math.round(i*2147483647);case Int16Array:return Math.round(i*32767);case Int8Array:return Math.round(i*127);default:throw new Error("Invalid component type.")}}class Ge{constructor(e=0,t=0){Ge.prototype.isVector2=!0,this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){const t=this.x,n=this.y,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6],this.y=r[1]*t+r[4]*n+r[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=He(this.x,e.x,t.x),this.y=He(this.y,e.y,t.y),this}clampScalar(e,t){return this.x=He(this.x,e,t),this.y=He(this.y,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(He(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(He(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y;return t*t+n*n}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){const n=Math.cos(t),r=Math.sin(t),s=this.x-e.x,a=this.y-e.y;return this.x=s*n-a*r+e.x,this.y=s*r+a*n+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Ai{constructor(e=0,t=0,n=0,r=1){this.isQuaternion=!0,this._x=e,this._y=t,this._z=n,this._w=r}static slerpFlat(e,t,n,r,s,a,o){let c=n[r+0],l=n[r+1],h=n[r+2],d=n[r+3];const f=s[a+0],m=s[a+1],_=s[a+2],x=s[a+3];if(o===0){e[t+0]=c,e[t+1]=l,e[t+2]=h,e[t+3]=d;return}if(o===1){e[t+0]=f,e[t+1]=m,e[t+2]=_,e[t+3]=x;return}if(d!==x||c!==f||l!==m||h!==_){let p=1-o;const u=c*f+l*m+h*_+d*x,b=u>=0?1:-1,A=1-u*u;if(A>Number.EPSILON){const D=Math.sqrt(A),R=Math.atan2(D,u*b);p=Math.sin(p*R)/D,o=Math.sin(o*R)/D}const E=o*b;if(c=c*p+f*E,l=l*p+m*E,h=h*p+_*E,d=d*p+x*E,p===1-o){const D=1/Math.sqrt(c*c+l*l+h*h+d*d);c*=D,l*=D,h*=D,d*=D}}e[t]=c,e[t+1]=l,e[t+2]=h,e[t+3]=d}static multiplyQuaternionsFlat(e,t,n,r,s,a){const o=n[r],c=n[r+1],l=n[r+2],h=n[r+3],d=s[a],f=s[a+1],m=s[a+2],_=s[a+3];return e[t]=o*_+h*d+c*m-l*f,e[t+1]=c*_+h*f+l*d-o*m,e[t+2]=l*_+h*m+o*f-c*d,e[t+3]=h*_-o*d-c*f-l*m,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,n,r){return this._x=e,this._y=t,this._z=n,this._w=r,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){const n=e._x,r=e._y,s=e._z,a=e._order,o=Math.cos,c=Math.sin,l=o(n/2),h=o(r/2),d=o(s/2),f=c(n/2),m=c(r/2),_=c(s/2);switch(a){case"XYZ":this._x=f*h*d+l*m*_,this._y=l*m*d-f*h*_,this._z=l*h*_+f*m*d,this._w=l*h*d-f*m*_;break;case"YXZ":this._x=f*h*d+l*m*_,this._y=l*m*d-f*h*_,this._z=l*h*_-f*m*d,this._w=l*h*d+f*m*_;break;case"ZXY":this._x=f*h*d-l*m*_,this._y=l*m*d+f*h*_,this._z=l*h*_+f*m*d,this._w=l*h*d-f*m*_;break;case"ZYX":this._x=f*h*d-l*m*_,this._y=l*m*d+f*h*_,this._z=l*h*_-f*m*d,this._w=l*h*d+f*m*_;break;case"YZX":this._x=f*h*d+l*m*_,this._y=l*m*d+f*h*_,this._z=l*h*_-f*m*d,this._w=l*h*d-f*m*_;break;case"XZY":this._x=f*h*d-l*m*_,this._y=l*m*d-f*h*_,this._z=l*h*_+f*m*d,this._w=l*h*d+f*m*_;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+a)}return t===!0&&this._onChangeCallback(),this}setFromAxisAngle(e,t){const n=t/2,r=Math.sin(n);return this._x=e.x*r,this._y=e.y*r,this._z=e.z*r,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(e){const t=e.elements,n=t[0],r=t[4],s=t[8],a=t[1],o=t[5],c=t[9],l=t[2],h=t[6],d=t[10],f=n+o+d;if(f>0){const m=.5/Math.sqrt(f+1);this._w=.25/m,this._x=(h-c)*m,this._y=(s-l)*m,this._z=(a-r)*m}else if(n>o&&n>d){const m=2*Math.sqrt(1+n-o-d);this._w=(h-c)/m,this._x=.25*m,this._y=(r+a)/m,this._z=(s+l)/m}else if(o>d){const m=2*Math.sqrt(1+o-n-d);this._w=(s-l)/m,this._x=(r+a)/m,this._y=.25*m,this._z=(c+h)/m}else{const m=2*Math.sqrt(1+d-n-o);this._w=(a-r)/m,this._x=(s+l)/m,this._y=(c+h)/m,this._z=.25*m}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let n=e.dot(t)+1;return n<1e-8?(n=0,Math.abs(e.x)>Math.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs(He(this.dot(e),-1,1)))}rotateTowards(e,t){const n=this.angleTo(e);if(n===0)return this;const r=Math.min(1,t/n);return this.slerp(e,r),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let e=this.length();return e===0?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){const n=e._x,r=e._y,s=e._z,a=e._w,o=t._x,c=t._y,l=t._z,h=t._w;return this._x=n*h+a*o+r*l-s*c,this._y=r*h+a*c+s*o-n*l,this._z=s*h+a*l+n*c-r*o,this._w=a*h-n*o-r*c-s*l,this._onChangeCallback(),this}slerp(e,t){if(t===0)return this;if(t===1)return this.copy(e);const n=this._x,r=this._y,s=this._z,a=this._w;let o=a*e._w+n*e._x+r*e._y+s*e._z;if(o<0?(this._w=-e._w,this._x=-e._x,this._y=-e._y,this._z=-e._z,o=-o):this.copy(e),o>=1)return this._w=a,this._x=n,this._y=r,this._z=s,this;const c=1-o*o;if(c<=Number.EPSILON){const m=1-t;return this._w=m*a+t*this._w,this._x=m*n+t*this._x,this._y=m*r+t*this._y,this._z=m*s+t*this._z,this.normalize(),this}const l=Math.sqrt(c),h=Math.atan2(l,o),d=Math.sin((1-t)*h)/l,f=Math.sin(t*h)/l;return this._w=a*d+this._w*f,this._x=n*d+this._x*f,this._y=r*d+this._y*f,this._z=s*d+this._z*f,this._onChangeCallback(),this}slerpQuaternions(e,t,n){return this.copy(e).slerp(t,n)}random(){const e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),n=Math.random(),r=Math.sqrt(1-n),s=Math.sqrt(n);return this.set(r*Math.sin(e),r*Math.cos(e),s*Math.sin(t),s*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class F{constructor(e=0,t=0,n=0){F.prototype.isVector3=!0,this.x=e,this.y=t,this.z=n}set(e,t,n){return n===void 0&&(n=this.z),this.x=e,this.y=t,this.z=n,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(oa.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(oa.setFromAxisAngle(e,t))}applyMatrix3(e){const t=this.x,n=this.y,r=this.z,s=e.elements;return this.x=s[0]*t+s[3]*n+s[6]*r,this.y=s[1]*t+s[4]*n+s[7]*r,this.z=s[2]*t+s[5]*n+s[8]*r,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){const t=this.x,n=this.y,r=this.z,s=e.elements,a=1/(s[3]*t+s[7]*n+s[11]*r+s[15]);return this.x=(s[0]*t+s[4]*n+s[8]*r+s[12])*a,this.y=(s[1]*t+s[5]*n+s[9]*r+s[13])*a,this.z=(s[2]*t+s[6]*n+s[10]*r+s[14])*a,this}applyQuaternion(e){const t=this.x,n=this.y,r=this.z,s=e.x,a=e.y,o=e.z,c=e.w,l=2*(a*r-o*n),h=2*(o*t-s*r),d=2*(s*n-a*t);return this.x=t+c*l+a*d-o*h,this.y=n+c*h+o*l-s*d,this.z=r+c*d+s*h-a*l,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){const t=this.x,n=this.y,r=this.z,s=e.elements;return this.x=s[0]*t+s[4]*n+s[8]*r,this.y=s[1]*t+s[5]*n+s[9]*r,this.z=s[2]*t+s[6]*n+s[10]*r,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=He(this.x,e.x,t.x),this.y=He(this.y,e.y,t.y),this.z=He(this.z,e.z,t.z),this}clampScalar(e,t){return this.x=He(this.x,e,t),this.y=He(this.y,e,t),this.z=He(this.z,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(He(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){const n=e.x,r=e.y,s=e.z,a=t.x,o=t.y,c=t.z;return this.x=r*c-s*o,this.y=s*a-n*c,this.z=n*o-r*a,this}projectOnVector(e){const t=e.lengthSq();if(t===0)return this.set(0,0,0);const n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)}projectOnPlane(e){return fr.copy(this).projectOnVector(e),this.sub(fr)}reflect(e){return this.sub(fr.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){const t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;const n=this.dot(e)/t;return Math.acos(He(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y,r=this.z-e.z;return t*t+n*n+r*r}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,n){const r=Math.sin(t)*e;return this.x=r*Math.sin(n),this.y=Math.cos(t)*e,this.z=r*Math.cos(n),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){const t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),r=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=r,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,t*4)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,t*3)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const e=Math.random()*Math.PI*2,t=Math.random()*2-1,n=Math.sqrt(1-t*t);return this.x=n*Math.cos(e),this.y=t,this.z=n*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const fr=new F,oa=new Ai;class Ie{constructor(e,t,n,r,s,a,o,c,l){Ie.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],e!==void 0&&this.set(e,t,n,r,s,a,o,c,l)}set(e,t,n,r,s,a,o,c,l){const h=this.elements;return h[0]=e,h[1]=r,h[2]=o,h[3]=t,h[4]=s,h[5]=c,h[6]=n,h[7]=a,h[8]=l,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this}extractBasis(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(e){const t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,r=t.elements,s=this.elements,a=n[0],o=n[3],c=n[6],l=n[1],h=n[4],d=n[7],f=n[2],m=n[5],_=n[8],x=r[0],p=r[3],u=r[6],b=r[1],A=r[4],E=r[7],D=r[2],R=r[5],w=r[8];return s[0]=a*x+o*b+c*D,s[3]=a*p+o*A+c*R,s[6]=a*u+o*E+c*w,s[1]=l*x+h*b+d*D,s[4]=l*p+h*A+d*R,s[7]=l*u+h*E+d*w,s[2]=f*x+m*b+_*D,s[5]=f*p+m*A+_*R,s[8]=f*u+m*E+_*w,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],c=e[6],l=e[7],h=e[8];return t*a*h-t*o*l-n*s*h+n*o*c+r*s*l-r*a*c}invert(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],c=e[6],l=e[7],h=e[8],d=h*a-o*l,f=o*c-h*s,m=l*s-a*c,_=t*d+n*f+r*m;if(_===0)return this.set(0,0,0,0,0,0,0,0,0);const x=1/_;return e[0]=d*x,e[1]=(r*l-h*n)*x,e[2]=(o*n-r*a)*x,e[3]=f*x,e[4]=(h*t-r*c)*x,e[5]=(r*s-o*t)*x,e[6]=m*x,e[7]=(n*c-l*t)*x,e[8]=(a*t-n*s)*x,this}transpose(){let e;const t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){const t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,n,r,s,a,o){const c=Math.cos(s),l=Math.sin(s);return this.set(n*c,n*l,-n*(c*a+l*o)+a+e,-r*l,r*c,-r*(-l*a+c*o)+o+t,0,0,1),this}scale(e,t){return this.premultiply(pr.makeScale(e,t)),this}rotate(e){return this.premultiply(pr.makeRotation(-e)),this}translate(e,t){return this.premultiply(pr.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,n,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){const t=this.elements,n=e.elements;for(let r=0;r<9;r++)if(t[r]!==n[r])return!1;return!0}fromArray(e,t=0){for(let n=0;n<9;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}clone(){return new this.constructor().fromArray(this.elements)}}const pr=new Ie;function mo(i){for(let e=i.length-1;e>=0;--e)if(i[e]>=65535)return!0;return!1}function Si(i){return document.createElementNS("http://www.w3.org/1999/xhtml",i)}function Cl(){const i=Si("canvas");return i.style.display="block",i}const la={};function Ei(i){i in la||(la[i]=!0,console.warn(i))}function Pl(i,e,t){return new Promise(function(n,r){function s(){switch(i.clientWaitSync(e,i.SYNC_FLUSH_COMMANDS_BIT,0)){case i.WAIT_FAILED:r();break;case i.TIMEOUT_EXPIRED:setTimeout(s,t);break;default:n()}}setTimeout(s,t)})}const ca=new Ie().set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),ua=new Ie().set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function Dl(){const i={enabled:!0,workingColorSpace:ii,spaces:{},convert:function(r,s,a){return this.enabled===!1||s===a||!s||!a||(this.spaces[s].transfer===Ye&&(r.r=rn(r.r),r.g=rn(r.g),r.b=rn(r.b)),this.spaces[s].primaries!==this.spaces[a].primaries&&(r.applyMatrix3(this.spaces[s].toXYZ),r.applyMatrix3(this.spaces[a].fromXYZ)),this.spaces[a].transfer===Ye&&(r.r=Qn(r.r),r.g=Qn(r.g),r.b=Qn(r.b))),r},workingToColorSpace:function(r,s){return this.convert(r,this.workingColorSpace,s)},colorSpaceToWorking:function(r,s){return this.convert(r,s,this.workingColorSpace)},getPrimaries:function(r){return this.spaces[r].primaries},getTransfer:function(r){return r===dn?rr:this.spaces[r].transfer},getToneMappingMode:function(r){return this.spaces[r].outputColorSpaceConfig.toneMappingMode||"standard"},getLuminanceCoefficients:function(r,s=this.workingColorSpace){return r.fromArray(this.spaces[s].luminanceCoefficients)},define:function(r){Object.assign(this.spaces,r)},_getMatrix:function(r,s,a){return r.copy(this.spaces[s].toXYZ).multiply(this.spaces[a].fromXYZ)},_getDrawingBufferColorSpace:function(r){return this.spaces[r].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(r=this.workingColorSpace){return this.spaces[r].workingColorSpaceConfig.unpackColorSpace},fromWorkingColorSpace:function(r,s){return Ei("THREE.ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."),i.workingToColorSpace(r,s)},toWorkingColorSpace:function(r,s){return Ei("THREE.ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."),i.colorSpaceToWorking(r,s)}},e=[.64,.33,.3,.6,.15,.06],t=[.2126,.7152,.0722],n=[.3127,.329];return i.define({[ii]:{primaries:e,whitePoint:n,transfer:rr,toXYZ:ca,fromXYZ:ua,luminanceCoefficients:t,workingColorSpaceConfig:{unpackColorSpace:Lt},outputColorSpaceConfig:{drawingBufferColorSpace:Lt}},[Lt]:{primaries:e,whitePoint:n,transfer:Ye,toXYZ:ca,fromXYZ:ua,luminanceCoefficients:t,outputColorSpaceConfig:{drawingBufferColorSpace:Lt}}}),i}const Ve=Dl();function rn(i){return i<.04045?i*.0773993808:Math.pow(i*.9478672986+.0521327014,2.4)}function Qn(i){return i<.0031308?i*12.92:1.055*Math.pow(i,.41666)-.055}let Fn;class Ll{static getDataURL(e,t="image/png"){if(/^data:/i.test(e.src)||typeof HTMLCanvasElement>"u")return e.src;let n;if(e instanceof HTMLCanvasElement)n=e;else{Fn===void 0&&(Fn=Si("canvas")),Fn.width=e.width,Fn.height=e.height;const r=Fn.getContext("2d");e instanceof ImageData?r.putImageData(e,0,0):r.drawImage(e,0,0,e.width,e.height),n=Fn}return n.toDataURL(t)}static sRGBToLinear(e){if(typeof HTMLImageElement<"u"&&e instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&e instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&e instanceof ImageBitmap){const t=Si("canvas");t.width=e.width,t.height=e.height;const n=t.getContext("2d");n.drawImage(e,0,0,e.width,e.height);const r=n.getImageData(0,0,e.width,e.height),s=r.data;for(let a=0;a1),this.pmremVersion=0}get width(){return this.source.getSize(gr).x}get height(){return this.source.getSize(gr).y}get depth(){return this.source.getSize(gr).z}get image(){return this.source.data}set image(e=null){this.source.data=e}updateMatrix(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}clone(){return new this.constructor().copy(this)}copy(e){return this.name=e.name,this.source=e.source,this.mipmaps=e.mipmaps.slice(0),this.mapping=e.mapping,this.channel=e.channel,this.wrapS=e.wrapS,this.wrapT=e.wrapT,this.magFilter=e.magFilter,this.minFilter=e.minFilter,this.anisotropy=e.anisotropy,this.format=e.format,this.internalFormat=e.internalFormat,this.type=e.type,this.offset.copy(e.offset),this.repeat.copy(e.repeat),this.center.copy(e.center),this.rotation=e.rotation,this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrix.copy(e.matrix),this.generateMipmaps=e.generateMipmaps,this.premultiplyAlpha=e.premultiplyAlpha,this.flipY=e.flipY,this.unpackAlignment=e.unpackAlignment,this.colorSpace=e.colorSpace,this.renderTarget=e.renderTarget,this.isRenderTargetTexture=e.isRenderTargetTexture,this.isArrayTexture=e.isArrayTexture,this.userData=JSON.parse(JSON.stringify(e.userData)),this.needsUpdate=!0,this}setValues(e){for(const t in e){const n=e[t];if(n===void 0){console.warn(`THREE.Texture.setValues(): parameter '${t}' has value of undefined.`);continue}const r=this[t];if(r===void 0){console.warn(`THREE.Texture.setValues(): property '${t}' does not exist.`);continue}r&&n&&r.isVector2&&n.isVector2||r&&n&&r.isVector3&&n.isVector3||r&&n&&r.isMatrix3&&n.isMatrix3?r.copy(n):this[t]=n}}toJSON(e){const t=e===void 0||typeof e=="string";if(!t&&e.textures[this.uuid]!==void 0)return e.textures[this.uuid];const n={metadata:{version:4.7,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,image:this.source.toJSON(e).uuid,mapping:this.mapping,channel:this.channel,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,internalFormat:this.internalFormat,type:this.type,colorSpace:this.colorSpace,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,generateMipmaps:this.generateMipmaps,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};return Object.keys(this.userData).length>0&&(n.userData=this.userData),t||(e.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==io)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case Cn:e.x=e.x-Math.floor(e.x);break;case Pn:e.x=e.x<0?0:1;break;case es:Math.abs(Math.floor(e.x)%2)===1?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x);break}if(e.y<0||e.y>1)switch(this.wrapT){case Cn:e.y=e.y-Math.floor(e.y);break;case Pn:e.y=e.y<0?0:1;break;case es:Math.abs(Math.floor(e.y)%2)===1?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y);break}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){e===!0&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){e===!0&&this.pmremVersion++}}xt.DEFAULT_IMAGE=null;xt.DEFAULT_MAPPING=io;xt.DEFAULT_ANISOTROPY=1;class rt{constructor(e=0,t=0,n=0,r=1){rt.prototype.isVector4=!0,this.x=e,this.y=t,this.z=n,this.w=r}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,n,r){return this.x=e,this.y=t,this.z=n,this.w=r,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w!==void 0?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){const t=this.x,n=this.y,r=this.z,s=this.w,a=e.elements;return this.x=a[0]*t+a[4]*n+a[8]*r+a[12]*s,this.y=a[1]*t+a[5]*n+a[9]*r+a[13]*s,this.z=a[2]*t+a[6]*n+a[10]*r+a[14]*s,this.w=a[3]*t+a[7]*n+a[11]*r+a[15]*s,this}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this.w/=e.w,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);const t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,n,r,s;const c=e.elements,l=c[0],h=c[4],d=c[8],f=c[1],m=c[5],_=c[9],x=c[2],p=c[6],u=c[10];if(Math.abs(h-f)<.01&&Math.abs(d-x)<.01&&Math.abs(_-p)<.01){if(Math.abs(h+f)<.1&&Math.abs(d+x)<.1&&Math.abs(_+p)<.1&&Math.abs(l+m+u-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;const A=(l+1)/2,E=(m+1)/2,D=(u+1)/2,R=(h+f)/4,w=(d+x)/4,U=(_+p)/4;return A>E&&A>D?A<.01?(n=0,r=.707106781,s=.707106781):(n=Math.sqrt(A),r=R/n,s=w/n):E>D?E<.01?(n=.707106781,r=0,s=.707106781):(r=Math.sqrt(E),n=R/r,s=U/r):D<.01?(n=.707106781,r=.707106781,s=0):(s=Math.sqrt(D),n=w/s,r=U/s),this.set(n,r,s,t),this}let b=Math.sqrt((p-_)*(p-_)+(d-x)*(d-x)+(f-h)*(f-h));return Math.abs(b)<.001&&(b=1),this.x=(p-_)/b,this.y=(d-x)/b,this.z=(f-h)/b,this.w=Math.acos((l+m+u-1)/2),this}setFromMatrixPosition(e){const t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this.w=t[15],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this}clamp(e,t){return this.x=He(this.x,e.x,t.x),this.y=He(this.y,e.y,t.y),this.z=He(this.z,e.z,t.z),this.w=He(this.w,e.w,t.w),this}clampScalar(e,t){return this.x=He(this.x,e,t),this.y=He(this.y,e,t),this.z=He(this.z,e,t),this.w=He(this.w,e,t),this}clampLength(e,t){const n=this.length();return this.divideScalar(n||1).multiplyScalar(He(n,e,t))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this.w=Math.trunc(this.w),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)}normalize(){return this.divideScalar(this.length()||1)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this.w=e.w+(t.w-e.w)*n,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this.w=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z,yield this.w}}class Nl extends si{constructor(e=1,t=1,n={}){super(),n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:Ut,depthBuffer:!0,stencilBuffer:!1,resolveDepthBuffer:!0,resolveStencilBuffer:!0,depthTexture:null,samples:0,count:1,depth:1,multiview:!1},n),this.isRenderTarget=!0,this.width=e,this.height=t,this.depth=n.depth,this.scissor=new rt(0,0,e,t),this.scissorTest=!1,this.viewport=new rt(0,0,e,t);const r={width:e,height:t,depth:n.depth},s=new xt(r);this.textures=[];const a=n.count;for(let o=0;o1;this.dispose()}this.viewport.set(0,0,e,t),this.scissor.set(0,0,e,t)}clone(){return new this.constructor().copy(this)}copy(e){this.width=e.width,this.height=e.height,this.depth=e.depth,this.scissor.copy(e.scissor),this.scissorTest=e.scissorTest,this.viewport.copy(e.viewport),this.textures.length=0;for(let t=0,n=e.textures.length;t=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}intersectsSphere(e){return this.clampPoint(e.center,Nt),Nt.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(ui),Ii.subVectors(this.max,ui),On.subVectors(e.a,ui),Bn.subVectors(e.b,ui),Hn.subVectors(e.c,ui),an.subVectors(Bn,On),on.subVectors(Hn,Bn),xn.subVectors(On,Hn);let t=[0,-an.z,an.y,0,-on.z,on.y,0,-xn.z,xn.y,an.z,0,-an.x,on.z,0,-on.x,xn.z,0,-xn.x,-an.y,an.x,0,-on.y,on.x,0,-xn.y,xn.x,0];return!_r(t,On,Bn,Hn,Ii)||(t=[1,0,0,0,1,0,0,0,1],!_r(t,On,Bn,Hn,Ii))?!1:(Ui.crossVectors(an,on),t=[Ui.x,Ui.y,Ui.z],_r(t,On,Bn,Hn,Ii))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,Nt).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=this.getSize(Nt).length()*.5),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()?this:(Kt[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),Kt[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),Kt[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),Kt[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),Kt[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),Kt[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),Kt[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),Kt[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints(Kt),this)}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}toJSON(){return{min:this.min.toArray(),max:this.max.toArray()}}fromJSON(e){return this.min.fromArray(e.min),this.max.fromArray(e.max),this}}const Kt=[new F,new F,new F,new F,new F,new F,new F,new F],Nt=new F,Li=new bi,On=new F,Bn=new F,Hn=new F,an=new F,on=new F,xn=new F,ui=new F,Ii=new F,Ui=new F,Mn=new F;function _r(i,e,t,n,r){for(let s=0,a=i.length-3;s<=a;s+=3){Mn.fromArray(i,s);const o=r.x*Math.abs(Mn.x)+r.y*Math.abs(Mn.y)+r.z*Math.abs(Mn.z),c=e.dot(Mn),l=t.dot(Mn),h=n.dot(Mn);if(Math.max(-Math.max(c,l,h),Math.min(c,l,h))>o)return!1}return!0}const Ol=new bi,hi=new F,vr=new F;class zs{constructor(e=new F,t=-1){this.isSphere=!0,this.center=e,this.radius=t}set(e,t){return this.center.copy(e),this.radius=t,this}setFromPoints(e,t){const n=this.center;t!==void 0?n.copy(t):Ol.setFromPoints(e).getCenter(n);let r=0;for(let s=0,a=e.length;sthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;hi.subVectors(e,this.center);const t=hi.lengthSq();if(t>this.radius*this.radius){const n=Math.sqrt(t),r=(n-this.radius)*.5;this.center.addScaledVector(hi,r/n),this.radius+=r}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(this.center.equals(e.center)===!0?this.radius=Math.max(this.radius,e.radius):(vr.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(hi.copy(e.center).add(vr)),this.expandByPoint(hi.copy(e.center).sub(vr))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return new this.constructor().copy(this)}toJSON(){return{radius:this.radius,center:this.center.toArray()}}fromJSON(e){return this.radius=e.radius,this.center.fromArray(e.center),this}}const Zt=new F,xr=new F,Ni=new F,ln=new F,Mr=new F,Fi=new F,Sr=new F;class _o{constructor(e=new F,t=new F(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,Zt)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);const n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){const t=Zt.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Zt.copy(this.origin).addScaledVector(this.direction,t),Zt.distanceToSquared(e))}distanceSqToSegment(e,t,n,r){xr.copy(e).add(t).multiplyScalar(.5),Ni.copy(t).sub(e).normalize(),ln.copy(this.origin).sub(xr);const s=e.distanceTo(t)*.5,a=-this.direction.dot(Ni),o=ln.dot(this.direction),c=-ln.dot(Ni),l=ln.lengthSq(),h=Math.abs(1-a*a);let d,f,m,_;if(h>0)if(d=a*c-o,f=a*o-c,_=s*h,d>=0)if(f>=-_)if(f<=_){const x=1/h;d*=x,f*=x,m=d*(d+a*f+2*o)+f*(a*d+f+2*c)+l}else f=s,d=Math.max(0,-(a*f+o)),m=-d*d+f*(f+2*c)+l;else f=-s,d=Math.max(0,-(a*f+o)),m=-d*d+f*(f+2*c)+l;else f<=-_?(d=Math.max(0,-(-a*s+o)),f=d>0?-s:Math.min(Math.max(-s,-c),s),m=-d*d+f*(f+2*c)+l):f<=_?(d=0,f=Math.min(Math.max(-s,-c),s),m=f*(f+2*c)+l):(d=Math.max(0,-(a*s+o)),f=d>0?s:Math.min(Math.max(-s,-c),s),m=-d*d+f*(f+2*c)+l);else f=a>0?-s:s,d=Math.max(0,-(a*f+o)),m=-d*d+f*(f+2*c)+l;return n&&n.copy(this.origin).addScaledVector(this.direction,d),r&&r.copy(xr).addScaledVector(Ni,f),m}intersectSphere(e,t){Zt.subVectors(e.center,this.origin);const n=Zt.dot(this.direction),r=Zt.dot(Zt)-n*n,s=e.radius*e.radius;if(r>s)return null;const a=Math.sqrt(s-r),o=n-a,c=n+a;return c<0?null:o<0?this.at(c,t):this.at(o,t)}intersectsSphere(e){return e.radius<0?!1:this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){const t=e.normal.dot(this.direction);if(t===0)return e.distanceToPoint(this.origin)===0?0:null;const n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null}intersectPlane(e,t){const n=this.distanceToPlane(e);return n===null?null:this.at(n,t)}intersectsPlane(e){const t=e.distanceToPoint(this.origin);return t===0||e.normal.dot(this.direction)*t<0}intersectBox(e,t){let n,r,s,a,o,c;const l=1/this.direction.x,h=1/this.direction.y,d=1/this.direction.z,f=this.origin;return l>=0?(n=(e.min.x-f.x)*l,r=(e.max.x-f.x)*l):(n=(e.max.x-f.x)*l,r=(e.min.x-f.x)*l),h>=0?(s=(e.min.y-f.y)*h,a=(e.max.y-f.y)*h):(s=(e.max.y-f.y)*h,a=(e.min.y-f.y)*h),n>a||s>r||((s>n||isNaN(n))&&(n=s),(a=0?(o=(e.min.z-f.z)*d,c=(e.max.z-f.z)*d):(o=(e.max.z-f.z)*d,c=(e.min.z-f.z)*d),n>c||o>r)||((o>n||n!==n)&&(n=o),(c=0?n:r,t)}intersectsBox(e){return this.intersectBox(e,Zt)!==null}intersectTriangle(e,t,n,r,s){Mr.subVectors(t,e),Fi.subVectors(n,e),Sr.crossVectors(Mr,Fi);let a=this.direction.dot(Sr),o;if(a>0){if(r)return null;o=1}else if(a<0)o=-1,a=-a;else return null;ln.subVectors(this.origin,e);const c=o*this.direction.dot(Fi.crossVectors(ln,Fi));if(c<0)return null;const l=o*this.direction.dot(Mr.cross(ln));if(l<0||c+l>a)return null;const h=-o*ln.dot(Sr);return h<0?null:this.at(h/a,s)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}}class st{constructor(e,t,n,r,s,a,o,c,l,h,d,f,m,_,x,p){st.prototype.isMatrix4=!0,this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],e!==void 0&&this.set(e,t,n,r,s,a,o,c,l,h,d,f,m,_,x,p)}set(e,t,n,r,s,a,o,c,l,h,d,f,m,_,x,p){const u=this.elements;return u[0]=e,u[4]=t,u[8]=n,u[12]=r,u[1]=s,u[5]=a,u[9]=o,u[13]=c,u[2]=l,u[6]=h,u[10]=d,u[14]=f,u[3]=m,u[7]=_,u[11]=x,u[15]=p,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return new st().fromArray(this.elements)}copy(e){const t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],this}copyPosition(e){const t=this.elements,n=e.elements;return t[12]=n[12],t[13]=n[13],t[14]=n[14],this}setFromMatrix3(e){const t=e.elements;return this.set(t[0],t[3],t[6],0,t[1],t[4],t[7],0,t[2],t[5],t[8],0,0,0,0,1),this}extractBasis(e,t,n){return e.setFromMatrixColumn(this,0),t.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(e,t,n){return this.set(e.x,t.x,n.x,0,e.y,t.y,n.y,0,e.z,t.z,n.z,0,0,0,0,1),this}extractRotation(e){const t=this.elements,n=e.elements,r=1/zn.setFromMatrixColumn(e,0).length(),s=1/zn.setFromMatrixColumn(e,1).length(),a=1/zn.setFromMatrixColumn(e,2).length();return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=0,t[4]=n[4]*s,t[5]=n[5]*s,t[6]=n[6]*s,t[7]=0,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromEuler(e){const t=this.elements,n=e.x,r=e.y,s=e.z,a=Math.cos(n),o=Math.sin(n),c=Math.cos(r),l=Math.sin(r),h=Math.cos(s),d=Math.sin(s);if(e.order==="XYZ"){const f=a*h,m=a*d,_=o*h,x=o*d;t[0]=c*h,t[4]=-c*d,t[8]=l,t[1]=m+_*l,t[5]=f-x*l,t[9]=-o*c,t[2]=x-f*l,t[6]=_+m*l,t[10]=a*c}else if(e.order==="YXZ"){const f=c*h,m=c*d,_=l*h,x=l*d;t[0]=f+x*o,t[4]=_*o-m,t[8]=a*l,t[1]=a*d,t[5]=a*h,t[9]=-o,t[2]=m*o-_,t[6]=x+f*o,t[10]=a*c}else if(e.order==="ZXY"){const f=c*h,m=c*d,_=l*h,x=l*d;t[0]=f-x*o,t[4]=-a*d,t[8]=_+m*o,t[1]=m+_*o,t[5]=a*h,t[9]=x-f*o,t[2]=-a*l,t[6]=o,t[10]=a*c}else if(e.order==="ZYX"){const f=a*h,m=a*d,_=o*h,x=o*d;t[0]=c*h,t[4]=_*l-m,t[8]=f*l+x,t[1]=c*d,t[5]=x*l+f,t[9]=m*l-_,t[2]=-l,t[6]=o*c,t[10]=a*c}else if(e.order==="YZX"){const f=a*c,m=a*l,_=o*c,x=o*l;t[0]=c*h,t[4]=x-f*d,t[8]=_*d+m,t[1]=d,t[5]=a*h,t[9]=-o*h,t[2]=-l*h,t[6]=m*d+_,t[10]=f-x*d}else if(e.order==="XZY"){const f=a*c,m=a*l,_=o*c,x=o*l;t[0]=c*h,t[4]=-d,t[8]=l*h,t[1]=f*d+x,t[5]=a*h,t[9]=m*d-_,t[2]=_*d-m,t[6]=o*h,t[10]=x*d+f}return t[3]=0,t[7]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,this}makeRotationFromQuaternion(e){return this.compose(Bl,e,Hl)}lookAt(e,t,n){const r=this.elements;return At.subVectors(e,t),At.lengthSq()===0&&(At.z=1),At.normalize(),cn.crossVectors(n,At),cn.lengthSq()===0&&(Math.abs(n.z)===1?At.x+=1e-4:At.z+=1e-4,At.normalize(),cn.crossVectors(n,At)),cn.normalize(),Oi.crossVectors(At,cn),r[0]=cn.x,r[4]=Oi.x,r[8]=At.x,r[1]=cn.y,r[5]=Oi.y,r[9]=At.y,r[2]=cn.z,r[6]=Oi.z,r[10]=At.z,this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){const n=e.elements,r=t.elements,s=this.elements,a=n[0],o=n[4],c=n[8],l=n[12],h=n[1],d=n[5],f=n[9],m=n[13],_=n[2],x=n[6],p=n[10],u=n[14],b=n[3],A=n[7],E=n[11],D=n[15],R=r[0],w=r[4],U=r[8],S=r[12],M=r[1],C=r[5],O=r[9],z=r[13],q=r[2],W=r[6],X=r[10],Z=r[14],G=r[3],se=r[7],ce=r[11],Ee=r[15];return s[0]=a*R+o*M+c*q+l*G,s[4]=a*w+o*C+c*W+l*se,s[8]=a*U+o*O+c*X+l*ce,s[12]=a*S+o*z+c*Z+l*Ee,s[1]=h*R+d*M+f*q+m*G,s[5]=h*w+d*C+f*W+m*se,s[9]=h*U+d*O+f*X+m*ce,s[13]=h*S+d*z+f*Z+m*Ee,s[2]=_*R+x*M+p*q+u*G,s[6]=_*w+x*C+p*W+u*se,s[10]=_*U+x*O+p*X+u*ce,s[14]=_*S+x*z+p*Z+u*Ee,s[3]=b*R+A*M+E*q+D*G,s[7]=b*w+A*C+E*W+D*se,s[11]=b*U+A*O+E*X+D*ce,s[15]=b*S+A*z+E*Z+D*Ee,this}multiplyScalar(e){const t=this.elements;return t[0]*=e,t[4]*=e,t[8]*=e,t[12]*=e,t[1]*=e,t[5]*=e,t[9]*=e,t[13]*=e,t[2]*=e,t[6]*=e,t[10]*=e,t[14]*=e,t[3]*=e,t[7]*=e,t[11]*=e,t[15]*=e,this}determinant(){const e=this.elements,t=e[0],n=e[4],r=e[8],s=e[12],a=e[1],o=e[5],c=e[9],l=e[13],h=e[2],d=e[6],f=e[10],m=e[14],_=e[3],x=e[7],p=e[11],u=e[15];return _*(+s*c*d-r*l*d-s*o*f+n*l*f+r*o*m-n*c*m)+x*(+t*c*m-t*l*f+s*a*f-r*a*m+r*l*h-s*c*h)+p*(+t*l*d-t*o*m-s*a*d+n*a*m+s*o*h-n*l*h)+u*(-r*o*h-t*c*d+t*o*f+r*a*d-n*a*f+n*c*h)}transpose(){const e=this.elements;let t;return t=e[1],e[1]=e[4],e[4]=t,t=e[2],e[2]=e[8],e[8]=t,t=e[6],e[6]=e[9],e[9]=t,t=e[3],e[3]=e[12],e[12]=t,t=e[7],e[7]=e[13],e[13]=t,t=e[11],e[11]=e[14],e[14]=t,this}setPosition(e,t,n){const r=this.elements;return e.isVector3?(r[12]=e.x,r[13]=e.y,r[14]=e.z):(r[12]=e,r[13]=t,r[14]=n),this}invert(){const e=this.elements,t=e[0],n=e[1],r=e[2],s=e[3],a=e[4],o=e[5],c=e[6],l=e[7],h=e[8],d=e[9],f=e[10],m=e[11],_=e[12],x=e[13],p=e[14],u=e[15],b=d*p*l-x*f*l+x*c*m-o*p*m-d*c*u+o*f*u,A=_*f*l-h*p*l-_*c*m+a*p*m+h*c*u-a*f*u,E=h*x*l-_*d*l+_*o*m-a*x*m-h*o*u+a*d*u,D=_*d*c-h*x*c-_*o*f+a*x*f+h*o*p-a*d*p,R=t*b+n*A+r*E+s*D;if(R===0)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const w=1/R;return e[0]=b*w,e[1]=(x*f*s-d*p*s-x*r*m+n*p*m+d*r*u-n*f*u)*w,e[2]=(o*p*s-x*c*s+x*r*l-n*p*l-o*r*u+n*c*u)*w,e[3]=(d*c*s-o*f*s-d*r*l+n*f*l+o*r*m-n*c*m)*w,e[4]=A*w,e[5]=(h*p*s-_*f*s+_*r*m-t*p*m-h*r*u+t*f*u)*w,e[6]=(_*c*s-a*p*s-_*r*l+t*p*l+a*r*u-t*c*u)*w,e[7]=(a*f*s-h*c*s+h*r*l-t*f*l-a*r*m+t*c*m)*w,e[8]=E*w,e[9]=(_*d*s-h*x*s-_*n*m+t*x*m+h*n*u-t*d*u)*w,e[10]=(a*x*s-_*o*s+_*n*l-t*x*l-a*n*u+t*o*u)*w,e[11]=(h*o*s-a*d*s-h*n*l+t*d*l+a*n*m-t*o*m)*w,e[12]=D*w,e[13]=(h*x*r-_*d*r+_*n*f-t*x*f-h*n*p+t*d*p)*w,e[14]=(_*o*r-a*x*r-_*n*c+t*x*c+a*n*p-t*o*p)*w,e[15]=(a*d*r-h*o*r+h*n*c-t*d*c-a*n*f+t*o*f)*w,this}scale(e){const t=this.elements,n=e.x,r=e.y,s=e.z;return t[0]*=n,t[4]*=r,t[8]*=s,t[1]*=n,t[5]*=r,t[9]*=s,t[2]*=n,t[6]*=r,t[10]*=s,t[3]*=n,t[7]*=r,t[11]*=s,this}getMaxScaleOnAxis(){const e=this.elements,t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2],n=e[4]*e[4]+e[5]*e[5]+e[6]*e[6],r=e[8]*e[8]+e[9]*e[9]+e[10]*e[10];return Math.sqrt(Math.max(t,n,r))}makeTranslation(e,t,n){return e.isVector3?this.set(1,0,0,e.x,0,1,0,e.y,0,0,1,e.z,0,0,0,1):this.set(1,0,0,e,0,1,0,t,0,0,1,n,0,0,0,1),this}makeRotationX(e){const t=Math.cos(e),n=Math.sin(e);return this.set(1,0,0,0,0,t,-n,0,0,n,t,0,0,0,0,1),this}makeRotationY(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,0,n,0,0,1,0,0,-n,0,t,0,0,0,0,1),this}makeRotationZ(e){const t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,0,n,t,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(e,t){const n=Math.cos(t),r=Math.sin(t),s=1-n,a=e.x,o=e.y,c=e.z,l=s*a,h=s*o;return this.set(l*a+n,l*o-r*c,l*c+r*o,0,l*o+r*c,h*o+n,h*c-r*a,0,l*c-r*o,h*c+r*a,s*c*c+n,0,0,0,0,1),this}makeScale(e,t,n){return this.set(e,0,0,0,0,t,0,0,0,0,n,0,0,0,0,1),this}makeShear(e,t,n,r,s,a){return this.set(1,n,s,0,e,1,a,0,t,r,1,0,0,0,0,1),this}compose(e,t,n){const r=this.elements,s=t._x,a=t._y,o=t._z,c=t._w,l=s+s,h=a+a,d=o+o,f=s*l,m=s*h,_=s*d,x=a*h,p=a*d,u=o*d,b=c*l,A=c*h,E=c*d,D=n.x,R=n.y,w=n.z;return r[0]=(1-(x+u))*D,r[1]=(m+E)*D,r[2]=(_-A)*D,r[3]=0,r[4]=(m-E)*R,r[5]=(1-(f+u))*R,r[6]=(p+b)*R,r[7]=0,r[8]=(_+A)*w,r[9]=(p-b)*w,r[10]=(1-(f+x))*w,r[11]=0,r[12]=e.x,r[13]=e.y,r[14]=e.z,r[15]=1,this}decompose(e,t,n){const r=this.elements;let s=zn.set(r[0],r[1],r[2]).length();const a=zn.set(r[4],r[5],r[6]).length(),o=zn.set(r[8],r[9],r[10]).length();this.determinant()<0&&(s=-s),e.x=r[12],e.y=r[13],e.z=r[14],Ft.copy(this);const l=1/s,h=1/a,d=1/o;return Ft.elements[0]*=l,Ft.elements[1]*=l,Ft.elements[2]*=l,Ft.elements[4]*=h,Ft.elements[5]*=h,Ft.elements[6]*=h,Ft.elements[8]*=d,Ft.elements[9]*=d,Ft.elements[10]*=d,t.setFromRotationMatrix(Ft),n.x=s,n.y=a,n.z=o,this}makePerspective(e,t,n,r,s,a,o=Wt,c=!1){const l=this.elements,h=2*s/(t-e),d=2*s/(n-r),f=(t+e)/(t-e),m=(n+r)/(n-r);let _,x;if(c)_=s/(a-s),x=a*s/(a-s);else if(o===Wt)_=-(a+s)/(a-s),x=-2*a*s/(a-s);else if(o===sr)_=-a/(a-s),x=-a*s/(a-s);else throw new Error("THREE.Matrix4.makePerspective(): Invalid coordinate system: "+o);return l[0]=h,l[4]=0,l[8]=f,l[12]=0,l[1]=0,l[5]=d,l[9]=m,l[13]=0,l[2]=0,l[6]=0,l[10]=_,l[14]=x,l[3]=0,l[7]=0,l[11]=-1,l[15]=0,this}makeOrthographic(e,t,n,r,s,a,o=Wt,c=!1){const l=this.elements,h=2/(t-e),d=2/(n-r),f=-(t+e)/(t-e),m=-(n+r)/(n-r);let _,x;if(c)_=1/(a-s),x=a/(a-s);else if(o===Wt)_=-2/(a-s),x=-(a+s)/(a-s);else if(o===sr)_=-1/(a-s),x=-s/(a-s);else throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);return l[0]=h,l[4]=0,l[8]=0,l[12]=f,l[1]=0,l[5]=d,l[9]=0,l[13]=m,l[2]=0,l[6]=0,l[10]=_,l[14]=x,l[3]=0,l[7]=0,l[11]=0,l[15]=1,this}equals(e){const t=this.elements,n=e.elements;for(let r=0;r<16;r++)if(t[r]!==n[r])return!1;return!0}fromArray(e,t=0){for(let n=0;n<16;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){const n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e[t+9]=n[9],e[t+10]=n[10],e[t+11]=n[11],e[t+12]=n[12],e[t+13]=n[13],e[t+14]=n[14],e[t+15]=n[15],e}}const zn=new F,Ft=new st,Bl=new F(0,0,0),Hl=new F(1,1,1),cn=new F,Oi=new F,At=new F,ha=new st,da=new Ai;class Yt{constructor(e=0,t=0,n=0,r=Yt.DEFAULT_ORDER){this.isEuler=!0,this._x=e,this._y=t,this._z=n,this._order=r}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get order(){return this._order}set order(e){this._order=e,this._onChangeCallback()}set(e,t,n,r=this._order){return this._x=e,this._y=t,this._z=n,this._order=r,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(e){return this._x=e._x,this._y=e._y,this._z=e._z,this._order=e._order,this._onChangeCallback(),this}setFromRotationMatrix(e,t=this._order,n=!0){const r=e.elements,s=r[0],a=r[4],o=r[8],c=r[1],l=r[5],h=r[9],d=r[2],f=r[6],m=r[10];switch(t){case"XYZ":this._y=Math.asin(He(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-h,m),this._z=Math.atan2(-a,s)):(this._x=Math.atan2(f,l),this._z=0);break;case"YXZ":this._x=Math.asin(-He(h,-1,1)),Math.abs(h)<.9999999?(this._y=Math.atan2(o,m),this._z=Math.atan2(c,l)):(this._y=Math.atan2(-d,s),this._z=0);break;case"ZXY":this._x=Math.asin(He(f,-1,1)),Math.abs(f)<.9999999?(this._y=Math.atan2(-d,m),this._z=Math.atan2(-a,l)):(this._y=0,this._z=Math.atan2(c,s));break;case"ZYX":this._y=Math.asin(-He(d,-1,1)),Math.abs(d)<.9999999?(this._x=Math.atan2(f,m),this._z=Math.atan2(c,s)):(this._x=0,this._z=Math.atan2(-a,l));break;case"YZX":this._z=Math.asin(He(c,-1,1)),Math.abs(c)<.9999999?(this._x=Math.atan2(-h,l),this._y=Math.atan2(-d,s)):(this._x=0,this._y=Math.atan2(o,m));break;case"XZY":this._z=Math.asin(-He(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(f,l),this._y=Math.atan2(o,s)):(this._x=Math.atan2(-h,m),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+t)}return this._order=t,n===!0&&this._onChangeCallback(),this}setFromQuaternion(e,t,n){return ha.makeRotationFromQuaternion(e),this.setFromRotationMatrix(ha,t,n)}setFromVector3(e,t=this._order){return this.set(e.x,e.y,e.z,t)}reorder(e){return da.setFromEuler(this),this.setFromQuaternion(da,e)}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._order===this._order}fromArray(e){return this._x=e[0],this._y=e[1],this._z=e[2],e[3]!==void 0&&(this._order=e[3]),this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._order,e}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._order}}Yt.DEFAULT_ORDER="XYZ";class Gs{constructor(){this.mask=1}set(e){this.mask=(1<>>0}enable(e){this.mask|=1<1){for(let t=0;t1){for(let n=0;n0&&(r.userData=this.userData),r.layers=this.layers.mask,r.matrix=this.matrix.toArray(),r.up=this.up.toArray(),this.matrixAutoUpdate===!1&&(r.matrixAutoUpdate=!1),this.isInstancedMesh&&(r.type="InstancedMesh",r.count=this.count,r.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(r.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(r.type="BatchedMesh",r.perObjectFrustumCulled=this.perObjectFrustumCulled,r.sortObjects=this.sortObjects,r.drawRanges=this._drawRanges,r.reservedRanges=this._reservedRanges,r.geometryInfo=this._geometryInfo.map(o=>({...o,boundingBox:o.boundingBox?o.boundingBox.toJSON():void 0,boundingSphere:o.boundingSphere?o.boundingSphere.toJSON():void 0})),r.instanceInfo=this._instanceInfo.map(o=>({...o})),r.availableInstanceIds=this._availableInstanceIds.slice(),r.availableGeometryIds=this._availableGeometryIds.slice(),r.nextIndexStart=this._nextIndexStart,r.nextVertexStart=this._nextVertexStart,r.geometryCount=this._geometryCount,r.maxInstanceCount=this._maxInstanceCount,r.maxVertexCount=this._maxVertexCount,r.maxIndexCount=this._maxIndexCount,r.geometryInitialized=this._geometryInitialized,r.matricesTexture=this._matricesTexture.toJSON(e),r.indirectTexture=this._indirectTexture.toJSON(e),this._colorsTexture!==null&&(r.colorsTexture=this._colorsTexture.toJSON(e)),this.boundingSphere!==null&&(r.boundingSphere=this.boundingSphere.toJSON()),this.boundingBox!==null&&(r.boundingBox=this.boundingBox.toJSON()));function s(o,c){return o[c.uuid]===void 0&&(o[c.uuid]=c.toJSON(e)),c.uuid}if(this.isScene)this.background&&(this.background.isColor?r.background=this.background.toJSON():this.background.isTexture&&(r.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(r.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){r.geometry=s(e.geometries,this.geometry);const o=this.geometry.parameters;if(o!==void 0&&o.shapes!==void 0){const c=o.shapes;if(Array.isArray(c))for(let l=0,h=c.length;l0){r.children=[];for(let o=0;o0){r.animations=[];for(let o=0;o0&&(n.geometries=o),c.length>0&&(n.materials=c),l.length>0&&(n.textures=l),h.length>0&&(n.images=h),d.length>0&&(n.shapes=d),f.length>0&&(n.skeletons=f),m.length>0&&(n.animations=m),_.length>0&&(n.nodes=_)}return n.object=r,n;function a(o){const c=[];for(const l in o){const h=o[l];delete h.metadata,c.push(h)}return c}}clone(e){return new this.constructor().copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),t===!0)for(let n=0;n0?r.multiplyScalar(1/Math.sqrt(s)):r.set(0,0,0)}static getBarycoord(e,t,n,r,s){Ot.subVectors(r,t),Jt.subVectors(n,t),yr.subVectors(e,t);const a=Ot.dot(Ot),o=Ot.dot(Jt),c=Ot.dot(yr),l=Jt.dot(Jt),h=Jt.dot(yr),d=a*l-o*o;if(d===0)return s.set(0,0,0),null;const f=1/d,m=(l*c-o*h)*f,_=(a*h-o*c)*f;return s.set(1-m-_,_,m)}static containsPoint(e,t,n,r){return this.getBarycoord(e,t,n,r,Qt)===null?!1:Qt.x>=0&&Qt.y>=0&&Qt.x+Qt.y<=1}static getInterpolation(e,t,n,r,s,a,o,c){return this.getBarycoord(e,t,n,r,Qt)===null?(c.x=0,c.y=0,"z"in c&&(c.z=0),"w"in c&&(c.w=0),null):(c.setScalar(0),c.addScaledVector(s,Qt.x),c.addScaledVector(a,Qt.y),c.addScaledVector(o,Qt.z),c)}static getInterpolatedAttribute(e,t,n,r,s,a){return wr.setScalar(0),Rr.setScalar(0),Cr.setScalar(0),wr.fromBufferAttribute(e,t),Rr.fromBufferAttribute(e,n),Cr.fromBufferAttribute(e,r),a.setScalar(0),a.addScaledVector(wr,s.x),a.addScaledVector(Rr,s.y),a.addScaledVector(Cr,s.z),a}static isFrontFacing(e,t,n,r){return Ot.subVectors(n,t),Jt.subVectors(e,t),Ot.cross(Jt).dot(r)<0}set(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this}setFromPointsAndIndices(e,t,n,r){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[r]),this}setFromAttributeAndIndices(e,t,n,r){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,n),this.c.fromBufferAttribute(e,r),this}clone(){return new this.constructor().copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return Ot.subVectors(this.c,this.b),Jt.subVectors(this.a,this.b),Ot.cross(Jt).length()*.5}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return Ht.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return Ht.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,n,r,s){return Ht.getInterpolation(e,this.a,this.b,this.c,t,n,r,s)}containsPoint(e){return Ht.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return Ht.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){const n=this.a,r=this.b,s=this.c;let a,o;Vn.subVectors(r,n),Wn.subVectors(s,n),Tr.subVectors(e,n);const c=Vn.dot(Tr),l=Wn.dot(Tr);if(c<=0&&l<=0)return t.copy(n);Ar.subVectors(e,r);const h=Vn.dot(Ar),d=Wn.dot(Ar);if(h>=0&&d<=h)return t.copy(r);const f=c*d-h*l;if(f<=0&&c>=0&&h<=0)return a=c/(c-h),t.copy(n).addScaledVector(Vn,a);br.subVectors(e,s);const m=Vn.dot(br),_=Wn.dot(br);if(_>=0&&m<=_)return t.copy(s);const x=m*l-c*_;if(x<=0&&l>=0&&_<=0)return o=l/(l-_),t.copy(n).addScaledVector(Wn,o);const p=h*_-m*d;if(p<=0&&d-h>=0&&m-_>=0)return va.subVectors(s,r),o=(d-h)/(d-h+(m-_)),t.copy(r).addScaledVector(va,o);const u=1/(p+x+f);return a=x*u,o=f*u,t.copy(n).addScaledVector(Vn,a).addScaledVector(Wn,o)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}}const vo={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},un={h:0,s:0,l:0},Hi={h:0,s:0,l:0};function Pr(i,e,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?i+(e-i)*6*t:t<1/2?e:t<2/3?i+(e-i)*6*(2/3-t):i}class Oe{constructor(e,t,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,n)}set(e,t,n){if(t===void 0&&n===void 0){const r=e;r&&r.isColor?this.copy(r):typeof r=="number"?this.setHex(r):typeof r=="string"&&this.setStyle(r)}else this.setRGB(e,t,n);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=Lt){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(e&255)/255,Ve.colorSpaceToWorking(this,t),this}setRGB(e,t,n,r=Ve.workingColorSpace){return this.r=e,this.g=t,this.b=n,Ve.colorSpaceToWorking(this,r),this}setHSL(e,t,n,r=Ve.workingColorSpace){if(e=Rl(e,1),t=He(t,0,1),n=He(n,0,1),t===0)this.r=this.g=this.b=n;else{const s=n<=.5?n*(1+t):n+t-n*t,a=2*n-s;this.r=Pr(a,s,e+1/3),this.g=Pr(a,s,e),this.b=Pr(a,s,e-1/3)}return Ve.colorSpaceToWorking(this,r),this}setStyle(e,t=Lt){function n(s){s!==void 0&&parseFloat(s)<1&&console.warn("THREE.Color: Alpha component of "+e+" will be ignored.")}let r;if(r=/^(\w+)\(([^\)]*)\)/.exec(e)){let s;const a=r[1],o=r[2];switch(a){case"rgb":case"rgba":if(s=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setRGB(Math.min(255,parseInt(s[1],10))/255,Math.min(255,parseInt(s[2],10))/255,Math.min(255,parseInt(s[3],10))/255,t);if(s=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setRGB(Math.min(100,parseInt(s[1],10))/100,Math.min(100,parseInt(s[2],10))/100,Math.min(100,parseInt(s[3],10))/100,t);break;case"hsl":case"hsla":if(s=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(s[4]),this.setHSL(parseFloat(s[1])/360,parseFloat(s[2])/100,parseFloat(s[3])/100,t);break;default:console.warn("THREE.Color: Unknown color model "+e)}}else if(r=/^\#([A-Fa-f\d]+)$/.exec(e)){const s=r[1],a=s.length;if(a===3)return this.setRGB(parseInt(s.charAt(0),16)/15,parseInt(s.charAt(1),16)/15,parseInt(s.charAt(2),16)/15,t);if(a===6)return this.setHex(parseInt(s,16),t);console.warn("THREE.Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=Lt){const n=vo[e.toLowerCase()];return n!==void 0?this.setHex(n,t):console.warn("THREE.Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=rn(e.r),this.g=rn(e.g),this.b=rn(e.b),this}copyLinearToSRGB(e){return this.r=Qn(e.r),this.g=Qn(e.g),this.b=Qn(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=Lt){return Ve.workingToColorSpace(mt.copy(this),e),Math.round(He(mt.r*255,0,255))*65536+Math.round(He(mt.g*255,0,255))*256+Math.round(He(mt.b*255,0,255))}getHexString(e=Lt){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=Ve.workingColorSpace){Ve.workingToColorSpace(mt.copy(this),t);const n=mt.r,r=mt.g,s=mt.b,a=Math.max(n,r,s),o=Math.min(n,r,s);let c,l;const h=(o+a)/2;if(o===a)c=0,l=0;else{const d=a-o;switch(l=h<=.5?d/(a+o):d/(2-a-o),a){case n:c=(r-s)/d+(r0!=e>0&&this.version++,this._alphaTest=e}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(e!==void 0)for(const t in e){const n=e[t];if(n===void 0){console.warn(`THREE.Material: parameter '${t}' has value of undefined.`);continue}const r=this[t];if(r===void 0){console.warn(`THREE.Material: '${t}' is not a property of THREE.${this.type}.`);continue}r&&r.isColor?r.set(n):r&&r.isVector3&&n&&n.isVector3?r.copy(n):this[t]=n}}toJSON(e){const t=e===void 0||typeof e=="string";t&&(e={textures:{},images:{}});const n={metadata:{version:4.7,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,this.name!==""&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),this.roughness!==void 0&&(n.roughness=this.roughness),this.metalness!==void 0&&(n.metalness=this.metalness),this.sheen!==void 0&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),this.sheenRoughness!==void 0&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity!==void 0&&this.emissiveIntensity!==1&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),this.specularIntensity!==void 0&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),this.shininess!==void 0&&(n.shininess=this.shininess),this.clearcoat!==void 0&&(n.clearcoat=this.clearcoat),this.clearcoatRoughness!==void 0&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.sheenColorMap&&this.sheenColorMap.isTexture&&(n.sheenColorMap=this.sheenColorMap.toJSON(e).uuid),this.sheenRoughnessMap&&this.sheenRoughnessMap.isTexture&&(n.sheenRoughnessMap=this.sheenRoughnessMap.toJSON(e).uuid),this.dispersion!==void 0&&(n.dispersion=this.dispersion),this.iridescence!==void 0&&(n.iridescence=this.iridescence),this.iridescenceIOR!==void 0&&(n.iridescenceIOR=this.iridescenceIOR),this.iridescenceThicknessRange!==void 0&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).uuid),this.anisotropy!==void 0&&(n.anisotropy=this.anisotropy),this.anisotropyRotation!==void 0&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(e).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(e).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(e).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(e).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(e).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(e).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(e).uuid,this.combine!==void 0&&(n.combine=this.combine)),this.envMapRotation!==void 0&&(n.envMapRotation=this.envMapRotation.toArray()),this.envMapIntensity!==void 0&&(n.envMapIntensity=this.envMapIntensity),this.reflectivity!==void 0&&(n.reflectivity=this.reflectivity),this.refractionRatio!==void 0&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(e).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(e).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(e).uuid),this.attenuationDistance!==void 0&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.shadowSide!==null&&(n.shadowSide=this.shadowSide),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==Jn&&(n.blending=this.blending),this.side!==mn&&(n.side=this.side),this.vertexColors===!0&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.transparent===!0&&(n.transparent=!0),this.blendSrc!==Vr&&(n.blendSrc=this.blendSrc),this.blendDst!==Wr&&(n.blendDst=this.blendDst),this.blendEquation!==wn&&(n.blendEquation=this.blendEquation),this.blendSrcAlpha!==null&&(n.blendSrcAlpha=this.blendSrcAlpha),this.blendDstAlpha!==null&&(n.blendDstAlpha=this.blendDstAlpha),this.blendEquationAlpha!==null&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),this.blendAlpha!==0&&(n.blendAlpha=this.blendAlpha),this.depthFunc!==ei&&(n.depthFunc=this.depthFunc),this.depthTest===!1&&(n.depthTest=this.depthTest),this.depthWrite===!1&&(n.depthWrite=this.depthWrite),this.colorWrite===!1&&(n.colorWrite=this.colorWrite),this.stencilWriteMask!==255&&(n.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==ra&&(n.stencilFunc=this.stencilFunc),this.stencilRef!==0&&(n.stencilRef=this.stencilRef),this.stencilFuncMask!==255&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==Nn&&(n.stencilFail=this.stencilFail),this.stencilZFail!==Nn&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==Nn&&(n.stencilZPass=this.stencilZPass),this.stencilWrite===!0&&(n.stencilWrite=this.stencilWrite),this.rotation!==void 0&&this.rotation!==0&&(n.rotation=this.rotation),this.polygonOffset===!0&&(n.polygonOffset=!0),this.polygonOffsetFactor!==0&&(n.polygonOffsetFactor=this.polygonOffsetFactor),this.polygonOffsetUnits!==0&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth!==void 0&&this.linewidth!==1&&(n.linewidth=this.linewidth),this.dashSize!==void 0&&(n.dashSize=this.dashSize),this.gapSize!==void 0&&(n.gapSize=this.gapSize),this.scale!==void 0&&(n.scale=this.scale),this.dithering===!0&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),this.alphaHash===!0&&(n.alphaHash=!0),this.alphaToCoverage===!0&&(n.alphaToCoverage=!0),this.premultipliedAlpha===!0&&(n.premultipliedAlpha=!0),this.forceSinglePass===!0&&(n.forceSinglePass=!0),this.wireframe===!0&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!=="round"&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!=="round"&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading===!0&&(n.flatShading=!0),this.visible===!1&&(n.visible=!1),this.toneMapped===!1&&(n.toneMapped=!1),this.fog===!1&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData);function r(s){const a=[];for(const o in s){const c=s[o];delete c.metadata,a.push(c)}return a}if(t){const s=r(e.textures),a=r(e.images);s.length>0&&(n.textures=s),a.length>0&&(n.images=a)}return n}clone(){return new this.constructor().copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;const t=e.clippingPlanes;let n=null;if(t!==null){const r=t.length;n=new Array(r);for(let s=0;s!==r;++s)n[s]=t[s].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){e===!0&&this.version++}}class xo extends wi{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Oe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new Yt,this.combine=no,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}}const ot=new F,zi=new Ge;let Xl=0;class Xt{constructor(e,t,n=!1){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,Object.defineProperty(this,"id",{value:Xl++}),this.name="",this.array=e,this.itemSize=t,this.count=e!==void 0?e.length/t:0,this.normalized=n,this.usage=sa,this.updateRanges=[],this.gpuType=nn,this.version=0}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,n){e*=this.itemSize,n*=t.itemSize;for(let r=0,s=this.itemSize;rt.count&&console.warn("THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),t.needsUpdate=!0}return this}computeBoundingBox(){this.boundingBox===null&&(this.boundingBox=new bi);const e=this.attributes.position,t=this.morphAttributes.position;if(e&&e.isGLBufferAttribute){console.error("THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),this.boundingBox.set(new F(-1/0,-1/0,-1/0),new F(1/0,1/0,1/0));return}if(e!==void 0){if(this.boundingBox.setFromBufferAttribute(e),t)for(let n=0,r=t.length;n0&&(e.userData=this.userData),this.parameters!==void 0){const c=this.parameters;for(const l in c)c[l]!==void 0&&(e[l]=c[l]);return e}e.data={attributes:{}};const t=this.index;t!==null&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});const n=this.attributes;for(const c in n){const l=n[c];e.data.attributes[c]=l.toJSON(e.data)}const r={};let s=!1;for(const c in this.morphAttributes){const l=this.morphAttributes[c],h=[];for(let d=0,f=l.length;d0&&(r[c]=h,s=!0)}s&&(e.data.morphAttributes=r,e.data.morphTargetsRelative=this.morphTargetsRelative);const a=this.groups;a.length>0&&(e.data.groups=JSON.parse(JSON.stringify(a)));const o=this.boundingSphere;return o!==null&&(e.data.boundingSphere=o.toJSON()),e}clone(){return new this.constructor().copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const t={};this.name=e.name;const n=e.index;n!==null&&this.setIndex(n.clone());const r=e.attributes;for(const l in r){const h=r[l];this.setAttribute(l,h.clone(t))}const s=e.morphAttributes;for(const l in s){const h=[],d=s[l];for(let f=0,m=d.length;f0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,a=r.length;s(e.far-e.near)**2))&&(xa.copy(s).invert(),Sn.copy(e.ray).applyMatrix4(xa),!(n.boundingBox!==null&&Sn.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(e,t,Sn)))}_computeIntersections(e,t,n){let r;const s=this.geometry,a=this.material,o=s.index,c=s.attributes.position,l=s.attributes.uv,h=s.attributes.uv1,d=s.attributes.normal,f=s.groups,m=s.drawRange;if(o!==null)if(Array.isArray(a))for(let _=0,x=f.length;_t.far?null:{distance:l,point:qi.clone(),object:i}}function Yi(i,e,t,n,r,s,a,o,c,l){i.getVertexPosition(o,ki),i.getVertexPosition(c,Vi),i.getVertexPosition(l,Wi);const h=Yl(i,e,t,n,ki,Vi,Wi,Sa);if(h){const d=new F;Ht.getBarycoord(Sa,ki,Vi,Wi,d),r&&(h.uv=Ht.getInterpolatedAttribute(r,o,c,l,d,new Ge)),s&&(h.uv1=Ht.getInterpolatedAttribute(s,o,c,l,d,new Ge)),a&&(h.normal=Ht.getInterpolatedAttribute(a,o,c,l,d,new F),h.normal.dot(n.direction)>0&&h.normal.multiplyScalar(-1));const f={a:o,b:c,c:l,normal:new F,materialIndex:0};Ht.getNormal(ki,Vi,Wi,f.normal),h.face=f,h.barycoord=d}return h}class Ri extends sn{constructor(e=1,t=1,n=1,r=1,s=1,a=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:n,widthSegments:r,heightSegments:s,depthSegments:a};const o=this;r=Math.floor(r),s=Math.floor(s),a=Math.floor(a);const c=[],l=[],h=[],d=[];let f=0,m=0;_("z","y","x",-1,-1,n,t,e,a,s,0),_("z","y","x",1,-1,n,t,-e,a,s,1),_("x","z","y",1,1,e,n,t,r,a,2),_("x","z","y",1,-1,e,n,-t,r,a,3),_("x","y","z",1,-1,e,t,n,r,s,4),_("x","y","z",-1,-1,e,t,-n,r,s,5),this.setIndex(c),this.setAttribute("position",new Rt(l,3)),this.setAttribute("normal",new Rt(h,3)),this.setAttribute("uv",new Rt(d,2));function _(x,p,u,b,A,E,D,R,w,U,S){const M=E/w,C=D/U,O=E/2,z=D/2,q=R/2,W=w+1,X=U+1;let Z=0,G=0;const se=new F;for(let ce=0;ce0?1:-1,h.push(se.x,se.y,se.z),d.push(Fe/w),d.push(1-ce/U),Z+=1}}for(let ce=0;ce0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const n={};for(const r in this.extensions)this.extensions[r]===!0&&(n[r]=!0);return Object.keys(n).length>0&&(t.extensions=n),t}}class Io extends ft{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new it,this.projectionMatrix=new it,this.projectionMatrixInverse=new it,this.coordinateSystem=Xt,this._reversedDepth=!1}get reversedDepth(){return this._reversedDepth}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return new this.constructor().copy(this)}}const un=new N,Pa=new Ge,Da=new Ge;class It extends Io{constructor(e=50,t=1,n=.1,r=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=n,this.far=r,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=e.view===null?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=Os*2*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(ir*.5*this.fov);return .5*this.getFilmHeight()/e}getEffectiveFOV(){return Os*2*Math.atan(Math.tan(ir*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,n){un.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(un.x,un.y).multiplyScalar(-e/un.z),un.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(un.x,un.y).multiplyScalar(-e/un.z)}getViewSize(e,t){return this.getViewBounds(e,Pa,Da),t.subVectors(Da,Pa)}setViewOffset(e,t,n,r,s,a){this.aspect=e/t,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=r,this.view.width=s,this.view.height=a,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=this.near;let t=e*Math.tan(ir*.5*this.fov)/this.zoom,n=2*t,r=this.aspect*n,s=-.5*r;const a=this.view;if(this.view!==null&&this.view.enabled){const l=a.fullWidth,c=a.fullHeight;s+=a.offsetX*r/l,t-=a.offsetY*n/c,r*=a.width/l,n*=a.height/c}const o=this.filmOffset;o!==0&&(s+=e*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(s,s+r,t,t-n,e,this.far,this.coordinateSystem,this.reversedDepth),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,this.view!==null&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}}const Wn=-90,Xn=1;class ol extends ft{constructor(e,t,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const r=new It(Wn,Xn,e,t);r.layers=this.layers,this.add(r);const s=new It(Wn,Xn,e,t);s.layers=this.layers,this.add(s);const a=new It(Wn,Xn,e,t);a.layers=this.layers,this.add(a);const o=new It(Wn,Xn,e,t);o.layers=this.layers,this.add(o);const l=new It(Wn,Xn,e,t);l.layers=this.layers,this.add(l);const c=new It(Wn,Xn,e,t);c.layers=this.layers,this.add(c)}updateCoordinateSystem(){const e=this.coordinateSystem,t=this.children.concat(),[n,r,s,a,o,l]=t;for(const c of t)this.remove(c);if(e===Xt)n.up.set(0,1,0),n.lookAt(1,0,0),r.up.set(0,1,0),r.lookAt(-1,0,0),s.up.set(0,0,-1),s.lookAt(0,1,0),a.up.set(0,0,1),a.lookAt(0,-1,0),o.up.set(0,1,0),o.lookAt(0,0,1),l.up.set(0,1,0),l.lookAt(0,0,-1);else if(e===ar)n.up.set(0,-1,0),n.lookAt(-1,0,0),r.up.set(0,-1,0),r.lookAt(1,0,0),s.up.set(0,0,1),s.lookAt(0,1,0),a.up.set(0,0,-1),a.lookAt(0,-1,0),o.up.set(0,-1,0),o.lookAt(0,0,1),l.up.set(0,-1,0),l.lookAt(0,0,-1);else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);for(const c of t)this.add(c),c.updateMatrixWorld()}update(e,t){this.parent===null&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:r}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());const[s,a,o,l,c,d]=this.children,h=e.getRenderTarget(),f=e.getActiveCubeFace(),m=e.getActiveMipmapLevel(),_=e.xr.enabled;e.xr.enabled=!1;const x=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,e.setRenderTarget(n,0,r),e.render(t,s),e.setRenderTarget(n,1,r),e.render(t,a),e.setRenderTarget(n,2,r),e.render(t,o),e.setRenderTarget(n,3,r),e.render(t,l),e.setRenderTarget(n,4,r),e.render(t,c),n.texture.generateMipmaps=x,e.setRenderTarget(n,5,r),e.render(t,d),e.setRenderTarget(h,f,m),e.xr.enabled=_,n.texture.needsPMREMUpdate=!0}}class Uo extends Tt{constructor(e=[],t=jn,n,r,s,a,o,l,c,d){super(e,t,n,r,s,a,o,l,c,d),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}}class cl extends Dn{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;const n={width:e,height:e,depth:1},r=[n,n,n,n,n,n];this.texture=new Uo(r),this._setTextureOptions(t),this.texture.isRenderTargetTexture=!0}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:` +}`;class gn extends wi{constructor(e){super(),this.isShaderMaterial=!0,this.type="ShaderMaterial",this.defines={},this.uniforms={},this.uniformsGroups=[],this.vertexShader=Zl,this.fragmentShader=jl,this.linewidth=1,this.wireframe=!1,this.wireframeLinewidth=1,this.fog=!1,this.lights=!1,this.clipping=!1,this.forceSinglePass=!0,this.extensions={clipCullDistance:!1,multiDraw:!1},this.defaultAttributeValues={color:[1,1,1],uv:[0,0],uv1:[0,0]},this.index0AttributeName=void 0,this.uniformsNeedUpdate=!1,this.glslVersion=null,e!==void 0&&this.setValues(e)}copy(e){return super.copy(e),this.fragmentShader=e.fragmentShader,this.vertexShader=e.vertexShader,this.uniforms=ri(e.uniforms),this.uniformsGroups=$l(e.uniformsGroups),this.defines=Object.assign({},e.defines),this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.fog=e.fog,this.lights=e.lights,this.clipping=e.clipping,this.extensions=Object.assign({},e.extensions),this.glslVersion=e.glslVersion,this}toJSON(e){const t=super.toJSON(e);t.glslVersion=this.glslVersion,t.uniforms={};for(const r in this.uniforms){const a=this.uniforms[r].value;a&&a.isTexture?t.uniforms[r]={type:"t",value:a.toJSON(e).uuid}:a&&a.isColor?t.uniforms[r]={type:"c",value:a.getHex()}:a&&a.isVector2?t.uniforms[r]={type:"v2",value:a.toArray()}:a&&a.isVector3?t.uniforms[r]={type:"v3",value:a.toArray()}:a&&a.isVector4?t.uniforms[r]={type:"v4",value:a.toArray()}:a&&a.isMatrix3?t.uniforms[r]={type:"m3",value:a.toArray()}:a&&a.isMatrix4?t.uniforms[r]={type:"m4",value:a.toArray()}:t.uniforms[r]={value:a}}Object.keys(this.defines).length>0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;const n={};for(const r in this.extensions)this.extensions[r]===!0&&(n[r]=!0);return Object.keys(n).length>0&&(t.extensions=n),t}}class yo extends dt{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new st,this.projectionMatrix=new st,this.projectionMatrixInverse=new st,this.coordinateSystem=Wt,this._reversedDepth=!1}get reversedDepth(){return this._reversedDepth}copy(e,t){return super.copy(e,t),this.matrixWorldInverse.copy(e.matrixWorldInverse),this.projectionMatrix.copy(e.projectionMatrix),this.projectionMatrixInverse.copy(e.projectionMatrixInverse),this.coordinateSystem=e.coordinateSystem,this}getWorldDirection(e){return super.getWorldDirection(e).negate()}updateMatrixWorld(e){super.updateMatrixWorld(e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(e,t){super.updateWorldMatrix(e,t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return new this.constructor().copy(this)}}const hn=new F,Ea=new Ge,ya=new Ge;class It extends yo{constructor(e=50,t=1,n=.1,r=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=e,this.zoom=1,this.near=n,this.far=r,this.focus=10,this.aspect=t,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(e,t){return super.copy(e,t),this.fov=e.fov,this.zoom=e.zoom,this.near=e.near,this.far=e.far,this.focus=e.focus,this.aspect=e.aspect,this.view=e.view===null?null:Object.assign({},e.view),this.filmGauge=e.filmGauge,this.filmOffset=e.filmOffset,this}setFocalLength(e){const t=.5*this.getFilmHeight()/e;this.fov=Cs*2*Math.atan(t),this.updateProjectionMatrix()}getFocalLength(){const e=Math.tan(hr*.5*this.fov);return .5*this.getFilmHeight()/e}getEffectiveFOV(){return Cs*2*Math.atan(Math.tan(hr*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(e,t,n){hn.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),t.set(hn.x,hn.y).multiplyScalar(-e/hn.z),hn.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(hn.x,hn.y).multiplyScalar(-e/hn.z)}getViewSize(e,t){return this.getViewBounds(e,Ea,ya),t.subVectors(ya,Ea)}setViewOffset(e,t,n,r,s,a){this.aspect=e/t,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=e,this.view.fullHeight=t,this.view.offsetX=n,this.view.offsetY=r,this.view.width=s,this.view.height=a,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const e=this.near;let t=e*Math.tan(hr*.5*this.fov)/this.zoom,n=2*t,r=this.aspect*n,s=-.5*r;const a=this.view;if(this.view!==null&&this.view.enabled){const c=a.fullWidth,l=a.fullHeight;s+=a.offsetX*r/c,t-=a.offsetY*n/l,r*=a.width/c,n*=a.height/l}const o=this.filmOffset;o!==0&&(s+=e*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(s,s+r,t,t-n,e,this.far,this.coordinateSystem,this.reversedDepth),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(e){const t=super.toJSON(e);return t.object.fov=this.fov,t.object.zoom=this.zoom,t.object.near=this.near,t.object.far=this.far,t.object.focus=this.focus,t.object.aspect=this.aspect,this.view!==null&&(t.object.view=Object.assign({},this.view)),t.object.filmGauge=this.filmGauge,t.object.filmOffset=this.filmOffset,t}}const qn=-90,Yn=1;class Jl extends dt{constructor(e,t,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const r=new It(qn,Yn,e,t);r.layers=this.layers,this.add(r);const s=new It(qn,Yn,e,t);s.layers=this.layers,this.add(s);const a=new It(qn,Yn,e,t);a.layers=this.layers,this.add(a);const o=new It(qn,Yn,e,t);o.layers=this.layers,this.add(o);const c=new It(qn,Yn,e,t);c.layers=this.layers,this.add(c);const l=new It(qn,Yn,e,t);l.layers=this.layers,this.add(l)}updateCoordinateSystem(){const e=this.coordinateSystem,t=this.children.concat(),[n,r,s,a,o,c]=t;for(const l of t)this.remove(l);if(e===Wt)n.up.set(0,1,0),n.lookAt(1,0,0),r.up.set(0,1,0),r.lookAt(-1,0,0),s.up.set(0,0,-1),s.lookAt(0,1,0),a.up.set(0,0,1),a.lookAt(0,-1,0),o.up.set(0,1,0),o.lookAt(0,0,1),c.up.set(0,1,0),c.lookAt(0,0,-1);else if(e===sr)n.up.set(0,-1,0),n.lookAt(-1,0,0),r.up.set(0,-1,0),r.lookAt(1,0,0),s.up.set(0,0,1),s.lookAt(0,1,0),a.up.set(0,0,-1),a.lookAt(0,-1,0),o.up.set(0,-1,0),o.lookAt(0,0,1),c.up.set(0,-1,0),c.lookAt(0,0,-1);else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+e);for(const l of t)this.add(l),l.updateMatrixWorld()}update(e,t){this.parent===null&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:r}=this;this.coordinateSystem!==e.coordinateSystem&&(this.coordinateSystem=e.coordinateSystem,this.updateCoordinateSystem());const[s,a,o,c,l,h]=this.children,d=e.getRenderTarget(),f=e.getActiveCubeFace(),m=e.getActiveMipmapLevel(),_=e.xr.enabled;e.xr.enabled=!1;const x=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,e.setRenderTarget(n,0,r),e.render(t,s),e.setRenderTarget(n,1,r),e.render(t,a),e.setRenderTarget(n,2,r),e.render(t,o),e.setRenderTarget(n,3,r),e.render(t,c),e.setRenderTarget(n,4,r),e.render(t,l),n.texture.generateMipmaps=x,e.setRenderTarget(n,5,r),e.render(t,h),e.setRenderTarget(d,f,m),e.xr.enabled=_,n.texture.needsPMREMUpdate=!0}}class To extends xt{constructor(e=[],t=ti,n,r,s,a,o,c,l,h){super(e,t,n,r,s,a,o,c,l,h),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}}class Ql extends In{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;const n={width:e,height:e,depth:1},r=[n,n,n,n,n,n];this.texture=new To(r),this._setTextureOptions(t),this.texture.isRenderTargetTexture=!0}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:` varying vec3 vWorldDirection; @@ -41,13 +41,13 @@ gl_FragColor = texture2D( tEquirect, sampleUV ); } - `},r=new yi(5,5,5),s=new mn({name:"CubemapFromEquirect",uniforms:ei(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:yt,blending:dn});s.uniforms.tEquirect.value=t;const a=new Et(r,s),o=t.minFilter;return t.minFilter===Cn&&(t.minFilter=Wt),new ol(1,10,this).update(e,a),t.minFilter=o,a.geometry.dispose(),a.material.dispose(),this}clear(e,t=!0,n=!0,r=!0){const s=e.getRenderTarget();for(let a=0;a<6;a++)e.setRenderTarget(this,a),e.clear(t,n,r);e.setRenderTarget(s)}}class hi extends ft{constructor(){super(),this.isGroup=!0,this.type="Group"}}const ll={type:"move"};class zr{constructor(){this._targetRay=null,this._grip=null,this._hand=null}getHandSpace(){return this._hand===null&&(this._hand=new hi,this._hand.matrixAutoUpdate=!1,this._hand.visible=!1,this._hand.joints={},this._hand.inputState={pinching:!1}),this._hand}getTargetRaySpace(){return this._targetRay===null&&(this._targetRay=new hi,this._targetRay.matrixAutoUpdate=!1,this._targetRay.visible=!1,this._targetRay.hasLinearVelocity=!1,this._targetRay.linearVelocity=new N,this._targetRay.hasAngularVelocity=!1,this._targetRay.angularVelocity=new N),this._targetRay}getGripSpace(){return this._grip===null&&(this._grip=new hi,this._grip.matrixAutoUpdate=!1,this._grip.visible=!1,this._grip.hasLinearVelocity=!1,this._grip.linearVelocity=new N,this._grip.hasAngularVelocity=!1,this._grip.angularVelocity=new N),this._grip}dispatchEvent(e){return this._targetRay!==null&&this._targetRay.dispatchEvent(e),this._grip!==null&&this._grip.dispatchEvent(e),this._hand!==null&&this._hand.dispatchEvent(e),this}connect(e){if(e&&e.hand){const t=this._hand;if(t)for(const n of e.hand.values())this._getHandJoint(t,n)}return this.dispatchEvent({type:"connected",data:e}),this}disconnect(e){return this.dispatchEvent({type:"disconnected",data:e}),this._targetRay!==null&&(this._targetRay.visible=!1),this._grip!==null&&(this._grip.visible=!1),this._hand!==null&&(this._hand.visible=!1),this}update(e,t,n){let r=null,s=null,a=null;const o=this._targetRay,l=this._grip,c=this._hand;if(e&&t.session.visibilityState!=="visible-blurred"){if(c&&e.hand){a=!0;for(const x of e.hand.values()){const p=t.getJointPose(x,n),u=this._getHandJoint(c,x);p!==null&&(u.matrix.fromArray(p.transform.matrix),u.matrix.decompose(u.position,u.rotation,u.scale),u.matrixWorldNeedsUpdate=!0,u.jointRadius=p.radius),u.visible=p!==null}const d=c.joints["index-finger-tip"],h=c.joints["thumb-tip"],f=d.position.distanceTo(h.position),m=.02,_=.005;c.inputState.pinching&&f>m+_?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!c.inputState.pinching&&f<=m-_&&(c.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else l!==null&&e.gripSpace&&(s=t.getPose(e.gripSpace,n),s!==null&&(l.matrix.fromArray(s.transform.matrix),l.matrix.decompose(l.position,l.rotation,l.scale),l.matrixWorldNeedsUpdate=!0,s.linearVelocity?(l.hasLinearVelocity=!0,l.linearVelocity.copy(s.linearVelocity)):l.hasLinearVelocity=!1,s.angularVelocity?(l.hasAngularVelocity=!0,l.angularVelocity.copy(s.angularVelocity)):l.hasAngularVelocity=!1));o!==null&&(r=t.getPose(e.targetRaySpace,n),r===null&&s!==null&&(r=s),r!==null&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(ll)))}return o!==null&&(o.visible=r!==null),l!==null&&(l.visible=s!==null),c!==null&&(c.visible=a!==null),this}_getHandJoint(e,t){if(e.joints[t.jointName]===void 0){const n=new hi;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}class ul extends ft{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new $t,this.environmentIntensity=1,this.environmentRotation=new $t,this.overrideMaterial=null,typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),e.background!==null&&(this.background=e.background.clone()),e.environment!==null&&(this.environment=e.environment.clone()),e.fog!==null&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentIntensity=e.environmentIntensity,this.environmentRotation.copy(e.environmentRotation),e.overrideMaterial!==null&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return this.fog!==null&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),this.environmentIntensity!==1&&(t.object.environmentIntensity=this.environmentIntensity),t.object.environmentRotation=this.environmentRotation.toArray(),t}}const Hr=new N,hl=new N,dl=new Ie;class Tn{constructor(e=new N(1,0,0),t=0){this.isPlane=!0,this.normal=e,this.constant=t}set(e,t){return this.normal.copy(e),this.constant=t,this}setComponents(e,t,n,r){return this.normal.set(e,t,n),this.constant=r,this}setFromNormalAndCoplanarPoint(e,t){return this.normal.copy(e),this.constant=-t.dot(this.normal),this}setFromCoplanarPoints(e,t,n){const r=Hr.subVectors(n,t).cross(hl.subVectors(e,t)).normalize();return this.setFromNormalAndCoplanarPoint(r,e),this}copy(e){return this.normal.copy(e.normal),this.constant=e.constant,this}normalize(){const e=1/this.normal.length();return this.normal.multiplyScalar(e),this.constant*=e,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(e){return this.normal.dot(e)+this.constant}distanceToSphere(e){return this.distanceToPoint(e.center)-e.radius}projectPoint(e,t){return t.copy(e).addScaledVector(this.normal,-this.distanceToPoint(e))}intersectLine(e,t){const n=e.delta(Hr),r=this.normal.dot(n);if(r===0)return this.distanceToPoint(e.start)===0?t.copy(e.start):null;const s=-(e.start.dot(this.normal)+this.constant)/r;return s<0||s>1?null:t.copy(e.start).addScaledVector(n,s)}intersectsLine(e){const t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){const n=t||dl.getNormalMatrix(e),r=this.coplanarPoint(Hr).applyMatrix4(e),s=this.normal.applyMatrix3(n).normalize();return this.constant=-r.dot(s),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return new this.constructor().copy(this)}}const Sn=new fr,fl=new Ge(.5,.5),Wi=new N;class js{constructor(e=new Tn,t=new Tn,n=new Tn,r=new Tn,s=new Tn,a=new Tn){this.planes=[e,t,n,r,s,a]}set(e,t,n,r,s,a){const o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(n),o[3].copy(r),o[4].copy(s),o[5].copy(a),this}copy(e){const t=this.planes;for(let n=0;n<6;n++)t[n].copy(e.planes[n]);return this}setFromProjectionMatrix(e,t=Xt,n=!1){const r=this.planes,s=e.elements,a=s[0],o=s[1],l=s[2],c=s[3],d=s[4],h=s[5],f=s[6],m=s[7],_=s[8],x=s[9],p=s[10],u=s[11],b=s[12],A=s[13],E=s[14],C=s[15];if(r[0].setComponents(c-a,m-d,u-_,C-b).normalize(),r[1].setComponents(c+a,m+d,u+_,C+b).normalize(),r[2].setComponents(c+o,m+h,u+x,C+A).normalize(),r[3].setComponents(c-o,m-h,u-x,C-A).normalize(),n)r[4].setComponents(l,f,p,E).normalize(),r[5].setComponents(c-l,m-f,u-p,C-E).normalize();else if(r[4].setComponents(c-l,m-f,u-p,C-E).normalize(),t===Xt)r[5].setComponents(c+l,m+f,u+p,C+E).normalize();else if(t===ar)r[5].setComponents(l,f,p,E).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);return this}intersectsObject(e){if(e.boundingSphere!==void 0)e.boundingSphere===null&&e.computeBoundingSphere(),Sn.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{const t=e.geometry;t.boundingSphere===null&&t.computeBoundingSphere(),Sn.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(Sn)}intersectsSprite(e){Sn.center.set(0,0,0);const t=fl.distanceTo(e.center);return Sn.radius=.7071067811865476+t,Sn.applyMatrix4(e.matrixWorld),this.intersectsSphere(Sn)}intersectsSphere(e){const t=this.planes,n=e.center,r=-e.radius;for(let s=0;s<6;s++)if(t[s].distanceToPoint(n)0?e.max.x:e.min.x,Wi.y=r.normal.y>0?e.max.y:e.min.y,Wi.z=r.normal.z>0?e.max.z:e.min.z,r.distanceToPoint(Wi)<0)return!1}return!0}containsPoint(e){const t=this.planes;for(let n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}}class No extends ni{constructor(e){super(),this.isLineBasicMaterial=!0,this.type="LineBasicMaterial",this.color=new Fe(16777215),this.map=null,this.linewidth=1,this.linecap="round",this.linejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.linewidth=e.linewidth,this.linecap=e.linecap,this.linejoin=e.linejoin,this.fog=e.fog,this}}const lr=new N,ur=new N,La=new it,ui=new Ks,Xi=new fr,Gr=new N,Ia=new N;class pl extends ft{constructor(e=new Nt,t=new No){super(),this.isLine=!0,this.type="Line",this.geometry=e,this.material=t,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.updateMorphTargets()}copy(e,t){return super.copy(e,t),this.material=Array.isArray(e.material)?e.material.slice():e.material,this.geometry=e.geometry,this}computeLineDistances(){const e=this.geometry;if(e.index===null){const t=e.attributes.position,n=[0];for(let r=1,s=t.count;r0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,a=r.length;sn)return;Gr.applyMatrix4(i.matrixWorld);const c=e.ray.origin.distanceTo(Gr);if(!(ce.far))return{distance:c,point:Ia.clone().applyMatrix4(i.matrixWorld),index:a,face:null,faceIndex:null,barycoord:null,object:i}}const Ua=new N,Na=new N;class ml extends pl{constructor(e,t){super(e,t),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const e=this.geometry;if(e.index===null){const t=e.attributes.position,n=[];for(let r=0,s=t.count;r0&&A(!0),t>0&&A(!1)),this.setIndex(d),this.setAttribute("position",new ct(h,3)),this.setAttribute("normal",new ct(f,3)),this.setAttribute("uv",new ct(m,2));function b(){const E=new N,C=new N;let R=0;const w=(t-e)/n;for(let U=0;U<=s;U++){const S=[],M=U/s,P=M*(t-e)+e;for(let O=0;O<=r;O++){const H=O/r,q=H*l+o,W=Math.sin(q),X=Math.cos(q);C.x=P*W,C.y=-M*n+p,C.z=P*X,h.push(C.x,C.y,C.z),E.set(W,w,X).normalize(),f.push(E.x,E.y,E.z),m.push(H,1-M),S.push(_++)}x.push(S)}for(let U=0;U0||S!==0)&&(d.push(M,P,H),R+=3),(t>0||S!==s-1)&&(d.push(P,O,H),R+=3)}c.addGroup(u,R,0),u+=R}function A(E){const C=_,R=new Ge,w=new N;let U=0;const S=E===!0?e:t,M=E===!0?1:-1;for(let O=1;O<=r;O++)h.push(0,p*M,0),f.push(0,M,0),m.push(.5,.5),_++;const P=_;for(let O=0;O<=r;O++){const q=O/r*l+o,W=Math.cos(q),X=Math.sin(q);w.x=S*X,w.y=p*M,w.z=S*W,h.push(w.x,w.y,w.z),f.push(0,M,0),R.x=W*.5+.5,R.y=X*.5*M+.5,m.push(R.x,R.y),_++}for(let O=0;Om+_?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!l.inputState.pinching&&f<=m-_&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else c!==null&&e.gripSpace&&(s=t.getPose(e.gripSpace,n),s!==null&&(c.matrix.fromArray(s.transform.matrix),c.matrix.decompose(c.position,c.rotation,c.scale),c.matrixWorldNeedsUpdate=!0,s.linearVelocity?(c.hasLinearVelocity=!0,c.linearVelocity.copy(s.linearVelocity)):c.hasLinearVelocity=!1,s.angularVelocity?(c.hasAngularVelocity=!0,c.angularVelocity.copy(s.angularVelocity)):c.hasAngularVelocity=!1));o!==null&&(r=t.getPose(e.targetRaySpace,n),r===null&&s!==null&&(r=s),r!==null&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(ec)))}return o!==null&&(o.visible=r!==null),c!==null&&(c.visible=s!==null),l!==null&&(l.visible=a!==null),this}_getHandJoint(e,t){if(e.joints[t.jointName]===void 0){const n=new Zn;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}class tc extends dt{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new Yt,this.environmentIntensity=1,this.environmentRotation=new Yt,this.overrideMaterial=null,typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),e.background!==null&&(this.background=e.background.clone()),e.environment!==null&&(this.environment=e.environment.clone()),e.fog!==null&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentIntensity=e.environmentIntensity,this.environmentRotation.copy(e.environmentRotation),e.overrideMaterial!==null&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return this.fog!==null&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),this.environmentIntensity!==1&&(t.object.environmentIntensity=this.environmentIntensity),t.object.environmentRotation=this.environmentRotation.toArray(),t}}const Ur=new F,nc=new F,ic=new Ie;class An{constructor(e=new F(1,0,0),t=0){this.isPlane=!0,this.normal=e,this.constant=t}set(e,t){return this.normal.copy(e),this.constant=t,this}setComponents(e,t,n,r){return this.normal.set(e,t,n),this.constant=r,this}setFromNormalAndCoplanarPoint(e,t){return this.normal.copy(e),this.constant=-t.dot(this.normal),this}setFromCoplanarPoints(e,t,n){const r=Ur.subVectors(n,t).cross(nc.subVectors(e,t)).normalize();return this.setFromNormalAndCoplanarPoint(r,e),this}copy(e){return this.normal.copy(e.normal),this.constant=e.constant,this}normalize(){const e=1/this.normal.length();return this.normal.multiplyScalar(e),this.constant*=e,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(e){return this.normal.dot(e)+this.constant}distanceToSphere(e){return this.distanceToPoint(e.center)-e.radius}projectPoint(e,t){return t.copy(e).addScaledVector(this.normal,-this.distanceToPoint(e))}intersectLine(e,t){const n=e.delta(Ur),r=this.normal.dot(n);if(r===0)return this.distanceToPoint(e.start)===0?t.copy(e.start):null;const s=-(e.start.dot(this.normal)+this.constant)/r;return s<0||s>1?null:t.copy(e.start).addScaledVector(n,s)}intersectsLine(e){const t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){const n=t||ic.getNormalMatrix(e),r=this.coplanarPoint(Ur).applyMatrix4(e),s=this.normal.applyMatrix3(n).normalize();return this.constant=-r.dot(s),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return new this.constructor().copy(this)}}const En=new zs,rc=new Ge(.5,.5),$i=new F;class ks{constructor(e=new An,t=new An,n=new An,r=new An,s=new An,a=new An){this.planes=[e,t,n,r,s,a]}set(e,t,n,r,s,a){const o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(n),o[3].copy(r),o[4].copy(s),o[5].copy(a),this}copy(e){const t=this.planes;for(let n=0;n<6;n++)t[n].copy(e.planes[n]);return this}setFromProjectionMatrix(e,t=Wt,n=!1){const r=this.planes,s=e.elements,a=s[0],o=s[1],c=s[2],l=s[3],h=s[4],d=s[5],f=s[6],m=s[7],_=s[8],x=s[9],p=s[10],u=s[11],b=s[12],A=s[13],E=s[14],D=s[15];if(r[0].setComponents(l-a,m-h,u-_,D-b).normalize(),r[1].setComponents(l+a,m+h,u+_,D+b).normalize(),r[2].setComponents(l+o,m+d,u+x,D+A).normalize(),r[3].setComponents(l-o,m-d,u-x,D-A).normalize(),n)r[4].setComponents(c,f,p,E).normalize(),r[5].setComponents(l-c,m-f,u-p,D-E).normalize();else if(r[4].setComponents(l-c,m-f,u-p,D-E).normalize(),t===Wt)r[5].setComponents(l+c,m+f,u+p,D+E).normalize();else if(t===sr)r[5].setComponents(c,f,p,E).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);return this}intersectsObject(e){if(e.boundingSphere!==void 0)e.boundingSphere===null&&e.computeBoundingSphere(),En.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{const t=e.geometry;t.boundingSphere===null&&t.computeBoundingSphere(),En.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(En)}intersectsSprite(e){En.center.set(0,0,0);const t=rc.distanceTo(e.center);return En.radius=.7071067811865476+t,En.applyMatrix4(e.matrixWorld),this.intersectsSphere(En)}intersectsSphere(e){const t=this.planes,n=e.center,r=-e.radius;for(let s=0;s<6;s++)if(t[s].distanceToPoint(n)0?e.max.x:e.min.x,$i.y=r.normal.y>0?e.max.y:e.min.y,$i.z=r.normal.z>0?e.max.z:e.min.z,r.distanceToPoint($i)<0)return!1}return!0}containsPoint(e){const t=this.planes;for(let n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}}class Ao extends xt{constructor(e,t,n=Ln,r,s,a,o=Gt,c=Gt,l,h=xi,d=1){if(h!==xi&&h!==Mi)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");const f={width:e,height:t,depth:d};super(f,r,s,a,o,c,h,n,l),this.isDepthTexture=!0,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(e){return super.copy(e),this.source=new Hs(Object.assign({},e.image)),this.compareFunction=e.compareFunction,this}toJSON(e){const t=super.toJSON(e);return this.compareFunction!==null&&(t.compareFunction=this.compareFunction),t}}class bo extends xt{constructor(e=null){super(),this.sourceTexture=e,this.isExternalTexture=!0}copy(e){return super.copy(e),this.sourceTexture=e.sourceTexture,this}}class Vs extends sn{constructor(e=1,t=1,n=1,r=32,s=1,a=!1,o=0,c=Math.PI*2){super(),this.type="CylinderGeometry",this.parameters={radiusTop:e,radiusBottom:t,height:n,radialSegments:r,heightSegments:s,openEnded:a,thetaStart:o,thetaLength:c};const l=this;r=Math.floor(r),s=Math.floor(s);const h=[],d=[],f=[],m=[];let _=0;const x=[],p=n/2;let u=0;b(),a===!1&&(e>0&&A(!0),t>0&&A(!1)),this.setIndex(h),this.setAttribute("position",new Rt(d,3)),this.setAttribute("normal",new Rt(f,3)),this.setAttribute("uv",new Rt(m,2));function b(){const E=new F,D=new F;let R=0;const w=(t-e)/n;for(let U=0;U<=s;U++){const S=[],M=U/s,C=M*(t-e)+e;for(let O=0;O<=r;O++){const z=O/r,q=z*c+o,W=Math.sin(q),X=Math.cos(q);D.x=C*W,D.y=-M*n+p,D.z=C*X,d.push(D.x,D.y,D.z),E.set(W,w,X).normalize(),f.push(E.x,E.y,E.z),m.push(z,1-M),S.push(_++)}x.push(S)}for(let U=0;U0||S!==0)&&(h.push(M,C,z),R+=3),(t>0||S!==s-1)&&(h.push(C,O,z),R+=3)}l.addGroup(u,R,0),u+=R}function A(E){const D=_,R=new Ge,w=new F;let U=0;const S=E===!0?e:t,M=E===!0?1:-1;for(let O=1;O<=r;O++)d.push(0,p*M,0),f.push(0,M,0),m.push(.5,.5),_++;const C=_;for(let O=0;O<=r;O++){const q=O/r*c+o,W=Math.cos(q),X=Math.sin(q);w.x=S*X,w.y=p*M,w.z=S*W,d.push(w.x,w.y,w.z),f.push(0,M,0),R.x=W*.5+.5,R.y=X*.5*M+.5,m.push(R.x,R.y),_++}for(let O=0;Om.start-_.start);let f=0;for(let m=1;mm.start-_.start);let f=0;for(let m=1;m 0 +#endif`,Uc=`#if NUM_CLIPPING_PLANES > 0 vec4 plane; #ifdef ALPHA_TO_COVERAGE float distanceToPlane, distanceGradient; @@ -297,26 +297,26 @@ vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in ve if ( clipped ) discard; #endif #endif -#endif`,Wl=`#if NUM_CLIPPING_PLANES > 0 +#endif`,Nc=`#if NUM_CLIPPING_PLANES > 0 varying vec3 vClipPosition; uniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ]; -#endif`,Xl=`#if NUM_CLIPPING_PLANES > 0 +#endif`,Fc=`#if NUM_CLIPPING_PLANES > 0 varying vec3 vClipPosition; -#endif`,ql=`#if NUM_CLIPPING_PLANES > 0 +#endif`,Oc=`#if NUM_CLIPPING_PLANES > 0 vClipPosition = - mvPosition.xyz; -#endif`,Yl=`#if defined( USE_COLOR_ALPHA ) +#endif`,Bc=`#if defined( USE_COLOR_ALPHA ) diffuseColor *= vColor; #elif defined( USE_COLOR ) diffuseColor.rgb *= vColor; -#endif`,$l=`#if defined( USE_COLOR_ALPHA ) +#endif`,Hc=`#if defined( USE_COLOR_ALPHA ) varying vec4 vColor; #elif defined( USE_COLOR ) varying vec3 vColor; -#endif`,Kl=`#if defined( USE_COLOR_ALPHA ) +#endif`,zc=`#if defined( USE_COLOR_ALPHA ) varying vec4 vColor; #elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) varying vec3 vColor; -#endif`,Zl=`#if defined( USE_COLOR_ALPHA ) +#endif`,Gc=`#if defined( USE_COLOR_ALPHA ) vColor = vec4( 1.0 ); #elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) vColor = vec3( 1.0 ); @@ -330,7 +330,7 @@ vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in ve #ifdef USE_BATCHING_COLOR vec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) ); vColor.xyz *= batchingColor.xyz; -#endif`,jl=`#define PI 3.141592653589793 +#endif`,kc=`#define PI 3.141592653589793 #define PI2 6.283185307179586 #define PI_HALF 1.5707963267948966 #define RECIPROCAL_PI 0.3183098861837907 @@ -404,7 +404,7 @@ vec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) { float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); -} // validated`,Jl=`#ifdef ENVMAP_TYPE_CUBE_UV +} // validated`,Vc=`#ifdef ENVMAP_TYPE_CUBE_UV #define cubeUV_minMipLevel 4.0 #define cubeUV_minTileSize 16.0 float getFace( vec3 direction ) { @@ -497,7 +497,7 @@ float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { return vec4( mix( color0, color1, mipF ), 1.0 ); } } -#endif`,Ql=`vec3 transformedNormal = objectNormal; +#endif`,Wc=`vec3 transformedNormal = objectNormal; #ifdef USE_TANGENT vec3 transformedTangent = objectTangent; #endif @@ -526,21 +526,21 @@ transformedNormal = normalMatrix * transformedNormal; #ifdef FLIP_SIDED transformedTangent = - transformedTangent; #endif -#endif`,eu=`#ifdef USE_DISPLACEMENTMAP +#endif`,Xc=`#ifdef USE_DISPLACEMENTMAP uniform sampler2D displacementMap; uniform float displacementScale; uniform float displacementBias; -#endif`,tu=`#ifdef USE_DISPLACEMENTMAP +#endif`,qc=`#ifdef USE_DISPLACEMENTMAP transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias ); -#endif`,nu=`#ifdef USE_EMISSIVEMAP +#endif`,Yc=`#ifdef USE_EMISSIVEMAP vec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv ); #ifdef DECODE_VIDEO_TEXTURE_EMISSIVE emissiveColor = sRGBTransferEOTF( emissiveColor ); #endif totalEmissiveRadiance *= emissiveColor.rgb; -#endif`,iu=`#ifdef USE_EMISSIVEMAP +#endif`,$c=`#ifdef USE_EMISSIVEMAP uniform sampler2D emissiveMap; -#endif`,ru="gl_FragColor = linearToOutputTexel( gl_FragColor );",su=`vec4 LinearTransferOETF( in vec4 value ) { +#endif`,Kc="gl_FragColor = linearToOutputTexel( gl_FragColor );",Zc=`vec4 LinearTransferOETF( in vec4 value ) { return value; } vec4 sRGBTransferEOTF( in vec4 value ) { @@ -548,7 +548,7 @@ vec4 sRGBTransferEOTF( in vec4 value ) { } vec4 sRGBTransferOETF( in vec4 value ) { return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); -}`,au=`#ifdef USE_ENVMAP +}`,jc=`#ifdef USE_ENVMAP #ifdef ENV_WORLDPOS vec3 cameraToFrag; if ( isOrthographic ) { @@ -577,7 +577,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { #elif defined( ENVMAP_BLENDING_ADD ) outgoingLight += envColor.xyz * specularStrength * reflectivity; #endif -#endif`,ou=`#ifdef USE_ENVMAP +#endif`,Jc=`#ifdef USE_ENVMAP uniform float envMapIntensity; uniform float flipEnvMap; uniform mat3 envMapRotation; @@ -587,7 +587,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { uniform sampler2D envMap; #endif -#endif`,cu=`#ifdef USE_ENVMAP +#endif`,Qc=`#ifdef USE_ENVMAP uniform float reflectivity; #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) #define ENV_WORLDPOS @@ -598,7 +598,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { #else varying vec3 vReflect; #endif -#endif`,lu=`#ifdef USE_ENVMAP +#endif`,eu=`#ifdef USE_ENVMAP #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) #define ENV_WORLDPOS #endif @@ -609,7 +609,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { varying vec3 vReflect; uniform float refractionRatio; #endif -#endif`,uu=`#ifdef USE_ENVMAP +#endif`,tu=`#ifdef USE_ENVMAP #ifdef ENV_WORLDPOS vWorldPosition = worldPosition.xyz; #else @@ -626,18 +626,18 @@ vec4 sRGBTransferOETF( in vec4 value ) { vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); #endif #endif -#endif`,hu=`#ifdef USE_FOG +#endif`,nu=`#ifdef USE_FOG vFogDepth = - mvPosition.z; -#endif`,du=`#ifdef USE_FOG +#endif`,iu=`#ifdef USE_FOG varying float vFogDepth; -#endif`,fu=`#ifdef USE_FOG +#endif`,ru=`#ifdef USE_FOG #ifdef FOG_EXP2 float fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth ); #else float fogFactor = smoothstep( fogNear, fogFar, vFogDepth ); #endif gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor ); -#endif`,pu=`#ifdef USE_FOG +#endif`,su=`#ifdef USE_FOG uniform vec3 fogColor; varying float vFogDepth; #ifdef FOG_EXP2 @@ -646,7 +646,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { uniform float fogNear; uniform float fogFar; #endif -#endif`,mu=`#ifdef USE_GRADIENTMAP +#endif`,au=`#ifdef USE_GRADIENTMAP uniform sampler2D gradientMap; #endif vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { @@ -658,12 +658,12 @@ vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { vec2 fw = fwidth( coord ) * 0.5; return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) ); #endif -}`,gu=`#ifdef USE_LIGHTMAP +}`,ou=`#ifdef USE_LIGHTMAP uniform sampler2D lightMap; uniform float lightMapIntensity; -#endif`,_u=`LambertMaterial material; +#endif`,lu=`LambertMaterial material; material.diffuseColor = diffuseColor.rgb; -material.specularStrength = specularStrength;`,vu=`varying vec3 vViewPosition; +material.specularStrength = specularStrength;`,cu=`varying vec3 vViewPosition; struct LambertMaterial { vec3 diffuseColor; float specularStrength; @@ -677,7 +677,7 @@ void RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometr reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } #define RE_Direct RE_Direct_Lambert -#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,xu=`uniform bool receiveShadow; +#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,uu=`uniform bool receiveShadow; uniform vec3 ambientLightColor; #if defined( USE_LIGHT_PROBES ) uniform vec3 lightProbe[ 9 ]; @@ -793,7 +793,7 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight ); return irradiance; } -#endif`,Mu=`#ifdef USE_ENVMAP +#endif`,hu=`#ifdef USE_ENVMAP vec3 getIBLIrradiance( const in vec3 normal ) { #ifdef ENVMAP_TYPE_CUBE_UV vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); @@ -826,8 +826,8 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi #endif } #endif -#endif`,Su=`ToonMaterial material; -material.diffuseColor = diffuseColor.rgb;`,Eu=`varying vec3 vViewPosition; +#endif`,du=`ToonMaterial material; +material.diffuseColor = diffuseColor.rgb;`,fu=`varying vec3 vViewPosition; struct ToonMaterial { vec3 diffuseColor; }; @@ -839,11 +839,11 @@ void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPo reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } #define RE_Direct RE_Direct_Toon -#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,yu=`BlinnPhongMaterial material; +#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,pu=`BlinnPhongMaterial material; material.diffuseColor = diffuseColor.rgb; material.specularColor = specular; material.specularShininess = shininess; -material.specularStrength = specularStrength;`,Tu=`varying vec3 vViewPosition; +material.specularStrength = specularStrength;`,mu=`varying vec3 vViewPosition; struct BlinnPhongMaterial { vec3 diffuseColor; vec3 specularColor; @@ -860,7 +860,7 @@ void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geom reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } #define RE_Direct RE_Direct_BlinnPhong -#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,Au=`PhysicalMaterial material; +#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,gu=`PhysicalMaterial material; material.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor ); vec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) ); float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z ); @@ -946,7 +946,7 @@ material.roughness = min( material.roughness, 1.0 ); material.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) ); material.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y; material.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y; -#endif`,bu=`struct PhysicalMaterial { +#endif`,_u=`struct PhysicalMaterial { vec3 diffuseColor; float roughness; vec3 specularColor; @@ -1247,7 +1247,7 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia #define RE_IndirectSpecular RE_IndirectSpecular_Physical float computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) { return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); -}`,wu=` +}`,vu=` vec3 geometryPosition = - vViewPosition; vec3 geometryNormal = normal; vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); @@ -1362,7 +1362,7 @@ IncidentLight directLight; #if defined( RE_IndirectSpecular ) vec3 radiance = vec3( 0.0 ); vec3 clearcoatRadiance = vec3( 0.0 ); -#endif`,Ru=`#if defined( RE_IndirectDiffuse ) +#endif`,xu=`#if defined( RE_IndirectDiffuse ) #ifdef USE_LIGHTMAP vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; @@ -1381,32 +1381,32 @@ IncidentLight directLight; #ifdef USE_CLEARCOAT clearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness ); #endif -#endif`,Cu=`#if defined( RE_IndirectDiffuse ) +#endif`,Mu=`#if defined( RE_IndirectDiffuse ) RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); #endif #if defined( RE_IndirectSpecular ) RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); -#endif`,Pu=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) +#endif`,Su=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) gl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5; -#endif`,Du=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) +#endif`,Eu=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) uniform float logDepthBufFC; varying float vFragDepth; varying float vIsPerspective; -#endif`,Lu=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER +#endif`,yu=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER varying float vFragDepth; varying float vIsPerspective; -#endif`,Iu=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER +#endif`,Tu=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER vFragDepth = 1.0 + gl_Position.w; vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) ); -#endif`,Uu=`#ifdef USE_MAP +#endif`,Au=`#ifdef USE_MAP vec4 sampledDiffuseColor = texture2D( map, vMapUv ); #ifdef DECODE_VIDEO_TEXTURE sampledDiffuseColor = sRGBTransferEOTF( sampledDiffuseColor ); #endif diffuseColor *= sampledDiffuseColor; -#endif`,Nu=`#ifdef USE_MAP +#endif`,bu=`#ifdef USE_MAP uniform sampler2D map; -#endif`,Fu=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) +#endif`,wu=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) #if defined( USE_POINTS_UV ) vec2 uv = vUv; #else @@ -1418,7 +1418,7 @@ IncidentLight directLight; #endif #ifdef USE_ALPHAMAP diffuseColor.a *= texture2D( alphaMap, uv ).g; -#endif`,Ou=`#if defined( USE_POINTS_UV ) +#endif`,Ru=`#if defined( USE_POINTS_UV ) varying vec2 vUv; #else #if defined( USE_MAP ) || defined( USE_ALPHAMAP ) @@ -1430,19 +1430,19 @@ IncidentLight directLight; #endif #ifdef USE_ALPHAMAP uniform sampler2D alphaMap; -#endif`,Bu=`float metalnessFactor = metalness; +#endif`,Cu=`float metalnessFactor = metalness; #ifdef USE_METALNESSMAP vec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv ); metalnessFactor *= texelMetalness.b; -#endif`,zu=`#ifdef USE_METALNESSMAP +#endif`,Pu=`#ifdef USE_METALNESSMAP uniform sampler2D metalnessMap; -#endif`,Hu=`#ifdef USE_INSTANCING_MORPH +#endif`,Du=`#ifdef USE_INSTANCING_MORPH float morphTargetInfluences[ MORPHTARGETS_COUNT ]; float morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r; for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { morphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r; } -#endif`,Gu=`#if defined( USE_MORPHCOLORS ) +#endif`,Lu=`#if defined( USE_MORPHCOLORS ) vColor *= morphTargetBaseInfluence; for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { #if defined( USE_COLOR_ALPHA ) @@ -1451,12 +1451,12 @@ IncidentLight directLight; if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]; #endif } -#endif`,Vu=`#ifdef USE_MORPHNORMALS +#endif`,Iu=`#ifdef USE_MORPHNORMALS objectNormal *= morphTargetBaseInfluence; for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ]; } -#endif`,ku=`#ifdef USE_MORPHTARGETS +#endif`,Uu=`#ifdef USE_MORPHTARGETS #ifndef USE_INSTANCING_MORPH uniform float morphTargetBaseInfluence; uniform float morphTargetInfluences[ MORPHTARGETS_COUNT ]; @@ -1470,12 +1470,12 @@ IncidentLight directLight; ivec3 morphUV = ivec3( x, y, morphTargetIndex ); return texelFetch( morphTargetsTexture, morphUV, 0 ); } -#endif`,Wu=`#ifdef USE_MORPHTARGETS +#endif`,Nu=`#ifdef USE_MORPHTARGETS transformed *= morphTargetBaseInfluence; for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ]; } -#endif`,Xu=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; +#endif`,Fu=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; #ifdef FLAT_SHADED vec3 fdx = dFdx( vViewPosition ); vec3 fdy = dFdy( vViewPosition ); @@ -1516,7 +1516,7 @@ IncidentLight directLight; tbn2[1] *= faceDirection; #endif #endif -vec3 nonPerturbedNormal = normal;`,qu=`#ifdef USE_NORMALMAP_OBJECTSPACE +vec3 nonPerturbedNormal = normal;`,Ou=`#ifdef USE_NORMALMAP_OBJECTSPACE normal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; #ifdef FLIP_SIDED normal = - normal; @@ -1531,25 +1531,25 @@ vec3 nonPerturbedNormal = normal;`,qu=`#ifdef USE_NORMALMAP_OBJECTSPACE normal = normalize( tbn * mapN ); #elif defined( USE_BUMPMAP ) normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); -#endif`,Yu=`#ifndef FLAT_SHADED +#endif`,Bu=`#ifndef FLAT_SHADED varying vec3 vNormal; #ifdef USE_TANGENT varying vec3 vTangent; varying vec3 vBitangent; #endif -#endif`,$u=`#ifndef FLAT_SHADED +#endif`,Hu=`#ifndef FLAT_SHADED varying vec3 vNormal; #ifdef USE_TANGENT varying vec3 vTangent; varying vec3 vBitangent; #endif -#endif`,Ku=`#ifndef FLAT_SHADED +#endif`,zu=`#ifndef FLAT_SHADED vNormal = normalize( transformedNormal ); #ifdef USE_TANGENT vTangent = normalize( transformedTangent ); vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); #endif -#endif`,Zu=`#ifdef USE_NORMALMAP +#endif`,Gu=`#ifdef USE_NORMALMAP uniform sampler2D normalMap; uniform vec2 normalScale; #endif @@ -1571,13 +1571,13 @@ vec3 nonPerturbedNormal = normal;`,qu=`#ifdef USE_NORMALMAP_OBJECTSPACE float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det ); return mat3( T * scale, B * scale, N ); } -#endif`,ju=`#ifdef USE_CLEARCOAT +#endif`,ku=`#ifdef USE_CLEARCOAT vec3 clearcoatNormal = nonPerturbedNormal; -#endif`,Ju=`#ifdef USE_CLEARCOAT_NORMALMAP +#endif`,Vu=`#ifdef USE_CLEARCOAT_NORMALMAP vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0; clearcoatMapN.xy *= clearcoatNormalScale; clearcoatNormal = normalize( tbn2 * clearcoatMapN ); -#endif`,Qu=`#ifdef USE_CLEARCOATMAP +#endif`,Wu=`#ifdef USE_CLEARCOATMAP uniform sampler2D clearcoatMap; #endif #ifdef USE_CLEARCOAT_NORMALMAP @@ -1586,18 +1586,18 @@ vec3 nonPerturbedNormal = normal;`,qu=`#ifdef USE_NORMALMAP_OBJECTSPACE #endif #ifdef USE_CLEARCOAT_ROUGHNESSMAP uniform sampler2D clearcoatRoughnessMap; -#endif`,eh=`#ifdef USE_IRIDESCENCEMAP +#endif`,Xu=`#ifdef USE_IRIDESCENCEMAP uniform sampler2D iridescenceMap; #endif #ifdef USE_IRIDESCENCE_THICKNESSMAP uniform sampler2D iridescenceThicknessMap; -#endif`,th=`#ifdef OPAQUE +#endif`,qu=`#ifdef OPAQUE diffuseColor.a = 1.0; #endif #ifdef USE_TRANSMISSION diffuseColor.a *= material.transmissionAlpha; #endif -gl_FragColor = vec4( outgoingLight, diffuseColor.a );`,nh=`vec3 packNormalToRGB( const in vec3 normal ) { +gl_FragColor = vec4( outgoingLight, diffuseColor.a );`,Yu=`vec3 packNormalToRGB( const in vec3 normal ) { return normalize( normal ) * 0.5 + 0.5; } vec3 unpackRGBToNormal( const in vec3 rgb ) { @@ -1666,9 +1666,9 @@ float viewZToPerspectiveDepth( const in float viewZ, const in float near, const } float perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) { return ( near * far ) / ( ( far - near ) * depth - far ); -}`,ih=`#ifdef PREMULTIPLIED_ALPHA +}`,$u=`#ifdef PREMULTIPLIED_ALPHA gl_FragColor.rgb *= gl_FragColor.a; -#endif`,rh=`vec4 mvPosition = vec4( transformed, 1.0 ); +#endif`,Ku=`vec4 mvPosition = vec4( transformed, 1.0 ); #ifdef USE_BATCHING mvPosition = batchingMatrix * mvPosition; #endif @@ -1676,22 +1676,22 @@ float perspectiveDepthToViewZ( const in float depth, const in float near, const mvPosition = instanceMatrix * mvPosition; #endif mvPosition = modelViewMatrix * mvPosition; -gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING +gl_Position = projectionMatrix * mvPosition;`,Zu=`#ifdef DITHERING gl_FragColor.rgb = dithering( gl_FragColor.rgb ); -#endif`,ah=`#ifdef DITHERING +#endif`,ju=`#ifdef DITHERING vec3 dithering( vec3 color ) { float grid_position = rand( gl_FragCoord.xy ); vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 ); dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position ); return color + dither_shift_RGB; } -#endif`,oh=`float roughnessFactor = roughness; +#endif`,Ju=`float roughnessFactor = roughness; #ifdef USE_ROUGHNESSMAP vec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv ); roughnessFactor *= texelRoughness.g; -#endif`,ch=`#ifdef USE_ROUGHNESSMAP +#endif`,Qu=`#ifdef USE_ROUGHNESSMAP uniform sampler2D roughnessMap; -#endif`,lh=`#if NUM_SPOT_LIGHT_COORDS > 0 +#endif`,eh=`#if NUM_SPOT_LIGHT_COORDS > 0 varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; #endif #if NUM_SPOT_LIGHT_MAPS > 0 @@ -1886,7 +1886,7 @@ gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING } return mix( 1.0, shadow, shadowIntensity ); } -#endif`,uh=`#if NUM_SPOT_LIGHT_COORDS > 0 +#endif`,th=`#if NUM_SPOT_LIGHT_COORDS > 0 uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ]; varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; #endif @@ -1927,7 +1927,7 @@ gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING }; uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; #endif -#endif`,hh=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) +#endif`,nh=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) vec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); vec4 shadowWorldPosition; #endif @@ -1959,7 +1959,7 @@ gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition; } #pragma unroll_loop_end -#endif`,dh=`float getShadowMask() { +#endif`,ih=`float getShadowMask() { float shadow = 1.0; #ifdef USE_SHADOWMAP #if NUM_DIR_LIGHT_SHADOWS > 0 @@ -1991,12 +1991,12 @@ gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING #endif #endif return shadow; -}`,fh=`#ifdef USE_SKINNING +}`,rh=`#ifdef USE_SKINNING mat4 boneMatX = getBoneMatrix( skinIndex.x ); mat4 boneMatY = getBoneMatrix( skinIndex.y ); mat4 boneMatZ = getBoneMatrix( skinIndex.z ); mat4 boneMatW = getBoneMatrix( skinIndex.w ); -#endif`,ph=`#ifdef USE_SKINNING +#endif`,sh=`#ifdef USE_SKINNING uniform mat4 bindMatrix; uniform mat4 bindMatrixInverse; uniform highp sampler2D boneTexture; @@ -2011,7 +2011,7 @@ gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING vec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 ); return mat4( v1, v2, v3, v4 ); } -#endif`,mh=`#ifdef USE_SKINNING +#endif`,ah=`#ifdef USE_SKINNING vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); vec4 skinned = vec4( 0.0 ); skinned += boneMatX * skinVertex * skinWeight.x; @@ -2019,7 +2019,7 @@ gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING skinned += boneMatZ * skinVertex * skinWeight.z; skinned += boneMatW * skinVertex * skinWeight.w; transformed = ( bindMatrixInverse * skinned ).xyz; -#endif`,gh=`#ifdef USE_SKINNING +#endif`,oh=`#ifdef USE_SKINNING mat4 skinMatrix = mat4( 0.0 ); skinMatrix += skinWeight.x * boneMatX; skinMatrix += skinWeight.y * boneMatY; @@ -2030,17 +2030,17 @@ gl_Position = projectionMatrix * mvPosition;`,sh=`#ifdef DITHERING #ifdef USE_TANGENT objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; #endif -#endif`,_h=`float specularStrength; +#endif`,lh=`float specularStrength; #ifdef USE_SPECULARMAP vec4 texelSpecular = texture2D( specularMap, vSpecularMapUv ); specularStrength = texelSpecular.r; #else specularStrength = 1.0; -#endif`,vh=`#ifdef USE_SPECULARMAP +#endif`,ch=`#ifdef USE_SPECULARMAP uniform sampler2D specularMap; -#endif`,xh=`#if defined( TONE_MAPPING ) +#endif`,uh=`#if defined( TONE_MAPPING ) gl_FragColor.rgb = toneMapping( gl_FragColor.rgb ); -#endif`,Mh=`#ifndef saturate +#endif`,hh=`#ifndef saturate #define saturate( a ) clamp( a, 0.0, 1.0 ) #endif uniform float toneMappingExposure; @@ -2137,7 +2137,7 @@ vec3 NeutralToneMapping( vec3 color ) { float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. ); return mix( color, vec3( newPeak ), g ); } -vec3 CustomToneMapping( vec3 color ) { return color; }`,Sh=`#ifdef USE_TRANSMISSION +vec3 CustomToneMapping( vec3 color ) { return color; }`,dh=`#ifdef USE_TRANSMISSION material.transmission = transmission; material.transmissionAlpha = 1.0; material.thickness = thickness; @@ -2158,7 +2158,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,Sh=`#ifdef USE_TRANSMISS material.attenuationColor, material.attenuationDistance ); material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission ); totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission ); -#endif`,Eh=`#ifdef USE_TRANSMISSION +#endif`,fh=`#ifdef USE_TRANSMISSION uniform float transmission; uniform float thickness; uniform float attenuationDistance; @@ -2284,7 +2284,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,Sh=`#ifdef USE_TRANSMISS float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; return vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor ); } -#endif`,yh=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) +#endif`,ph=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) varying vec2 vUv; #endif #ifdef USE_MAP @@ -2354,7 +2354,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,Sh=`#ifdef USE_TRANSMISS #ifdef USE_THICKNESSMAP uniform mat3 thicknessMapTransform; varying vec2 vThicknessMapUv; -#endif`,Th=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) +#endif`,mh=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) varying vec2 vUv; #endif #ifdef USE_MAP @@ -2448,7 +2448,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,Sh=`#ifdef USE_TRANSMISS #ifdef USE_THICKNESSMAP uniform mat3 thicknessMapTransform; varying vec2 vThicknessMapUv; -#endif`,Ah=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) +#endif`,gh=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) vUv = vec3( uv, 1 ).xy; #endif #ifdef USE_MAP @@ -2519,7 +2519,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,Sh=`#ifdef USE_TRANSMISS #endif #ifdef USE_THICKNESSMAP vThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy; -#endif`,bh=`#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 +#endif`,_h=`#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 vec4 worldPosition = vec4( transformed, 1.0 ); #ifdef USE_BATCHING worldPosition = batchingMatrix * worldPosition; @@ -2528,12 +2528,12 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,Sh=`#ifdef USE_TRANSMISS worldPosition = instanceMatrix * worldPosition; #endif worldPosition = modelMatrix * worldPosition; -#endif`;const wh=`varying vec2 vUv; +#endif`;const vh=`varying vec2 vUv; uniform mat3 uvTransform; void main() { vUv = ( uvTransform * vec3( uv, 1 ) ).xy; gl_Position = vec4( position.xy, 1.0, 1.0 ); -}`,Rh=`uniform sampler2D t2D; +}`,xh=`uniform sampler2D t2D; uniform float backgroundIntensity; varying vec2 vUv; void main() { @@ -2545,14 +2545,14 @@ void main() { gl_FragColor = texColor; #include #include -}`,Ch=`varying vec3 vWorldDirection; +}`,Mh=`varying vec3 vWorldDirection; #include void main() { vWorldDirection = transformDirection( position, modelMatrix ); #include #include gl_Position.z = gl_Position.w; -}`,Ph=`#ifdef ENVMAP_TYPE_CUBE +}`,Sh=`#ifdef ENVMAP_TYPE_CUBE uniform samplerCube envMap; #elif defined( ENVMAP_TYPE_CUBE_UV ) uniform sampler2D envMap; @@ -2575,14 +2575,14 @@ void main() { gl_FragColor = texColor; #include #include -}`,Dh=`varying vec3 vWorldDirection; +}`,Eh=`varying vec3 vWorldDirection; #include void main() { vWorldDirection = transformDirection( position, modelMatrix ); #include #include gl_Position.z = gl_Position.w; -}`,Lh=`uniform samplerCube tCube; +}`,yh=`uniform samplerCube tCube; uniform float tFlip; uniform float opacity; varying vec3 vWorldDirection; @@ -2592,7 +2592,7 @@ void main() { gl_FragColor.a *= opacity; #include #include -}`,Ih=`#include +}`,Th=`#include #include #include #include @@ -2619,7 +2619,7 @@ void main() { #include #include vHighPrecisionZW = gl_Position.zw; -}`,Uh=`#if DEPTH_PACKING == 3200 +}`,Ah=`#if DEPTH_PACKING == 3200 uniform float opacity; #endif #include @@ -2657,7 +2657,7 @@ void main() { #elif DEPTH_PACKING == 3203 gl_FragColor = vec4( packDepthToRG( fragCoordZ ), 0.0, 1.0 ); #endif -}`,Nh=`#define DISTANCE +}`,bh=`#define DISTANCE varying vec3 vWorldPosition; #include #include @@ -2684,7 +2684,7 @@ void main() { #include #include vWorldPosition = worldPosition.xyz; -}`,Fh=`#define DISTANCE +}`,wh=`#define DISTANCE uniform vec3 referencePosition; uniform float nearDistance; uniform float farDistance; @@ -2708,13 +2708,13 @@ void main () { dist = ( dist - nearDistance ) / ( farDistance - nearDistance ); dist = saturate( dist ); gl_FragColor = packDepthToRGBA( dist ); -}`,Oh=`varying vec3 vWorldDirection; +}`,Rh=`varying vec3 vWorldDirection; #include void main() { vWorldDirection = transformDirection( position, modelMatrix ); #include #include -}`,Bh=`uniform sampler2D tEquirect; +}`,Ch=`uniform sampler2D tEquirect; varying vec3 vWorldDirection; #include void main() { @@ -2723,7 +2723,7 @@ void main() { gl_FragColor = texture2D( tEquirect, sampleUV ); #include #include -}`,zh=`uniform float scale; +}`,Ph=`uniform float scale; attribute float lineDistance; varying float vLineDistance; #include @@ -2745,7 +2745,7 @@ void main() { #include #include #include -}`,Hh=`uniform vec3 diffuse; +}`,Dh=`uniform vec3 diffuse; uniform float opacity; uniform float dashSize; uniform float totalSize; @@ -2773,7 +2773,7 @@ void main() { #include #include #include -}`,Gh=`#include +}`,Lh=`#include #include #include #include @@ -2805,7 +2805,7 @@ void main() { #include #include #include -}`,Vh=`uniform vec3 diffuse; +}`,Ih=`uniform vec3 diffuse; uniform float opacity; #ifndef FLAT_SHADED varying vec3 vNormal; @@ -2853,7 +2853,7 @@ void main() { #include #include #include -}`,kh=`#define LAMBERT +}`,Uh=`#define LAMBERT varying vec3 vViewPosition; #include #include @@ -2892,7 +2892,7 @@ void main() { #include #include #include -}`,Wh=`#define LAMBERT +}`,Nh=`#define LAMBERT uniform vec3 diffuse; uniform vec3 emissive; uniform float opacity; @@ -2949,7 +2949,7 @@ void main() { #include #include #include -}`,Xh=`#define MATCAP +}`,Fh=`#define MATCAP varying vec3 vViewPosition; #include #include @@ -2983,7 +2983,7 @@ void main() { #include #include vViewPosition = - mvPosition.xyz; -}`,qh=`#define MATCAP +}`,Oh=`#define MATCAP uniform vec3 diffuse; uniform float opacity; uniform sampler2D matcap; @@ -3029,7 +3029,7 @@ void main() { #include #include #include -}`,Yh=`#define NORMAL +}`,Bh=`#define NORMAL #if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) varying vec3 vViewPosition; #endif @@ -3062,7 +3062,7 @@ void main() { #if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) vViewPosition = - mvPosition.xyz; #endif -}`,$h=`#define NORMAL +}`,Hh=`#define NORMAL uniform float opacity; #if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) varying vec3 vViewPosition; @@ -3084,7 +3084,7 @@ void main() { #ifdef OPAQUE gl_FragColor.a = 1.0; #endif -}`,Kh=`#define PHONG +}`,zh=`#define PHONG varying vec3 vViewPosition; #include #include @@ -3123,7 +3123,7 @@ void main() { #include #include #include -}`,Zh=`#define PHONG +}`,Gh=`#define PHONG uniform vec3 diffuse; uniform vec3 emissive; uniform vec3 specular; @@ -3182,7 +3182,7 @@ void main() { #include #include #include -}`,jh=`#define STANDARD +}`,kh=`#define STANDARD varying vec3 vViewPosition; #ifdef USE_TRANSMISSION varying vec3 vWorldPosition; @@ -3225,7 +3225,7 @@ void main() { #ifdef USE_TRANSMISSION vWorldPosition = worldPosition.xyz; #endif -}`,Jh=`#define STANDARD +}`,Vh=`#define STANDARD #ifdef PHYSICAL #define IOR #define USE_SPECULAR @@ -3350,7 +3350,7 @@ void main() { #include #include #include -}`,Qh=`#define TOON +}`,Wh=`#define TOON varying vec3 vViewPosition; #include #include @@ -3387,7 +3387,7 @@ void main() { #include #include #include -}`,ed=`#define TOON +}`,Xh=`#define TOON uniform vec3 diffuse; uniform vec3 emissive; uniform float opacity; @@ -3440,7 +3440,7 @@ void main() { #include #include #include -}`,td=`uniform float size; +}`,qh=`uniform float size; uniform float scale; #include #include @@ -3471,7 +3471,7 @@ void main() { #include #include #include -}`,nd=`uniform vec3 diffuse; +}`,Yh=`uniform vec3 diffuse; uniform float opacity; #include #include @@ -3496,7 +3496,7 @@ void main() { #include #include #include -}`,id=`#include +}`,$h=`#include #include #include #include @@ -3519,7 +3519,7 @@ void main() { #include #include #include -}`,rd=`uniform vec3 color; +}`,Kh=`uniform vec3 color; uniform float opacity; #include #include @@ -3535,7 +3535,7 @@ void main() { #include #include #include -}`,sd=`uniform float rotation; +}`,Zh=`uniform float rotation; uniform vec2 center; #include #include @@ -3559,7 +3559,7 @@ void main() { #include #include #include -}`,ad=`uniform vec3 diffuse; +}`,jh=`uniform vec3 diffuse; uniform float opacity; #include #include @@ -3584,7 +3584,7 @@ void main() { #include #include #include -}`,Ne={alphahash_fragment:Rl,alphahash_pars_fragment:Cl,alphamap_fragment:Pl,alphamap_pars_fragment:Dl,alphatest_fragment:Ll,alphatest_pars_fragment:Il,aomap_fragment:Ul,aomap_pars_fragment:Nl,batching_pars_vertex:Fl,batching_vertex:Ol,begin_vertex:Bl,beginnormal_vertex:zl,bsdfs:Hl,iridescence_fragment:Gl,bumpmap_pars_fragment:Vl,clipping_planes_fragment:kl,clipping_planes_pars_fragment:Wl,clipping_planes_pars_vertex:Xl,clipping_planes_vertex:ql,color_fragment:Yl,color_pars_fragment:$l,color_pars_vertex:Kl,color_vertex:Zl,common:jl,cube_uv_reflection_fragment:Jl,defaultnormal_vertex:Ql,displacementmap_pars_vertex:eu,displacementmap_vertex:tu,emissivemap_fragment:nu,emissivemap_pars_fragment:iu,colorspace_fragment:ru,colorspace_pars_fragment:su,envmap_fragment:au,envmap_common_pars_fragment:ou,envmap_pars_fragment:cu,envmap_pars_vertex:lu,envmap_physical_pars_fragment:Mu,envmap_vertex:uu,fog_vertex:hu,fog_pars_vertex:du,fog_fragment:fu,fog_pars_fragment:pu,gradientmap_pars_fragment:mu,lightmap_pars_fragment:gu,lights_lambert_fragment:_u,lights_lambert_pars_fragment:vu,lights_pars_begin:xu,lights_toon_fragment:Su,lights_toon_pars_fragment:Eu,lights_phong_fragment:yu,lights_phong_pars_fragment:Tu,lights_physical_fragment:Au,lights_physical_pars_fragment:bu,lights_fragment_begin:wu,lights_fragment_maps:Ru,lights_fragment_end:Cu,logdepthbuf_fragment:Pu,logdepthbuf_pars_fragment:Du,logdepthbuf_pars_vertex:Lu,logdepthbuf_vertex:Iu,map_fragment:Uu,map_pars_fragment:Nu,map_particle_fragment:Fu,map_particle_pars_fragment:Ou,metalnessmap_fragment:Bu,metalnessmap_pars_fragment:zu,morphinstance_vertex:Hu,morphcolor_vertex:Gu,morphnormal_vertex:Vu,morphtarget_pars_vertex:ku,morphtarget_vertex:Wu,normal_fragment_begin:Xu,normal_fragment_maps:qu,normal_pars_fragment:Yu,normal_pars_vertex:$u,normal_vertex:Ku,normalmap_pars_fragment:Zu,clearcoat_normal_fragment_begin:ju,clearcoat_normal_fragment_maps:Ju,clearcoat_pars_fragment:Qu,iridescence_pars_fragment:eh,opaque_fragment:th,packing:nh,premultiplied_alpha_fragment:ih,project_vertex:rh,dithering_fragment:sh,dithering_pars_fragment:ah,roughnessmap_fragment:oh,roughnessmap_pars_fragment:ch,shadowmap_pars_fragment:lh,shadowmap_pars_vertex:uh,shadowmap_vertex:hh,shadowmask_pars_fragment:dh,skinbase_vertex:fh,skinning_pars_vertex:ph,skinning_vertex:mh,skinnormal_vertex:gh,specularmap_fragment:_h,specularmap_pars_fragment:vh,tonemapping_fragment:xh,tonemapping_pars_fragment:Mh,transmission_fragment:Sh,transmission_pars_fragment:Eh,uv_pars_fragment:yh,uv_pars_vertex:Th,uv_vertex:Ah,worldpos_vertex:bh,background_vert:wh,background_frag:Rh,backgroundCube_vert:Ch,backgroundCube_frag:Ph,cube_vert:Dh,cube_frag:Lh,depth_vert:Ih,depth_frag:Uh,distanceRGBA_vert:Nh,distanceRGBA_frag:Fh,equirect_vert:Oh,equirect_frag:Bh,linedashed_vert:zh,linedashed_frag:Hh,meshbasic_vert:Gh,meshbasic_frag:Vh,meshlambert_vert:kh,meshlambert_frag:Wh,meshmatcap_vert:Xh,meshmatcap_frag:qh,meshnormal_vert:Yh,meshnormal_frag:$h,meshphong_vert:Kh,meshphong_frag:Zh,meshphysical_vert:jh,meshphysical_frag:Jh,meshtoon_vert:Qh,meshtoon_frag:ed,points_vert:td,points_frag:nd,shadow_vert:id,shadow_frag:rd,sprite_vert:sd,sprite_frag:ad},re={common:{diffuse:{value:new Fe(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new Ie},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new Ie}},envmap:{envMap:{value:null},envMapRotation:{value:new Ie},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new Ie}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new Ie}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new Ie},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new Ie},normalScale:{value:new Ge(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new Ie},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new Ie}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new Ie}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new Ie}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Fe(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new Fe(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0},uvTransform:{value:new Ie}},sprite:{diffuse:{value:new Fe(16777215)},opacity:{value:1},center:{value:new Ge(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new Ie},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0}}},Vt={basic:{uniforms:xt([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.fog]),vertexShader:Ne.meshbasic_vert,fragmentShader:Ne.meshbasic_frag},lambert:{uniforms:xt([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.fog,re.lights,{emissive:{value:new Fe(0)}}]),vertexShader:Ne.meshlambert_vert,fragmentShader:Ne.meshlambert_frag},phong:{uniforms:xt([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.fog,re.lights,{emissive:{value:new Fe(0)},specular:{value:new Fe(1118481)},shininess:{value:30}}]),vertexShader:Ne.meshphong_vert,fragmentShader:Ne.meshphong_frag},standard:{uniforms:xt([re.common,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.roughnessmap,re.metalnessmap,re.fog,re.lights,{emissive:{value:new Fe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:Ne.meshphysical_vert,fragmentShader:Ne.meshphysical_frag},toon:{uniforms:xt([re.common,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.gradientmap,re.fog,re.lights,{emissive:{value:new Fe(0)}}]),vertexShader:Ne.meshtoon_vert,fragmentShader:Ne.meshtoon_frag},matcap:{uniforms:xt([re.common,re.bumpmap,re.normalmap,re.displacementmap,re.fog,{matcap:{value:null}}]),vertexShader:Ne.meshmatcap_vert,fragmentShader:Ne.meshmatcap_frag},points:{uniforms:xt([re.points,re.fog]),vertexShader:Ne.points_vert,fragmentShader:Ne.points_frag},dashed:{uniforms:xt([re.common,re.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:Ne.linedashed_vert,fragmentShader:Ne.linedashed_frag},depth:{uniforms:xt([re.common,re.displacementmap]),vertexShader:Ne.depth_vert,fragmentShader:Ne.depth_frag},normal:{uniforms:xt([re.common,re.bumpmap,re.normalmap,re.displacementmap,{opacity:{value:1}}]),vertexShader:Ne.meshnormal_vert,fragmentShader:Ne.meshnormal_frag},sprite:{uniforms:xt([re.sprite,re.fog]),vertexShader:Ne.sprite_vert,fragmentShader:Ne.sprite_frag},background:{uniforms:{uvTransform:{value:new Ie},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:Ne.background_vert,fragmentShader:Ne.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new Ie}},vertexShader:Ne.backgroundCube_vert,fragmentShader:Ne.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:Ne.cube_vert,fragmentShader:Ne.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:Ne.equirect_vert,fragmentShader:Ne.equirect_frag},distanceRGBA:{uniforms:xt([re.common,re.displacementmap,{referencePosition:{value:new N},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:Ne.distanceRGBA_vert,fragmentShader:Ne.distanceRGBA_frag},shadow:{uniforms:xt([re.lights,re.fog,{color:{value:new Fe(0)},opacity:{value:1}}]),vertexShader:Ne.shadow_vert,fragmentShader:Ne.shadow_frag}};Vt.physical={uniforms:xt([Vt.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new Ie},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new Ie},clearcoatNormalScale:{value:new Ge(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new Ie},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new Ie},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new Ie},sheen:{value:0},sheenColor:{value:new Fe(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new Ie},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new Ie},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new Ie},transmissionSamplerSize:{value:new Ge},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new Ie},attenuationDistance:{value:0},attenuationColor:{value:new Fe(0)},specularColor:{value:new Fe(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new Ie},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new Ie},anisotropyVector:{value:new Ge},anisotropyMap:{value:null},anisotropyMapTransform:{value:new Ie}}]),vertexShader:Ne.meshphysical_vert,fragmentShader:Ne.meshphysical_frag};const Zi={r:0,b:0,g:0},En=new $t,od=new it;function cd(i,e,t,n,r,s,a){const o=new Fe(0);let l=s===!0?0:1,c,d,h=null,f=0,m=null;function _(A){let E=A.isScene===!0?A.background:null;return E&&E.isTexture&&(E=(A.backgroundBlurriness>0?t:e).get(E)),E}function x(A){let E=!1;const C=_(A);C===null?u(o,l):C&&C.isColor&&(u(C,1),E=!0);const R=i.xr.getEnvironmentBlendMode();R==="additive"?n.buffers.color.setClear(0,0,0,1,a):R==="alpha-blend"&&n.buffers.color.setClear(0,0,0,0,a),(i.autoClear||E)&&(n.buffers.depth.setTest(!0),n.buffers.depth.setMask(!0),n.buffers.color.setMask(!0),i.clear(i.autoClearColor,i.autoClearDepth,i.autoClearStencil))}function p(A,E){const C=_(E);C&&(C.isCubeTexture||C.mapping===dr)?(d===void 0&&(d=new Et(new yi(1,1,1),new mn({name:"BackgroundCubeMaterial",uniforms:ei(Vt.backgroundCube.uniforms),vertexShader:Vt.backgroundCube.vertexShader,fragmentShader:Vt.backgroundCube.fragmentShader,side:yt,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),d.geometry.deleteAttribute("normal"),d.geometry.deleteAttribute("uv"),d.onBeforeRender=function(R,w,U){this.matrixWorld.copyPosition(U.matrixWorld)},Object.defineProperty(d.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),r.update(d)),En.copy(E.backgroundRotation),En.x*=-1,En.y*=-1,En.z*=-1,C.isCubeTexture&&C.isRenderTargetTexture===!1&&(En.y*=-1,En.z*=-1),d.material.uniforms.envMap.value=C,d.material.uniforms.flipEnvMap.value=C.isCubeTexture&&C.isRenderTargetTexture===!1?-1:1,d.material.uniforms.backgroundBlurriness.value=E.backgroundBlurriness,d.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,d.material.uniforms.backgroundRotation.value.setFromMatrix4(od.makeRotationFromEuler(En)),d.material.toneMapped=ke.getTransfer(C.colorSpace)!==Ye,(h!==C||f!==C.version||m!==i.toneMapping)&&(d.material.needsUpdate=!0,h=C,f=C.version,m=i.toneMapping),d.layers.enableAll(),A.unshift(d,d.geometry,d.material,0,0,null)):C&&C.isTexture&&(c===void 0&&(c=new Et(new Ti(2,2),new mn({name:"BackgroundMaterial",uniforms:ei(Vt.background.uniforms),vertexShader:Vt.background.vertexShader,fragmentShader:Vt.background.fragmentShader,side:pn,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),c.geometry.deleteAttribute("normal"),Object.defineProperty(c.material,"map",{get:function(){return this.uniforms.t2D.value}}),r.update(c)),c.material.uniforms.t2D.value=C,c.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,c.material.toneMapped=ke.getTransfer(C.colorSpace)!==Ye,C.matrixAutoUpdate===!0&&C.updateMatrix(),c.material.uniforms.uvTransform.value.copy(C.matrix),(h!==C||f!==C.version||m!==i.toneMapping)&&(c.material.needsUpdate=!0,h=C,f=C.version,m=i.toneMapping),c.layers.enableAll(),A.unshift(c,c.geometry,c.material,0,0,null))}function u(A,E){A.getRGB(Zi,Lo(i)),n.buffers.color.setClear(Zi.r,Zi.g,Zi.b,E,a)}function b(){d!==void 0&&(d.geometry.dispose(),d.material.dispose(),d=void 0),c!==void 0&&(c.geometry.dispose(),c.material.dispose(),c=void 0)}return{getClearColor:function(){return o},setClearColor:function(A,E=1){o.set(A),l=E,u(o,l)},getClearAlpha:function(){return l},setClearAlpha:function(A){l=A,u(o,l)},render:x,addToRenderList:p,dispose:b}}function ld(i,e){const t=i.getParameter(i.MAX_VERTEX_ATTRIBS),n={},r=f(null);let s=r,a=!1;function o(M,P,O,H,q){let W=!1;const X=h(H,O,P);s!==X&&(s=X,c(s.object)),W=m(M,H,O,q),W&&_(M,H,O,q),q!==null&&e.update(q,i.ELEMENT_ARRAY_BUFFER),(W||a)&&(a=!1,E(M,P,O,H),q!==null&&i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,e.get(q).buffer))}function l(){return i.createVertexArray()}function c(M){return i.bindVertexArray(M)}function d(M){return i.deleteVertexArray(M)}function h(M,P,O){const H=O.wireframe===!0;let q=n[M.id];q===void 0&&(q={},n[M.id]=q);let W=q[P.id];W===void 0&&(W={},q[P.id]=W);let X=W[H];return X===void 0&&(X=f(l()),W[H]=X),X}function f(M){const P=[],O=[],H=[];for(let q=0;q=0){const le=q[G];let Ee=W[G];if(Ee===void 0&&(G==="instanceMatrix"&&M.instanceMatrix&&(Ee=M.instanceMatrix),G==="instanceColor"&&M.instanceColor&&(Ee=M.instanceColor)),le===void 0||le.attribute!==Ee||Ee&&le.data!==Ee.data)return!0;X++}return s.attributesNum!==X||s.index!==H}function _(M,P,O,H){const q={},W=P.attributes;let X=0;const Z=O.getAttributes();for(const G in Z)if(Z[G].location>=0){let le=W[G];le===void 0&&(G==="instanceMatrix"&&M.instanceMatrix&&(le=M.instanceMatrix),G==="instanceColor"&&M.instanceColor&&(le=M.instanceColor));const Ee={};Ee.attribute=le,le&&le.data&&(Ee.data=le.data),q[G]=Ee,X++}s.attributes=q,s.attributesNum=X,s.index=H}function x(){const M=s.newAttributes;for(let P=0,O=M.length;P=0){let se=q[Z];if(se===void 0&&(Z==="instanceMatrix"&&M.instanceMatrix&&(se=M.instanceMatrix),Z==="instanceColor"&&M.instanceColor&&(se=M.instanceColor)),se!==void 0){const le=se.normalized,Ee=se.itemSize,Oe=e.get(se);if(Oe===void 0)continue;const Ke=Oe.buffer,Je=Oe.type,We=Oe.bytesPerElement,Y=Je===i.INT||Je===i.UNSIGNED_INT||se.gpuType===Vs;if(se.isInterleavedBufferAttribute){const j=se.data,de=j.stride,Ce=se.offset;if(j.isInstancedInterleavedBuffer){for(let Se=0;Se0&&i.getShaderPrecisionFormat(i.FRAGMENT_SHADER,i.HIGH_FLOAT).precision>0)return"highp";w="mediump"}return w==="mediump"&&i.getShaderPrecisionFormat(i.VERTEX_SHADER,i.MEDIUM_FLOAT).precision>0&&i.getShaderPrecisionFormat(i.FRAGMENT_SHADER,i.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let c=t.precision!==void 0?t.precision:"highp";const d=l(c);d!==c&&(console.warn("THREE.WebGLRenderer:",c,"not supported, using",d,"instead."),c=d);const h=t.logarithmicDepthBuffer===!0,f=t.reversedDepthBuffer===!0&&e.has("EXT_clip_control"),m=i.getParameter(i.MAX_TEXTURE_IMAGE_UNITS),_=i.getParameter(i.MAX_VERTEX_TEXTURE_IMAGE_UNITS),x=i.getParameter(i.MAX_TEXTURE_SIZE),p=i.getParameter(i.MAX_CUBE_MAP_TEXTURE_SIZE),u=i.getParameter(i.MAX_VERTEX_ATTRIBS),b=i.getParameter(i.MAX_VERTEX_UNIFORM_VECTORS),A=i.getParameter(i.MAX_VARYING_VECTORS),E=i.getParameter(i.MAX_FRAGMENT_UNIFORM_VECTORS),C=_>0,R=i.getParameter(i.MAX_SAMPLES);return{isWebGL2:!0,getMaxAnisotropy:s,getMaxPrecision:l,textureFormatReadable:a,textureTypeReadable:o,precision:c,logarithmicDepthBuffer:h,reversedDepthBuffer:f,maxTextures:m,maxVertexTextures:_,maxTextureSize:x,maxCubemapSize:p,maxAttributes:u,maxVertexUniforms:b,maxVaryings:A,maxFragmentUniforms:E,vertexTextures:C,maxSamples:R}}function dd(i){const e=this;let t=null,n=0,r=!1,s=!1;const a=new Tn,o=new Ie,l={value:null,needsUpdate:!1};this.uniform=l,this.numPlanes=0,this.numIntersection=0,this.init=function(h,f){const m=h.length!==0||f||n!==0||r;return r=f,n=h.length,m},this.beginShadows=function(){s=!0,d(null)},this.endShadows=function(){s=!1},this.setGlobalState=function(h,f){t=d(h,f,0)},this.setState=function(h,f,m){const _=h.clippingPlanes,x=h.clipIntersection,p=h.clipShadows,u=i.get(h);if(!r||_===null||_.length===0||s&&!p)s?d(null):c();else{const b=s?0:n,A=b*4;let E=u.clippingState||null;l.value=E,E=d(_,f,A,m);for(let C=0;C!==A;++C)E[C]=t[C];u.clippingState=E,this.numIntersection=x?this.numPlanes:0,this.numPlanes+=b}};function c(){l.value!==t&&(l.value=t,l.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function d(h,f,m,_){const x=h!==null?h.length:0;let p=null;if(x!==0){if(p=l.value,_!==!0||p===null){const u=m+x*4,b=f.matrixWorldInverse;o.getNormalMatrix(b),(p===null||p.length0){const c=new cl(l.height);return c.fromEquirectangularTexture(i,a),e.set(a,c),a.addEventListener("dispose",r),t(c.texture,a.mapping)}else return null}}return a}function r(a){const o=a.target;o.removeEventListener("dispose",r);const l=e.get(o);l!==void 0&&(e.delete(o),l.dispose())}function s(){e=new WeakMap}return{get:n,dispose:s}}const Yn=4,Ga=[.125,.215,.35,.446,.526,.582],wn=20,Wr=new Bo,Va=new Fe;let Xr=null,qr=0,Yr=0,$r=!1;const An=(1+Math.sqrt(5))/2,qn=1/An,ka=[new N(-An,qn,0),new N(An,qn,0),new N(-qn,0,An),new N(qn,0,An),new N(0,An,-qn),new N(0,An,qn),new N(-1,1,-1),new N(1,1,-1),new N(-1,1,1),new N(1,1,1)],pd=new N;class Wa{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(e,t=0,n=.1,r=100,s={}){const{size:a=256,position:o=pd}=s;Xr=this._renderer.getRenderTarget(),qr=this._renderer.getActiveCubeFace(),Yr=this._renderer.getActiveMipmapLevel(),$r=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(a);const l=this._allocateTargets();return l.depthBuffer=!0,this._sceneToCubeUV(e,n,r,l,o),t>0&&this._blur(l,0,0,t),this._applyPMREM(l),this._cleanup(l),l}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=Ya(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=qa(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),this._cubemapMaterial!==null&&this._cubemapMaterial.dispose(),this._equirectMaterial!==null&&this._equirectMaterial.dispose()}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){this._blurMaterial!==null&&this._blurMaterial.dispose(),this._pingPongRenderTarget!==null&&this._pingPongRenderTarget.dispose();for(let e=0;e2?C:0,C,C),h.setRenderTarget(r),u&&h.render(p,l),h.render(e,l)}p.geometry.dispose(),p.material.dispose(),h.toneMapping=m,h.autoClear=f,e.background=b}_textureToCubeUV(e,t){const n=this._renderer,r=e.mapping===jn||e.mapping===Jn;r?(this._cubemapMaterial===null&&(this._cubemapMaterial=Ya()),this._cubemapMaterial.uniforms.flipEnvMap.value=e.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=qa());const s=r?this._cubemapMaterial:this._equirectMaterial,a=new Et(this._lodPlanes[0],s),o=s.uniforms;o.envMap.value=e;const l=this._cubeSize;ji(t,0,0,3*l,2*l),n.setRenderTarget(t),n.render(a,Wr)}_applyPMREM(e){const t=this._renderer,n=t.autoClear;t.autoClear=!1;const r=this._lodPlanes.length;for(let s=1;swn&&console.warn(`sigmaRadians, ${s}, is too large and will clip, as it requested ${p} samples when the maximum is set to ${wn}`);const u=[];let b=0;for(let w=0;wA-Yn?r-A+Yn:0),R=4*(this._cubeSize-E);ji(t,C,R,3*E,2*E),l.setRenderTarget(t),l.render(h,Wr)}}function md(i){const e=[],t=[],n=[];let r=i;const s=i-Yn+1+Ga.length;for(let a=0;ai-Yn?l=Ga[a-i+Yn-1]:a===0&&(l=0),n.push(l);const c=1/(o-2),d=-c,h=1+c,f=[d,d,h,d,h,h,d,d,h,h,d,h],m=6,_=6,x=3,p=2,u=1,b=new Float32Array(x*_*m),A=new Float32Array(p*_*m),E=new Float32Array(u*_*m);for(let R=0;R2?0:-1,S=[w,U,0,w+2/3,U,0,w+2/3,U+1,0,w,U,0,w+2/3,U+1,0,w,U+1,0];b.set(S,x*_*R),A.set(f,p*_*R);const M=[R,R,R,R,R,R];E.set(M,u*_*R)}const C=new Nt;C.setAttribute("position",new qt(b,x)),C.setAttribute("uv",new qt(A,p)),C.setAttribute("faceIndex",new qt(E,u)),e.push(C),r>Yn&&r--}return{lodPlanes:e,sizeLods:t,sigmas:n}}function Xa(i,e,t){const n=new Dn(i,e,t);return n.texture.mapping=dr,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function ji(i,e,t,n,r){i.viewport.set(e,t,n,r),i.scissor.set(e,t,n,r)}function gd(i,e,t){const n=new Float32Array(wn),r=new N(0,1,0);return new mn({name:"SphericalGaussianBlur",defines:{n:wn,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP:`${i}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:r}},vertexShader:ta(),fragmentShader:` +}`,Ne={alphahash_fragment:xc,alphahash_pars_fragment:Mc,alphamap_fragment:Sc,alphamap_pars_fragment:Ec,alphatest_fragment:yc,alphatest_pars_fragment:Tc,aomap_fragment:Ac,aomap_pars_fragment:bc,batching_pars_vertex:wc,batching_vertex:Rc,begin_vertex:Cc,beginnormal_vertex:Pc,bsdfs:Dc,iridescence_fragment:Lc,bumpmap_pars_fragment:Ic,clipping_planes_fragment:Uc,clipping_planes_pars_fragment:Nc,clipping_planes_pars_vertex:Fc,clipping_planes_vertex:Oc,color_fragment:Bc,color_pars_fragment:Hc,color_pars_vertex:zc,color_vertex:Gc,common:kc,cube_uv_reflection_fragment:Vc,defaultnormal_vertex:Wc,displacementmap_pars_vertex:Xc,displacementmap_vertex:qc,emissivemap_fragment:Yc,emissivemap_pars_fragment:$c,colorspace_fragment:Kc,colorspace_pars_fragment:Zc,envmap_fragment:jc,envmap_common_pars_fragment:Jc,envmap_pars_fragment:Qc,envmap_pars_vertex:eu,envmap_physical_pars_fragment:hu,envmap_vertex:tu,fog_vertex:nu,fog_pars_vertex:iu,fog_fragment:ru,fog_pars_fragment:su,gradientmap_pars_fragment:au,lightmap_pars_fragment:ou,lights_lambert_fragment:lu,lights_lambert_pars_fragment:cu,lights_pars_begin:uu,lights_toon_fragment:du,lights_toon_pars_fragment:fu,lights_phong_fragment:pu,lights_phong_pars_fragment:mu,lights_physical_fragment:gu,lights_physical_pars_fragment:_u,lights_fragment_begin:vu,lights_fragment_maps:xu,lights_fragment_end:Mu,logdepthbuf_fragment:Su,logdepthbuf_pars_fragment:Eu,logdepthbuf_pars_vertex:yu,logdepthbuf_vertex:Tu,map_fragment:Au,map_pars_fragment:bu,map_particle_fragment:wu,map_particle_pars_fragment:Ru,metalnessmap_fragment:Cu,metalnessmap_pars_fragment:Pu,morphinstance_vertex:Du,morphcolor_vertex:Lu,morphnormal_vertex:Iu,morphtarget_pars_vertex:Uu,morphtarget_vertex:Nu,normal_fragment_begin:Fu,normal_fragment_maps:Ou,normal_pars_fragment:Bu,normal_pars_vertex:Hu,normal_vertex:zu,normalmap_pars_fragment:Gu,clearcoat_normal_fragment_begin:ku,clearcoat_normal_fragment_maps:Vu,clearcoat_pars_fragment:Wu,iridescence_pars_fragment:Xu,opaque_fragment:qu,packing:Yu,premultiplied_alpha_fragment:$u,project_vertex:Ku,dithering_fragment:Zu,dithering_pars_fragment:ju,roughnessmap_fragment:Ju,roughnessmap_pars_fragment:Qu,shadowmap_pars_fragment:eh,shadowmap_pars_vertex:th,shadowmap_vertex:nh,shadowmask_pars_fragment:ih,skinbase_vertex:rh,skinning_pars_vertex:sh,skinning_vertex:ah,skinnormal_vertex:oh,specularmap_fragment:lh,specularmap_pars_fragment:ch,tonemapping_fragment:uh,tonemapping_pars_fragment:hh,transmission_fragment:dh,transmission_pars_fragment:fh,uv_pars_fragment:ph,uv_pars_vertex:mh,uv_vertex:gh,worldpos_vertex:_h,background_vert:vh,background_frag:xh,backgroundCube_vert:Mh,backgroundCube_frag:Sh,cube_vert:Eh,cube_frag:yh,depth_vert:Th,depth_frag:Ah,distanceRGBA_vert:bh,distanceRGBA_frag:wh,equirect_vert:Rh,equirect_frag:Ch,linedashed_vert:Ph,linedashed_frag:Dh,meshbasic_vert:Lh,meshbasic_frag:Ih,meshlambert_vert:Uh,meshlambert_frag:Nh,meshmatcap_vert:Fh,meshmatcap_frag:Oh,meshnormal_vert:Bh,meshnormal_frag:Hh,meshphong_vert:zh,meshphong_frag:Gh,meshphysical_vert:kh,meshphysical_frag:Vh,meshtoon_vert:Wh,meshtoon_frag:Xh,points_vert:qh,points_frag:Yh,shadow_vert:$h,shadow_frag:Kh,sprite_vert:Zh,sprite_frag:jh},re={common:{diffuse:{value:new Oe(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new Ie},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new Ie}},envmap:{envMap:{value:null},envMapRotation:{value:new Ie},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new Ie}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new Ie}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new Ie},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new Ie},normalScale:{value:new Ge(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new Ie},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new Ie}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new Ie}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new Ie}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Oe(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotShadowMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new Oe(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0},uvTransform:{value:new Ie}},sprite:{diffuse:{value:new Oe(16777215)},opacity:{value:1},center:{value:new Ge(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new Ie},alphaMap:{value:null},alphaMapTransform:{value:new Ie},alphaTest:{value:0}}},Vt={basic:{uniforms:_t([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.fog]),vertexShader:Ne.meshbasic_vert,fragmentShader:Ne.meshbasic_frag},lambert:{uniforms:_t([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.fog,re.lights,{emissive:{value:new Oe(0)}}]),vertexShader:Ne.meshlambert_vert,fragmentShader:Ne.meshlambert_frag},phong:{uniforms:_t([re.common,re.specularmap,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.fog,re.lights,{emissive:{value:new Oe(0)},specular:{value:new Oe(1118481)},shininess:{value:30}}]),vertexShader:Ne.meshphong_vert,fragmentShader:Ne.meshphong_frag},standard:{uniforms:_t([re.common,re.envmap,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.roughnessmap,re.metalnessmap,re.fog,re.lights,{emissive:{value:new Oe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:Ne.meshphysical_vert,fragmentShader:Ne.meshphysical_frag},toon:{uniforms:_t([re.common,re.aomap,re.lightmap,re.emissivemap,re.bumpmap,re.normalmap,re.displacementmap,re.gradientmap,re.fog,re.lights,{emissive:{value:new Oe(0)}}]),vertexShader:Ne.meshtoon_vert,fragmentShader:Ne.meshtoon_frag},matcap:{uniforms:_t([re.common,re.bumpmap,re.normalmap,re.displacementmap,re.fog,{matcap:{value:null}}]),vertexShader:Ne.meshmatcap_vert,fragmentShader:Ne.meshmatcap_frag},points:{uniforms:_t([re.points,re.fog]),vertexShader:Ne.points_vert,fragmentShader:Ne.points_frag},dashed:{uniforms:_t([re.common,re.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:Ne.linedashed_vert,fragmentShader:Ne.linedashed_frag},depth:{uniforms:_t([re.common,re.displacementmap]),vertexShader:Ne.depth_vert,fragmentShader:Ne.depth_frag},normal:{uniforms:_t([re.common,re.bumpmap,re.normalmap,re.displacementmap,{opacity:{value:1}}]),vertexShader:Ne.meshnormal_vert,fragmentShader:Ne.meshnormal_frag},sprite:{uniforms:_t([re.sprite,re.fog]),vertexShader:Ne.sprite_vert,fragmentShader:Ne.sprite_frag},background:{uniforms:{uvTransform:{value:new Ie},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:Ne.background_vert,fragmentShader:Ne.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new Ie}},vertexShader:Ne.backgroundCube_vert,fragmentShader:Ne.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:Ne.cube_vert,fragmentShader:Ne.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:Ne.equirect_vert,fragmentShader:Ne.equirect_frag},distanceRGBA:{uniforms:_t([re.common,re.displacementmap,{referencePosition:{value:new F},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:Ne.distanceRGBA_vert,fragmentShader:Ne.distanceRGBA_frag},shadow:{uniforms:_t([re.lights,re.fog,{color:{value:new Oe(0)},opacity:{value:1}}]),vertexShader:Ne.shadow_vert,fragmentShader:Ne.shadow_frag}};Vt.physical={uniforms:_t([Vt.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new Ie},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new Ie},clearcoatNormalScale:{value:new Ge(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new Ie},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new Ie},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new Ie},sheen:{value:0},sheenColor:{value:new Oe(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new Ie},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new Ie},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new Ie},transmissionSamplerSize:{value:new Ge},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new Ie},attenuationDistance:{value:0},attenuationColor:{value:new Oe(0)},specularColor:{value:new Oe(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new Ie},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new Ie},anisotropyVector:{value:new Ge},anisotropyMap:{value:null},anisotropyMapTransform:{value:new Ie}}]),vertexShader:Ne.meshphysical_vert,fragmentShader:Ne.meshphysical_frag};const Ki={r:0,b:0,g:0},yn=new Yt,Jh=new st;function Qh(i,e,t,n,r,s,a){const o=new Oe(0);let c=s===!0?0:1,l,h,d=null,f=0,m=null;function _(A){let E=A.isScene===!0?A.background:null;return E&&E.isTexture&&(E=(A.backgroundBlurriness>0?t:e).get(E)),E}function x(A){let E=!1;const D=_(A);D===null?u(o,c):D&&D.isColor&&(u(D,1),E=!0);const R=i.xr.getEnvironmentBlendMode();R==="additive"?n.buffers.color.setClear(0,0,0,1,a):R==="alpha-blend"&&n.buffers.color.setClear(0,0,0,0,a),(i.autoClear||E)&&(n.buffers.depth.setTest(!0),n.buffers.depth.setMask(!0),n.buffers.color.setMask(!0),i.clear(i.autoClearColor,i.autoClearDepth,i.autoClearStencil))}function p(A,E){const D=_(E);D&&(D.isCubeTexture||D.mapping===ar)?(h===void 0&&(h=new wt(new Ri(1,1,1),new gn({name:"BackgroundCubeMaterial",uniforms:ri(Vt.backgroundCube.uniforms),vertexShader:Vt.backgroundCube.vertexShader,fragmentShader:Vt.backgroundCube.fragmentShader,side:Et,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),h.geometry.deleteAttribute("normal"),h.geometry.deleteAttribute("uv"),h.onBeforeRender=function(R,w,U){this.matrixWorld.copyPosition(U.matrixWorld)},Object.defineProperty(h.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),r.update(h)),yn.copy(E.backgroundRotation),yn.x*=-1,yn.y*=-1,yn.z*=-1,D.isCubeTexture&&D.isRenderTargetTexture===!1&&(yn.y*=-1,yn.z*=-1),h.material.uniforms.envMap.value=D,h.material.uniforms.flipEnvMap.value=D.isCubeTexture&&D.isRenderTargetTexture===!1?-1:1,h.material.uniforms.backgroundBlurriness.value=E.backgroundBlurriness,h.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,h.material.uniforms.backgroundRotation.value.setFromMatrix4(Jh.makeRotationFromEuler(yn)),h.material.toneMapped=Ve.getTransfer(D.colorSpace)!==Ye,(d!==D||f!==D.version||m!==i.toneMapping)&&(h.material.needsUpdate=!0,d=D,f=D.version,m=i.toneMapping),h.layers.enableAll(),A.unshift(h,h.geometry,h.material,0,0,null)):D&&D.isTexture&&(l===void 0&&(l=new wt(new ai(2,2),new gn({name:"BackgroundMaterial",uniforms:ri(Vt.background.uniforms),vertexShader:Vt.background.vertexShader,fragmentShader:Vt.background.fragmentShader,side:mn,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),l.geometry.deleteAttribute("normal"),Object.defineProperty(l.material,"map",{get:function(){return this.uniforms.t2D.value}}),r.update(l)),l.material.uniforms.t2D.value=D,l.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,l.material.toneMapped=Ve.getTransfer(D.colorSpace)!==Ye,D.matrixAutoUpdate===!0&&D.updateMatrix(),l.material.uniforms.uvTransform.value.copy(D.matrix),(d!==D||f!==D.version||m!==i.toneMapping)&&(l.material.needsUpdate=!0,d=D,f=D.version,m=i.toneMapping),l.layers.enableAll(),A.unshift(l,l.geometry,l.material,0,0,null))}function u(A,E){A.getRGB(Ki,Eo(i)),n.buffers.color.setClear(Ki.r,Ki.g,Ki.b,E,a)}function b(){h!==void 0&&(h.geometry.dispose(),h.material.dispose(),h=void 0),l!==void 0&&(l.geometry.dispose(),l.material.dispose(),l=void 0)}return{getClearColor:function(){return o},setClearColor:function(A,E=1){o.set(A),c=E,u(o,c)},getClearAlpha:function(){return c},setClearAlpha:function(A){c=A,u(o,c)},render:x,addToRenderList:p,dispose:b}}function ed(i,e){const t=i.getParameter(i.MAX_VERTEX_ATTRIBS),n={},r=f(null);let s=r,a=!1;function o(M,C,O,z,q){let W=!1;const X=d(z,O,C);s!==X&&(s=X,l(s.object)),W=m(M,z,O,q),W&&_(M,z,O,q),q!==null&&e.update(q,i.ELEMENT_ARRAY_BUFFER),(W||a)&&(a=!1,E(M,C,O,z),q!==null&&i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,e.get(q).buffer))}function c(){return i.createVertexArray()}function l(M){return i.bindVertexArray(M)}function h(M){return i.deleteVertexArray(M)}function d(M,C,O){const z=O.wireframe===!0;let q=n[M.id];q===void 0&&(q={},n[M.id]=q);let W=q[C.id];W===void 0&&(W={},q[C.id]=W);let X=W[z];return X===void 0&&(X=f(c()),W[z]=X),X}function f(M){const C=[],O=[],z=[];for(let q=0;q=0){const ce=q[G];let Ee=W[G];if(Ee===void 0&&(G==="instanceMatrix"&&M.instanceMatrix&&(Ee=M.instanceMatrix),G==="instanceColor"&&M.instanceColor&&(Ee=M.instanceColor)),ce===void 0||ce.attribute!==Ee||Ee&&ce.data!==Ee.data)return!0;X++}return s.attributesNum!==X||s.index!==z}function _(M,C,O,z){const q={},W=C.attributes;let X=0;const Z=O.getAttributes();for(const G in Z)if(Z[G].location>=0){let ce=W[G];ce===void 0&&(G==="instanceMatrix"&&M.instanceMatrix&&(ce=M.instanceMatrix),G==="instanceColor"&&M.instanceColor&&(ce=M.instanceColor));const Ee={};Ee.attribute=ce,ce&&ce.data&&(Ee.data=ce.data),q[G]=Ee,X++}s.attributes=q,s.attributesNum=X,s.index=z}function x(){const M=s.newAttributes;for(let C=0,O=M.length;C=0){let se=q[Z];if(se===void 0&&(Z==="instanceMatrix"&&M.instanceMatrix&&(se=M.instanceMatrix),Z==="instanceColor"&&M.instanceColor&&(se=M.instanceColor)),se!==void 0){const ce=se.normalized,Ee=se.itemSize,Fe=e.get(se);if(Fe===void 0)continue;const Ke=Fe.buffer,Je=Fe.type,We=Fe.bytesPerElement,Y=Je===i.INT||Je===i.UNSIGNED_INT||se.gpuType===Is;if(se.isInterleavedBufferAttribute){const j=se.data,de=j.stride,Ce=se.offset;if(j.isInstancedInterleavedBuffer){for(let Se=0;Se0&&i.getShaderPrecisionFormat(i.FRAGMENT_SHADER,i.HIGH_FLOAT).precision>0)return"highp";w="mediump"}return w==="mediump"&&i.getShaderPrecisionFormat(i.VERTEX_SHADER,i.MEDIUM_FLOAT).precision>0&&i.getShaderPrecisionFormat(i.FRAGMENT_SHADER,i.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let l=t.precision!==void 0?t.precision:"highp";const h=c(l);h!==l&&(console.warn("THREE.WebGLRenderer:",l,"not supported, using",h,"instead."),l=h);const d=t.logarithmicDepthBuffer===!0,f=t.reversedDepthBuffer===!0&&e.has("EXT_clip_control"),m=i.getParameter(i.MAX_TEXTURE_IMAGE_UNITS),_=i.getParameter(i.MAX_VERTEX_TEXTURE_IMAGE_UNITS),x=i.getParameter(i.MAX_TEXTURE_SIZE),p=i.getParameter(i.MAX_CUBE_MAP_TEXTURE_SIZE),u=i.getParameter(i.MAX_VERTEX_ATTRIBS),b=i.getParameter(i.MAX_VERTEX_UNIFORM_VECTORS),A=i.getParameter(i.MAX_VARYING_VECTORS),E=i.getParameter(i.MAX_FRAGMENT_UNIFORM_VECTORS),D=_>0,R=i.getParameter(i.MAX_SAMPLES);return{isWebGL2:!0,getMaxAnisotropy:s,getMaxPrecision:c,textureFormatReadable:a,textureTypeReadable:o,precision:l,logarithmicDepthBuffer:d,reversedDepthBuffer:f,maxTextures:m,maxVertexTextures:_,maxTextureSize:x,maxCubemapSize:p,maxAttributes:u,maxVertexUniforms:b,maxVaryings:A,maxFragmentUniforms:E,vertexTextures:D,maxSamples:R}}function id(i){const e=this;let t=null,n=0,r=!1,s=!1;const a=new An,o=new Ie,c={value:null,needsUpdate:!1};this.uniform=c,this.numPlanes=0,this.numIntersection=0,this.init=function(d,f){const m=d.length!==0||f||n!==0||r;return r=f,n=d.length,m},this.beginShadows=function(){s=!0,h(null)},this.endShadows=function(){s=!1},this.setGlobalState=function(d,f){t=h(d,f,0)},this.setState=function(d,f,m){const _=d.clippingPlanes,x=d.clipIntersection,p=d.clipShadows,u=i.get(d);if(!r||_===null||_.length===0||s&&!p)s?h(null):l();else{const b=s?0:n,A=b*4;let E=u.clippingState||null;c.value=E,E=h(_,f,A,m);for(let D=0;D!==A;++D)E[D]=t[D];u.clippingState=E,this.numIntersection=x?this.numPlanes:0,this.numPlanes+=b}};function l(){c.value!==t&&(c.value=t,c.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function h(d,f,m,_){const x=d!==null?d.length:0;let p=null;if(x!==0){if(p=c.value,_!==!0||p===null){const u=m+x*4,b=f.matrixWorldInverse;o.getNormalMatrix(b),(p===null||p.length0){const l=new Ql(c.height);return l.fromEquirectangularTexture(i,a),e.set(a,l),a.addEventListener("dispose",r),t(l.texture,a.mapping)}else return null}}return a}function r(a){const o=a.target;o.removeEventListener("dispose",r);const c=e.get(o);c!==void 0&&(e.delete(o),c.dispose())}function s(){e=new WeakMap}return{get:n,dispose:s}}const jn=4,Ca=[.125,.215,.35,.446,.526,.582],Rn=20,Or=new Ro,Pa=new Oe;let Br=null,Hr=0,zr=0,Gr=!1;const bn=(1+Math.sqrt(5))/2,Kn=1/bn,Da=[new F(-bn,Kn,0),new F(bn,Kn,0),new F(-Kn,0,bn),new F(Kn,0,bn),new F(0,bn,-Kn),new F(0,bn,Kn),new F(-1,1,-1),new F(1,1,-1),new F(-1,1,1),new F(1,1,1)],sd=new F;class La{constructor(e){this._renderer=e,this._pingPongRenderTarget=null,this._lodMax=0,this._cubeSize=0,this._lodPlanes=[],this._sizeLods=[],this._sigmas=[],this._blurMaterial=null,this._cubemapMaterial=null,this._equirectMaterial=null,this._compileMaterial(this._blurMaterial)}fromScene(e,t=0,n=.1,r=100,s={}){const{size:a=256,position:o=sd}=s;Br=this._renderer.getRenderTarget(),Hr=this._renderer.getActiveCubeFace(),zr=this._renderer.getActiveMipmapLevel(),Gr=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(a);const c=this._allocateTargets();return c.depthBuffer=!0,this._sceneToCubeUV(e,n,r,c,o),t>0&&this._blur(c,0,0,t),this._applyPMREM(c),this._cleanup(c),c}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=Na(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=Ua(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),this._cubemapMaterial!==null&&this._cubemapMaterial.dispose(),this._equirectMaterial!==null&&this._equirectMaterial.dispose()}_setSize(e){this._lodMax=Math.floor(Math.log2(e)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){this._blurMaterial!==null&&this._blurMaterial.dispose(),this._pingPongRenderTarget!==null&&this._pingPongRenderTarget.dispose();for(let e=0;e2?D:0,D,D),d.setRenderTarget(r),u&&d.render(p,c),d.render(e,c)}p.geometry.dispose(),p.material.dispose(),d.toneMapping=m,d.autoClear=f,e.background=b}_textureToCubeUV(e,t){const n=this._renderer,r=e.mapping===ti||e.mapping===ni;r?(this._cubemapMaterial===null&&(this._cubemapMaterial=Na()),this._cubemapMaterial.uniforms.flipEnvMap.value=e.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=Ua());const s=r?this._cubemapMaterial:this._equirectMaterial,a=new wt(this._lodPlanes[0],s),o=s.uniforms;o.envMap.value=e;const c=this._cubeSize;Zi(t,0,0,3*c,2*c),n.setRenderTarget(t),n.render(a,Or)}_applyPMREM(e){const t=this._renderer,n=t.autoClear;t.autoClear=!1;const r=this._lodPlanes.length;for(let s=1;sRn&&console.warn(`sigmaRadians, ${s}, is too large and will clip, as it requested ${p} samples when the maximum is set to ${Rn}`);const u=[];let b=0;for(let w=0;wA-jn?r-A+jn:0),R=4*(this._cubeSize-E);Zi(t,D,R,3*E,2*E),c.setRenderTarget(t),c.render(d,Or)}}function ad(i){const e=[],t=[],n=[];let r=i;const s=i-jn+1+Ca.length;for(let a=0;ai-jn?c=Ca[a-i+jn-1]:a===0&&(c=0),n.push(c);const l=1/(o-2),h=-l,d=1+l,f=[h,h,d,h,d,d,h,h,d,d,h,d],m=6,_=6,x=3,p=2,u=1,b=new Float32Array(x*_*m),A=new Float32Array(p*_*m),E=new Float32Array(u*_*m);for(let R=0;R2?0:-1,S=[w,U,0,w+2/3,U,0,w+2/3,U+1,0,w,U,0,w+2/3,U+1,0,w,U+1,0];b.set(S,x*_*R),A.set(f,p*_*R);const M=[R,R,R,R,R,R];E.set(M,u*_*R)}const D=new sn;D.setAttribute("position",new Xt(b,x)),D.setAttribute("uv",new Xt(A,p)),D.setAttribute("faceIndex",new Xt(E,u)),e.push(D),r>jn&&r--}return{lodPlanes:e,sizeLods:t,sigmas:n}}function Ia(i,e,t){const n=new In(i,e,t);return n.texture.mapping=ar,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function Zi(i,e,t,n,r){i.viewport.set(e,t,n,r),i.scissor.set(e,t,n,r)}function od(i,e,t){const n=new Float32Array(Rn),r=new F(0,1,0);return new gn({name:"SphericalGaussianBlur",defines:{n:Rn,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP:`${i}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:r}},vertexShader:Ys(),fragmentShader:` precision mediump float; precision mediump int; @@ -3644,7 +3644,7 @@ void main() { } } - `,blending:dn,depthTest:!1,depthWrite:!1})}function qa(){return new mn({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:ta(),fragmentShader:` + `,blending:fn,depthTest:!1,depthWrite:!1})}function Ua(){return new gn({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:Ys(),fragmentShader:` precision mediump float; precision mediump int; @@ -3663,7 +3663,7 @@ void main() { gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); } - `,blending:dn,depthTest:!1,depthWrite:!1})}function Ya(){return new mn({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:ta(),fragmentShader:` + `,blending:fn,depthTest:!1,depthWrite:!1})}function Na(){return new gn({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:Ys(),fragmentShader:` precision mediump float; precision mediump int; @@ -3679,7 +3679,7 @@ void main() { gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); } - `,blending:dn,depthTest:!1,depthWrite:!1})}function ta(){return` + `,blending:fn,depthTest:!1,depthWrite:!1})}function Ys(){return` precision mediump float; precision mediump int; @@ -3734,17 +3734,17 @@ void main() { gl_Position = vec4( position, 1.0 ); } - `}function _d(i){let e=new WeakMap,t=null;function n(o){if(o&&o.isTexture){const l=o.mapping,c=l===ss||l===as,d=l===jn||l===Jn;if(c||d){let h=e.get(o);const f=h!==void 0?h.texture.pmremVersion:0;if(o.isRenderTargetTexture&&o.pmremVersion!==f)return t===null&&(t=new Wa(i)),h=c?t.fromEquirectangular(o,h):t.fromCubemap(o,h),h.texture.pmremVersion=o.pmremVersion,e.set(o,h),h.texture;if(h!==void 0)return h.texture;{const m=o.image;return c&&m&&m.height>0||d&&m&&r(m)?(t===null&&(t=new Wa(i)),h=c?t.fromEquirectangular(o):t.fromCubemap(o),h.texture.pmremVersion=o.pmremVersion,e.set(o,h),o.addEventListener("dispose",s),h.texture):null}}}return o}function r(o){let l=0;const c=6;for(let d=0;de.maxTextureSize&&(R=Math.ceil(C/e.maxTextureSize),C=e.maxTextureSize);const w=new Float32Array(C*R*4*h),U=new Ro(w,C,R,h);U.type=nn,U.needsUpdate=!0;const S=E*4;for(let P=0;P0)return i;const r=e*t;let s=Ka[r];if(s===void 0&&(s=new Float32Array(r),Ka[r]=s),e!==0){n.toArray(s,0);for(let a=1,o=0;a!==e;++a)o+=t,i[a].toArray(s,o)}return s}function lt(i,e){if(i.length!==e.length)return!1;for(let t=0,n=i.length;t0||h&&m&&r(m)?(t===null&&(t=new La(i)),d=l?t.fromEquirectangular(o):t.fromCubemap(o),d.texture.pmremVersion=o.pmremVersion,e.set(o,d),o.addEventListener("dispose",s),d.texture):null}}}return o}function r(o){let c=0;const l=6;for(let h=0;he.maxTextureSize&&(R=Math.ceil(D/e.maxTextureSize),D=e.maxTextureSize);const w=new Float32Array(D*R*4*d),U=new go(w,D,R,d);U.type=nn,U.needsUpdate=!0;const S=E*4;for(let C=0;C0)return i;const r=e*t;let s=Oa[r];if(s===void 0&&(s=new Float32Array(r),Oa[r]=s),e!==0){n.toArray(s,0);for(let a=1,o=0;a!==e;++a)o+=t,i[a].toArray(s,o)}return s}function lt(i,e){if(i.length!==e.length)return!1;for(let t=0,n=i.length;t":" "} ${o}: ${t[a]}`)}return n.join(` -`)}const no=new Ie;function vf(i){ke._getMatrix(no,ke.workingColorSpace,i);const e=`mat3( ${no.elements.map(t=>t.toFixed(4))} )`;switch(ke.getTransfer(i)){case sr:return[e,"LinearTransferOETF"];case Ye:return[e,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space: ",i),[e,"LinearTransferOETF"]}}function io(i,e,t){const n=i.getShaderParameter(e,i.COMPILE_STATUS),s=(i.getShaderInfoLog(e)||"").trim();if(n&&s==="")return"";const a=/ERROR: 0:(\d+)/.exec(s);if(a){const o=parseInt(a[1]);return t.toUpperCase()+` +`)}const Wa=new Ie;function cf(i){Ve._getMatrix(Wa,Ve.workingColorSpace,i);const e=`mat3( ${Wa.elements.map(t=>t.toFixed(4))} )`;switch(Ve.getTransfer(i)){case rr:return[e,"LinearTransferOETF"];case Ye:return[e,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space: ",i),[e,"LinearTransferOETF"]}}function Xa(i,e,t){const n=i.getShaderParameter(e,i.COMPILE_STATUS),s=(i.getShaderInfoLog(e)||"").trim();if(n&&s==="")return"";const a=/ERROR: 0:(\d+)/.exec(s);if(a){const o=parseInt(a[1]);return t.toUpperCase()+` `+s+` -`+_f(i.getShaderSource(e),o)}else return s}function xf(i,e){const t=vf(e);return[`vec4 ${i}( vec4 value ) {`,` return ${t[1]}( vec4( value.rgb * ${t[0]}, value.a ) );`,"}"].join(` -`)}function Mf(i,e){let t;switch(e){case xc:t="Linear";break;case Mc:t="Reinhard";break;case Sc:t="Cineon";break;case Ec:t="ACESFilmic";break;case Tc:t="AgX";break;case Ac:t="Neutral";break;case yc:t="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",e),t="Linear"}return"vec3 "+i+"( vec3 color ) { return "+t+"ToneMapping( color ); }"}const Ji=new N;function Sf(){ke.getLuminanceCoefficients(Ji);const i=Ji.x.toFixed(4),e=Ji.y.toFixed(4),t=Ji.z.toFixed(4);return["float luminance( const in vec3 rgb ) {",` const vec3 weights = vec3( ${i}, ${e}, ${t} );`," return dot( weights, rgb );","}"].join(` -`)}function Ef(i){return[i.extensionClipCullDistance?"#extension GL_ANGLE_clip_cull_distance : require":"",i.extensionMultiDraw?"#extension GL_ANGLE_multi_draw : require":""].filter(di).join(` -`)}function yf(i){const e=[];for(const t in i){const n=i[t];n!==!1&&e.push("#define "+t+" "+n)}return e.join(` -`)}function Tf(i,e){const t={},n=i.getProgramParameter(e,i.ACTIVE_ATTRIBUTES);for(let r=0;r/gm;function Hs(i){return i.replace(Af,wf)}const bf=new Map;function wf(i,e){let t=Ne[e];if(t===void 0){const n=bf.get(e);if(n!==void 0)t=Ne[n],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,n);else throw new Error("Can not resolve #include <"+e+">")}return Hs(t)}const Rf=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function ao(i){return i.replace(Rf,Cf)}function Cf(i,e,t,n){let r="";for(let s=parseInt(e);s/gm;function Ds(i){return i.replace(gf,vf)}const _f=new Map;function vf(i,e){let t=Ne[e];if(t===void 0){const n=_f.get(e);if(n!==void 0)t=Ne[n],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,n);else throw new Error("Can not resolve #include <"+e+">")}return Ds(t)}const xf=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function $a(i){return i.replace(xf,Mf)}function Mf(i,e,t,n){let r="";for(let s=parseInt(e);s0&&(p+=` -`),u=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_].filter(di).join(` +`),u=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_].filter(pi).join(` `),u.length>0&&(u+=` -`)):(p=[oo(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_,t.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",t.batching?"#define USE_BATCHING":"",t.batchingColor?"#define USE_BATCHING_COLOR":"",t.instancing?"#define USE_INSTANCING":"",t.instancingColor?"#define USE_INSTANCING_COLOR":"",t.instancingMorph?"#define USE_INSTANCING_MORPH":"",t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+d:"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.displacementMap?"#define USE_DISPLACEMENTMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.mapUv?"#define MAP_UV "+t.mapUv:"",t.alphaMapUv?"#define ALPHAMAP_UV "+t.alphaMapUv:"",t.lightMapUv?"#define LIGHTMAP_UV "+t.lightMapUv:"",t.aoMapUv?"#define AOMAP_UV "+t.aoMapUv:"",t.emissiveMapUv?"#define EMISSIVEMAP_UV "+t.emissiveMapUv:"",t.bumpMapUv?"#define BUMPMAP_UV "+t.bumpMapUv:"",t.normalMapUv?"#define NORMALMAP_UV "+t.normalMapUv:"",t.displacementMapUv?"#define DISPLACEMENTMAP_UV "+t.displacementMapUv:"",t.metalnessMapUv?"#define METALNESSMAP_UV "+t.metalnessMapUv:"",t.roughnessMapUv?"#define ROUGHNESSMAP_UV "+t.roughnessMapUv:"",t.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+t.anisotropyMapUv:"",t.clearcoatMapUv?"#define CLEARCOATMAP_UV "+t.clearcoatMapUv:"",t.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+t.clearcoatNormalMapUv:"",t.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+t.clearcoatRoughnessMapUv:"",t.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+t.iridescenceMapUv:"",t.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+t.iridescenceThicknessMapUv:"",t.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+t.sheenColorMapUv:"",t.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+t.sheenRoughnessMapUv:"",t.specularMapUv?"#define SPECULARMAP_UV "+t.specularMapUv:"",t.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+t.specularColorMapUv:"",t.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+t.specularIntensityMapUv:"",t.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+t.transmissionMapUv:"",t.thicknessMapUv?"#define THICKNESSMAP_UV "+t.thicknessMapUv:"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.flatShading?"#define FLAT_SHADED":"",t.skinning?"#define USE_SKINNING":"",t.morphTargets?"#define USE_MORPHTARGETS":"",t.morphNormals&&t.flatShading===!1?"#define USE_MORPHNORMALS":"",t.morphColors?"#define USE_MORPHCOLORS":"",t.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+t.morphTextureStride:"",t.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+t.morphTargetsCount:"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.sizeAttenuation?"#define USE_SIZEATTENUATION":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR"," attribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH"," uniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1"," attribute vec2 uv1;","#endif","#ifdef USE_UV2"," attribute vec2 uv2;","#endif","#ifdef USE_UV3"," attribute vec2 uv3;","#endif","#ifdef USE_TANGENT"," attribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )"," attribute vec4 color;","#elif defined( USE_COLOR )"," attribute vec3 color;","#endif","#ifdef USE_SKINNING"," attribute vec4 skinIndex;"," attribute vec4 skinWeight;","#endif",` -`].filter(di).join(` -`),u=[oo(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_,t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",t.map?"#define USE_MAP":"",t.matcap?"#define USE_MATCAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+c:"",t.envMap?"#define "+d:"",t.envMap?"#define "+h:"",f?"#define CUBEUV_TEXEL_WIDTH "+f.texelWidth:"",f?"#define CUBEUV_TEXEL_HEIGHT "+f.texelHeight:"",f?"#define CUBEUV_MAX_MIP "+f.maxMip+".0":"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoat?"#define USE_CLEARCOAT":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.dispersion?"#define USE_DISPERSION":"",t.iridescence?"#define USE_IRIDESCENCE":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaTest?"#define USE_ALPHATEST":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.sheen?"#define USE_SHEEN":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors||t.instancingColor||t.batchingColor?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.gradientMap?"#define USE_GRADIENTMAP":"",t.flatShading?"#define FLAT_SHADED":"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",t.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",t.toneMapping!==fn?"#define TONE_MAPPING":"",t.toneMapping!==fn?Ne.tonemapping_pars_fragment:"",t.toneMapping!==fn?Mf("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",Ne.colorspace_pars_fragment,xf("linearToOutputTexel",t.outputColorSpace),Sf(),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"",` -`].filter(di).join(` -`)),a=Hs(a),a=ro(a,t),a=so(a,t),o=Hs(o),o=ro(o,t),o=so(o,t),a=ao(a),o=ao(o),t.isRawShaderMaterial!==!0&&(b=`#version 300 es +`)):(p=[Ka(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_,t.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",t.batching?"#define USE_BATCHING":"",t.batchingColor?"#define USE_BATCHING_COLOR":"",t.instancing?"#define USE_INSTANCING":"",t.instancingColor?"#define USE_INSTANCING_COLOR":"",t.instancingMorph?"#define USE_INSTANCING_MORPH":"",t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+h:"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.displacementMap?"#define USE_DISPLACEMENTMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.mapUv?"#define MAP_UV "+t.mapUv:"",t.alphaMapUv?"#define ALPHAMAP_UV "+t.alphaMapUv:"",t.lightMapUv?"#define LIGHTMAP_UV "+t.lightMapUv:"",t.aoMapUv?"#define AOMAP_UV "+t.aoMapUv:"",t.emissiveMapUv?"#define EMISSIVEMAP_UV "+t.emissiveMapUv:"",t.bumpMapUv?"#define BUMPMAP_UV "+t.bumpMapUv:"",t.normalMapUv?"#define NORMALMAP_UV "+t.normalMapUv:"",t.displacementMapUv?"#define DISPLACEMENTMAP_UV "+t.displacementMapUv:"",t.metalnessMapUv?"#define METALNESSMAP_UV "+t.metalnessMapUv:"",t.roughnessMapUv?"#define ROUGHNESSMAP_UV "+t.roughnessMapUv:"",t.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+t.anisotropyMapUv:"",t.clearcoatMapUv?"#define CLEARCOATMAP_UV "+t.clearcoatMapUv:"",t.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+t.clearcoatNormalMapUv:"",t.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+t.clearcoatRoughnessMapUv:"",t.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+t.iridescenceMapUv:"",t.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+t.iridescenceThicknessMapUv:"",t.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+t.sheenColorMapUv:"",t.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+t.sheenRoughnessMapUv:"",t.specularMapUv?"#define SPECULARMAP_UV "+t.specularMapUv:"",t.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+t.specularColorMapUv:"",t.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+t.specularIntensityMapUv:"",t.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+t.transmissionMapUv:"",t.thicknessMapUv?"#define THICKNESSMAP_UV "+t.thicknessMapUv:"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.flatShading?"#define FLAT_SHADED":"",t.skinning?"#define USE_SKINNING":"",t.morphTargets?"#define USE_MORPHTARGETS":"",t.morphNormals&&t.flatShading===!1?"#define USE_MORPHNORMALS":"",t.morphColors?"#define USE_MORPHCOLORS":"",t.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+t.morphTextureStride:"",t.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+t.morphTargetsCount:"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+c:"",t.sizeAttenuation?"#define USE_SIZEATTENUATION":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR"," attribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH"," uniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1"," attribute vec2 uv1;","#endif","#ifdef USE_UV2"," attribute vec2 uv2;","#endif","#ifdef USE_UV3"," attribute vec2 uv3;","#endif","#ifdef USE_TANGENT"," attribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )"," attribute vec4 color;","#elif defined( USE_COLOR )"," attribute vec3 color;","#endif","#ifdef USE_SKINNING"," attribute vec4 skinIndex;"," attribute vec4 skinWeight;","#endif",` +`].filter(pi).join(` +`),u=[Ka(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,_,t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",t.map?"#define USE_MAP":"",t.matcap?"#define USE_MATCAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+l:"",t.envMap?"#define "+h:"",t.envMap?"#define "+d:"",f?"#define CUBEUV_TEXEL_WIDTH "+f.texelWidth:"",f?"#define CUBEUV_TEXEL_HEIGHT "+f.texelHeight:"",f?"#define CUBEUV_MAX_MIP "+f.maxMip+".0":"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoat?"#define USE_CLEARCOAT":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.dispersion?"#define USE_DISPERSION":"",t.iridescence?"#define USE_IRIDESCENCE":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaTest?"#define USE_ALPHATEST":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.sheen?"#define USE_SHEEN":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors||t.instancingColor||t.batchingColor?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.gradientMap?"#define USE_GRADIENTMAP":"",t.flatShading?"#define FLAT_SHADED":"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+c:"",t.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",t.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",t.toneMapping!==pn?"#define TONE_MAPPING":"",t.toneMapping!==pn?Ne.tonemapping_pars_fragment:"",t.toneMapping!==pn?hf("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",Ne.colorspace_pars_fragment,uf("linearToOutputTexel",t.outputColorSpace),df(),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"",` +`].filter(pi).join(` +`)),a=Ds(a),a=qa(a,t),a=Ya(a,t),o=Ds(o),o=qa(o,t),o=Ya(o,t),a=$a(a),o=$a(o),t.isRawShaderMaterial!==!0&&(b=`#version 300 es `,p=[m,"#define attribute in","#define varying out","#define texture2D texture"].join(` `)+` -`+p,u=["#define varying in",t.glslVersion===pa?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion===pa?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join(` +`+p,u=["#define varying in",t.glslVersion===aa?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion===aa?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join(` `)+` -`+u);const A=b+p+a,E=b+u+o,C=to(r,r.VERTEX_SHADER,A),R=to(r,r.FRAGMENT_SHADER,E);r.attachShader(x,C),r.attachShader(x,R),t.index0AttributeName!==void 0?r.bindAttribLocation(x,0,t.index0AttributeName):t.morphTargets===!0&&r.bindAttribLocation(x,0,"position"),r.linkProgram(x);function w(P){if(i.debug.checkShaderErrors){const O=r.getProgramInfoLog(x)||"",H=r.getShaderInfoLog(C)||"",q=r.getShaderInfoLog(R)||"",W=O.trim(),X=H.trim(),Z=q.trim();let G=!0,se=!0;if(r.getProgramParameter(x,r.LINK_STATUS)===!1)if(G=!1,typeof i.debug.onShaderError=="function")i.debug.onShaderError(r,x,C,R);else{const le=io(r,C,"vertex"),Ee=io(r,R,"fragment");console.error("THREE.WebGLProgram: Shader Error "+r.getError()+" - VALIDATE_STATUS "+r.getProgramParameter(x,r.VALIDATE_STATUS)+` +`+u);const A=b+p+a,E=b+u+o,D=Va(r,r.VERTEX_SHADER,A),R=Va(r,r.FRAGMENT_SHADER,E);r.attachShader(x,D),r.attachShader(x,R),t.index0AttributeName!==void 0?r.bindAttribLocation(x,0,t.index0AttributeName):t.morphTargets===!0&&r.bindAttribLocation(x,0,"position"),r.linkProgram(x);function w(C){if(i.debug.checkShaderErrors){const O=r.getProgramInfoLog(x)||"",z=r.getShaderInfoLog(D)||"",q=r.getShaderInfoLog(R)||"",W=O.trim(),X=z.trim(),Z=q.trim();let G=!0,se=!0;if(r.getProgramParameter(x,r.LINK_STATUS)===!1)if(G=!1,typeof i.debug.onShaderError=="function")i.debug.onShaderError(r,x,D,R);else{const ce=Xa(r,D,"vertex"),Ee=Xa(r,R,"fragment");console.error("THREE.WebGLProgram: Shader Error "+r.getError()+" - VALIDATE_STATUS "+r.getProgramParameter(x,r.VALIDATE_STATUS)+` -Material Name: `+P.name+` -Material Type: `+P.type+` +Material Name: `+C.name+` +Material Type: `+C.type+` Program Info Log: `+W+` -`+le+` -`+Ee)}else W!==""?console.warn("THREE.WebGLProgram: Program Info Log:",W):(X===""||Z==="")&&(se=!1);se&&(P.diagnostics={runnable:G,programLog:W,vertexShader:{log:X,prefix:p},fragmentShader:{log:Z,prefix:u}})}r.deleteShader(C),r.deleteShader(R),U=new rr(r,x),S=Tf(r,x)}let U;this.getUniforms=function(){return U===void 0&&w(this),U};let S;this.getAttributes=function(){return S===void 0&&w(this),S};let M=t.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return M===!1&&(M=r.getProgramParameter(x,mf)),M},this.destroy=function(){n.releaseStatesOfProgram(this),r.deleteProgram(x),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=gf++,this.cacheKey=e,this.usedTimes=1,this.program=x,this.vertexShader=C,this.fragmentShader=R,this}let Ff=0;class Of{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(e){const t=e.vertexShader,n=e.fragmentShader,r=this._getShaderStage(t),s=this._getShaderStage(n),a=this._getShaderCacheForMaterial(e);return a.has(r)===!1&&(a.add(r),r.usedTimes++),a.has(s)===!1&&(a.add(s),s.usedTimes++),this}remove(e){const t=this.materialCache.get(e);for(const n of t)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(e),this}getVertexShaderID(e){return this._getShaderStage(e.vertexShader).id}getFragmentShaderID(e){return this._getShaderStage(e.fragmentShader).id}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(e){const t=this.materialCache;let n=t.get(e);return n===void 0&&(n=new Set,t.set(e,n)),n}_getShaderStage(e){const t=this.shaderCache;let n=t.get(e);return n===void 0&&(n=new Bf(e),t.set(e,n)),n}}class Bf{constructor(e){this.id=Ff++,this.code=e,this.usedTimes=0}}function zf(i,e,t,n,r,s,a){const o=new Zs,l=new Of,c=new Set,d=[],h=r.logarithmicDepthBuffer,f=r.vertexTextures;let m=r.precision;const _={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function x(S){return c.add(S),S===0?"uv":`uv${S}`}function p(S,M,P,O,H){const q=O.fog,W=H.geometry,X=S.isMeshStandardMaterial?O.environment:null,Z=(S.isMeshStandardMaterial?t:e).get(S.envMap||X),G=Z&&Z.mapping===dr?Z.image.height:null,se=_[S.type];S.precision!==null&&(m=r.getMaxPrecision(S.precision),m!==S.precision&&console.warn("THREE.WebGLProgram.getParameters:",S.precision,"not supported, using",m,"instead."));const le=W.morphAttributes.position||W.morphAttributes.normal||W.morphAttributes.color,Ee=le!==void 0?le.length:0;let Oe=0;W.morphAttributes.position!==void 0&&(Oe=1),W.morphAttributes.normal!==void 0&&(Oe=2),W.morphAttributes.color!==void 0&&(Oe=3);let Ke,Je,We,Y;if(se){const Xe=Vt[se];Ke=Xe.vertexShader,Je=Xe.fragmentShader}else Ke=S.vertexShader,Je=S.fragmentShader,l.update(S),We=l.getVertexShaderID(S),Y=l.getFragmentShaderID(S);const j=i.getRenderTarget(),de=i.state.buffers.depth.getReversed(),Ce=H.isInstancedMesh===!0,Se=H.isBatchedMesh===!0,He=!!S.map,mt=!!S.matcap,T=!!Z,Qe=!!S.aoMap,De=!!S.lightMap,we=!!S.bumpMap,me=!!S.normalMap,et=!!S.displacementMap,ge=!!S.emissiveMap,Ue=!!S.metalnessMap,ht=!!S.roughnessMap,at=S.anisotropy>0,y=S.clearcoat>0,g=S.dispersion>0,F=S.iridescence>0,k=S.sheen>0,K=S.transmission>0,V=at&&!!S.anisotropyMap,Me=y&&!!S.clearcoatMap,ne=y&&!!S.clearcoatNormalMap,_e=y&&!!S.clearcoatRoughnessMap,ve=F&&!!S.iridescenceMap,ee=F&&!!S.iridescenceThicknessMap,ce=k&&!!S.sheenColorMap,be=k&&!!S.sheenRoughnessMap,xe=!!S.specularMap,ae=!!S.specularColorMap,Le=!!S.specularIntensityMap,D=K&&!!S.transmissionMap,te=K&&!!S.thicknessMap,ie=!!S.gradientMap,he=!!S.alphaMap,J=S.alphaTest>0,$=!!S.alphaHash,pe=!!S.extensions;let Pe=fn;S.toneMapped&&(j===null||j.isXRRenderTarget===!0)&&(Pe=i.toneMapping);const Ze={shaderID:se,shaderType:S.type,shaderName:S.name,vertexShader:Ke,fragmentShader:Je,defines:S.defines,customVertexShaderID:We,customFragmentShaderID:Y,isRawShaderMaterial:S.isRawShaderMaterial===!0,glslVersion:S.glslVersion,precision:m,batching:Se,batchingColor:Se&&H._colorsTexture!==null,instancing:Ce,instancingColor:Ce&&H.instanceColor!==null,instancingMorph:Ce&&H.morphTexture!==null,supportsVertexTextures:f,outputColorSpace:j===null?i.outputColorSpace:j.isXRRenderTarget===!0?j.texture.colorSpace:Qn,alphaToCoverage:!!S.alphaToCoverage,map:He,matcap:mt,envMap:T,envMapMode:T&&Z.mapping,envMapCubeUVHeight:G,aoMap:Qe,lightMap:De,bumpMap:we,normalMap:me,displacementMap:f&&et,emissiveMap:ge,normalMapObjectSpace:me&&S.normalMapType===Cc,normalMapTangentSpace:me&&S.normalMapType===Ao,metalnessMap:Ue,roughnessMap:ht,anisotropy:at,anisotropyMap:V,clearcoat:y,clearcoatMap:Me,clearcoatNormalMap:ne,clearcoatRoughnessMap:_e,dispersion:g,iridescence:F,iridescenceMap:ve,iridescenceThicknessMap:ee,sheen:k,sheenColorMap:ce,sheenRoughnessMap:be,specularMap:xe,specularColorMap:ae,specularIntensityMap:Le,transmission:K,transmissionMap:D,thicknessMap:te,gradientMap:ie,opaque:S.transparent===!1&&S.blending===$n&&S.alphaToCoverage===!1,alphaMap:he,alphaTest:J,alphaHash:$,combine:S.combine,mapUv:He&&x(S.map.channel),aoMapUv:Qe&&x(S.aoMap.channel),lightMapUv:De&&x(S.lightMap.channel),bumpMapUv:we&&x(S.bumpMap.channel),normalMapUv:me&&x(S.normalMap.channel),displacementMapUv:et&&x(S.displacementMap.channel),emissiveMapUv:ge&&x(S.emissiveMap.channel),metalnessMapUv:Ue&&x(S.metalnessMap.channel),roughnessMapUv:ht&&x(S.roughnessMap.channel),anisotropyMapUv:V&&x(S.anisotropyMap.channel),clearcoatMapUv:Me&&x(S.clearcoatMap.channel),clearcoatNormalMapUv:ne&&x(S.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:_e&&x(S.clearcoatRoughnessMap.channel),iridescenceMapUv:ve&&x(S.iridescenceMap.channel),iridescenceThicknessMapUv:ee&&x(S.iridescenceThicknessMap.channel),sheenColorMapUv:ce&&x(S.sheenColorMap.channel),sheenRoughnessMapUv:be&&x(S.sheenRoughnessMap.channel),specularMapUv:xe&&x(S.specularMap.channel),specularColorMapUv:ae&&x(S.specularColorMap.channel),specularIntensityMapUv:Le&&x(S.specularIntensityMap.channel),transmissionMapUv:D&&x(S.transmissionMap.channel),thicknessMapUv:te&&x(S.thicknessMap.channel),alphaMapUv:he&&x(S.alphaMap.channel),vertexTangents:!!W.attributes.tangent&&(me||at),vertexColors:S.vertexColors,vertexAlphas:S.vertexColors===!0&&!!W.attributes.color&&W.attributes.color.itemSize===4,pointsUvs:H.isPoints===!0&&!!W.attributes.uv&&(He||he),fog:!!q,useFog:S.fog===!0,fogExp2:!!q&&q.isFogExp2,flatShading:S.flatShading===!0&&S.wireframe===!1,sizeAttenuation:S.sizeAttenuation===!0,logarithmicDepthBuffer:h,reversedDepthBuffer:de,skinning:H.isSkinnedMesh===!0,morphTargets:W.morphAttributes.position!==void 0,morphNormals:W.morphAttributes.normal!==void 0,morphColors:W.morphAttributes.color!==void 0,morphTargetsCount:Ee,morphTextureStride:Oe,numDirLights:M.directional.length,numPointLights:M.point.length,numSpotLights:M.spot.length,numSpotLightMaps:M.spotLightMap.length,numRectAreaLights:M.rectArea.length,numHemiLights:M.hemi.length,numDirLightShadows:M.directionalShadowMap.length,numPointLightShadows:M.pointShadowMap.length,numSpotLightShadows:M.spotShadowMap.length,numSpotLightShadowsWithMaps:M.numSpotLightShadowsWithMaps,numLightProbes:M.numLightProbes,numClippingPlanes:a.numPlanes,numClipIntersection:a.numIntersection,dithering:S.dithering,shadowMapEnabled:i.shadowMap.enabled&&P.length>0,shadowMapType:i.shadowMap.type,toneMapping:Pe,decodeVideoTexture:He&&S.map.isVideoTexture===!0&&ke.getTransfer(S.map.colorSpace)===Ye,decodeVideoTextureEmissive:ge&&S.emissiveMap.isVideoTexture===!0&&ke.getTransfer(S.emissiveMap.colorSpace)===Ye,premultipliedAlpha:S.premultipliedAlpha,doubleSided:S.side===kt,flipSided:S.side===yt,useDepthPacking:S.depthPacking>=0,depthPacking:S.depthPacking||0,index0AttributeName:S.index0AttributeName,extensionClipCullDistance:pe&&S.extensions.clipCullDistance===!0&&n.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(pe&&S.extensions.multiDraw===!0||Se)&&n.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:n.has("KHR_parallel_shader_compile"),customProgramCacheKey:S.customProgramCacheKey()};return Ze.vertexUv1s=c.has(1),Ze.vertexUv2s=c.has(2),Ze.vertexUv3s=c.has(3),c.clear(),Ze}function u(S){const M=[];if(S.shaderID?M.push(S.shaderID):(M.push(S.customVertexShaderID),M.push(S.customFragmentShaderID)),S.defines!==void 0)for(const P in S.defines)M.push(P),M.push(S.defines[P]);return S.isRawShaderMaterial===!1&&(b(M,S),A(M,S),M.push(i.outputColorSpace)),M.push(S.customProgramCacheKey),M.join()}function b(S,M){S.push(M.precision),S.push(M.outputColorSpace),S.push(M.envMapMode),S.push(M.envMapCubeUVHeight),S.push(M.mapUv),S.push(M.alphaMapUv),S.push(M.lightMapUv),S.push(M.aoMapUv),S.push(M.bumpMapUv),S.push(M.normalMapUv),S.push(M.displacementMapUv),S.push(M.emissiveMapUv),S.push(M.metalnessMapUv),S.push(M.roughnessMapUv),S.push(M.anisotropyMapUv),S.push(M.clearcoatMapUv),S.push(M.clearcoatNormalMapUv),S.push(M.clearcoatRoughnessMapUv),S.push(M.iridescenceMapUv),S.push(M.iridescenceThicknessMapUv),S.push(M.sheenColorMapUv),S.push(M.sheenRoughnessMapUv),S.push(M.specularMapUv),S.push(M.specularColorMapUv),S.push(M.specularIntensityMapUv),S.push(M.transmissionMapUv),S.push(M.thicknessMapUv),S.push(M.combine),S.push(M.fogExp2),S.push(M.sizeAttenuation),S.push(M.morphTargetsCount),S.push(M.morphAttributeCount),S.push(M.numDirLights),S.push(M.numPointLights),S.push(M.numSpotLights),S.push(M.numSpotLightMaps),S.push(M.numHemiLights),S.push(M.numRectAreaLights),S.push(M.numDirLightShadows),S.push(M.numPointLightShadows),S.push(M.numSpotLightShadows),S.push(M.numSpotLightShadowsWithMaps),S.push(M.numLightProbes),S.push(M.shadowMapType),S.push(M.toneMapping),S.push(M.numClippingPlanes),S.push(M.numClipIntersection),S.push(M.depthPacking)}function A(S,M){o.disableAll(),M.supportsVertexTextures&&o.enable(0),M.instancing&&o.enable(1),M.instancingColor&&o.enable(2),M.instancingMorph&&o.enable(3),M.matcap&&o.enable(4),M.envMap&&o.enable(5),M.normalMapObjectSpace&&o.enable(6),M.normalMapTangentSpace&&o.enable(7),M.clearcoat&&o.enable(8),M.iridescence&&o.enable(9),M.alphaTest&&o.enable(10),M.vertexColors&&o.enable(11),M.vertexAlphas&&o.enable(12),M.vertexUv1s&&o.enable(13),M.vertexUv2s&&o.enable(14),M.vertexUv3s&&o.enable(15),M.vertexTangents&&o.enable(16),M.anisotropy&&o.enable(17),M.alphaHash&&o.enable(18),M.batching&&o.enable(19),M.dispersion&&o.enable(20),M.batchingColor&&o.enable(21),M.gradientMap&&o.enable(22),S.push(o.mask),o.disableAll(),M.fog&&o.enable(0),M.useFog&&o.enable(1),M.flatShading&&o.enable(2),M.logarithmicDepthBuffer&&o.enable(3),M.reversedDepthBuffer&&o.enable(4),M.skinning&&o.enable(5),M.morphTargets&&o.enable(6),M.morphNormals&&o.enable(7),M.morphColors&&o.enable(8),M.premultipliedAlpha&&o.enable(9),M.shadowMapEnabled&&o.enable(10),M.doubleSided&&o.enable(11),M.flipSided&&o.enable(12),M.useDepthPacking&&o.enable(13),M.dithering&&o.enable(14),M.transmission&&o.enable(15),M.sheen&&o.enable(16),M.opaque&&o.enable(17),M.pointsUvs&&o.enable(18),M.decodeVideoTexture&&o.enable(19),M.decodeVideoTextureEmissive&&o.enable(20),M.alphaToCoverage&&o.enable(21),S.push(o.mask)}function E(S){const M=_[S.type];let P;if(M){const O=Vt[M];P=rl.clone(O.uniforms)}else P=S.uniforms;return P}function C(S,M){let P;for(let O=0,H=d.length;O0?n.push(u):m.transparent===!0?r.push(u):t.push(u)}function l(h,f,m,_,x,p){const u=a(h,f,m,_,x,p);m.transmission>0?n.unshift(u):m.transparent===!0?r.unshift(u):t.unshift(u)}function c(h,f){t.length>1&&t.sort(h||Gf),n.length>1&&n.sort(f||co),r.length>1&&r.sort(f||co)}function d(){for(let h=e,f=i.length;h=s.length?(a=new lo,s.push(a)):a=s[r],a}function t(){i=new WeakMap}return{get:e,dispose:t}}function kf(){const i={};return{get:function(e){if(i[e.id]!==void 0)return i[e.id];let t;switch(e.type){case"DirectionalLight":t={direction:new N,color:new Fe};break;case"SpotLight":t={position:new N,direction:new N,color:new Fe,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":t={position:new N,color:new Fe,distance:0,decay:0};break;case"HemisphereLight":t={direction:new N,skyColor:new Fe,groundColor:new Fe};break;case"RectAreaLight":t={color:new Fe,position:new N,halfWidth:new N,halfHeight:new N};break}return i[e.id]=t,t}}}function Wf(){const i={};return{get:function(e){if(i[e.id]!==void 0)return i[e.id];let t;switch(e.type){case"DirectionalLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge};break;case"SpotLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge};break;case"PointLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge,shadowCameraNear:1,shadowCameraFar:1e3};break}return i[e.id]=t,t}}}let Xf=0;function qf(i,e){return(e.castShadow?2:0)-(i.castShadow?2:0)+(e.map?1:0)-(i.map?1:0)}function Yf(i){const e=new kf,t=Wf(),n={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let c=0;c<9;c++)n.probe.push(new N);const r=new N,s=new it,a=new it;function o(c){let d=0,h=0,f=0;for(let S=0;S<9;S++)n.probe[S].set(0,0,0);let m=0,_=0,x=0,p=0,u=0,b=0,A=0,E=0,C=0,R=0,w=0;c.sort(qf);for(let S=0,M=c.length;S0&&(i.has("OES_texture_float_linear")===!0?(n.rectAreaLTC1=re.LTC_FLOAT_1,n.rectAreaLTC2=re.LTC_FLOAT_2):(n.rectAreaLTC1=re.LTC_HALF_1,n.rectAreaLTC2=re.LTC_HALF_2)),n.ambient[0]=d,n.ambient[1]=h,n.ambient[2]=f;const U=n.hash;(U.directionalLength!==m||U.pointLength!==_||U.spotLength!==x||U.rectAreaLength!==p||U.hemiLength!==u||U.numDirectionalShadows!==b||U.numPointShadows!==A||U.numSpotShadows!==E||U.numSpotMaps!==C||U.numLightProbes!==w)&&(n.directional.length=m,n.spot.length=x,n.rectArea.length=p,n.point.length=_,n.hemi.length=u,n.directionalShadow.length=b,n.directionalShadowMap.length=b,n.pointShadow.length=A,n.pointShadowMap.length=A,n.spotShadow.length=E,n.spotShadowMap.length=E,n.directionalShadowMatrix.length=b,n.pointShadowMatrix.length=A,n.spotLightMatrix.length=E+C-R,n.spotLightMap.length=C,n.numSpotLightShadowsWithMaps=R,n.numLightProbes=w,U.directionalLength=m,U.pointLength=_,U.spotLength=x,U.rectAreaLength=p,U.hemiLength=u,U.numDirectionalShadows=b,U.numPointShadows=A,U.numSpotShadows=E,U.numSpotMaps=C,U.numLightProbes=w,n.version=Xf++)}function l(c,d){let h=0,f=0,m=0,_=0,x=0;const p=d.matrixWorldInverse;for(let u=0,b=c.length;u=a.length?(o=new uo(i),a.push(o)):o=a[s],o}function n(){e=new WeakMap}return{get:t,dispose:n}}const Kf=`void main() { +`+ce+` +`+Ee)}else W!==""?console.warn("THREE.WebGLProgram: Program Info Log:",W):(X===""||Z==="")&&(se=!1);se&&(C.diagnostics={runnable:G,programLog:W,vertexShader:{log:X,prefix:p},fragmentShader:{log:Z,prefix:u}})}r.deleteShader(D),r.deleteShader(R),U=new ir(r,x),S=mf(r,x)}let U;this.getUniforms=function(){return U===void 0&&w(this),U};let S;this.getAttributes=function(){return S===void 0&&w(this),S};let M=t.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return M===!1&&(M=r.getProgramParameter(x,af)),M},this.destroy=function(){n.releaseStatesOfProgram(this),r.deleteProgram(x),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=of++,this.cacheKey=e,this.usedTimes=1,this.program=x,this.vertexShader=D,this.fragmentShader=R,this}let wf=0;class Rf{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(e){const t=e.vertexShader,n=e.fragmentShader,r=this._getShaderStage(t),s=this._getShaderStage(n),a=this._getShaderCacheForMaterial(e);return a.has(r)===!1&&(a.add(r),r.usedTimes++),a.has(s)===!1&&(a.add(s),s.usedTimes++),this}remove(e){const t=this.materialCache.get(e);for(const n of t)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(e),this}getVertexShaderID(e){return this._getShaderStage(e.vertexShader).id}getFragmentShaderID(e){return this._getShaderStage(e.fragmentShader).id}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(e){const t=this.materialCache;let n=t.get(e);return n===void 0&&(n=new Set,t.set(e,n)),n}_getShaderStage(e){const t=this.shaderCache;let n=t.get(e);return n===void 0&&(n=new Cf(e),t.set(e,n)),n}}class Cf{constructor(e){this.id=wf++,this.code=e,this.usedTimes=0}}function Pf(i,e,t,n,r,s,a){const o=new Gs,c=new Rf,l=new Set,h=[],d=r.logarithmicDepthBuffer,f=r.vertexTextures;let m=r.precision;const _={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function x(S){return l.add(S),S===0?"uv":`uv${S}`}function p(S,M,C,O,z){const q=O.fog,W=z.geometry,X=S.isMeshStandardMaterial?O.environment:null,Z=(S.isMeshStandardMaterial?t:e).get(S.envMap||X),G=Z&&Z.mapping===ar?Z.image.height:null,se=_[S.type];S.precision!==null&&(m=r.getMaxPrecision(S.precision),m!==S.precision&&console.warn("THREE.WebGLProgram.getParameters:",S.precision,"not supported, using",m,"instead."));const ce=W.morphAttributes.position||W.morphAttributes.normal||W.morphAttributes.color,Ee=ce!==void 0?ce.length:0;let Fe=0;W.morphAttributes.position!==void 0&&(Fe=1),W.morphAttributes.normal!==void 0&&(Fe=2),W.morphAttributes.color!==void 0&&(Fe=3);let Ke,Je,We,Y;if(se){const Xe=Vt[se];Ke=Xe.vertexShader,Je=Xe.fragmentShader}else Ke=S.vertexShader,Je=S.fragmentShader,c.update(S),We=c.getVertexShaderID(S),Y=c.getFragmentShaderID(S);const j=i.getRenderTarget(),de=i.state.buffers.depth.getReversed(),Ce=z.isInstancedMesh===!0,Se=z.isBatchedMesh===!0,ze=!!S.map,ft=!!S.matcap,T=!!Z,Qe=!!S.aoMap,De=!!S.lightMap,we=!!S.bumpMap,me=!!S.normalMap,et=!!S.displacementMap,ge=!!S.emissiveMap,Ue=!!S.metalnessMap,ut=!!S.roughnessMap,at=S.anisotropy>0,y=S.clearcoat>0,g=S.dispersion>0,N=S.iridescence>0,V=S.sheen>0,K=S.transmission>0,k=at&&!!S.anisotropyMap,Me=y&&!!S.clearcoatMap,ne=y&&!!S.clearcoatNormalMap,_e=y&&!!S.clearcoatRoughnessMap,ve=N&&!!S.iridescenceMap,ee=N&&!!S.iridescenceThicknessMap,le=V&&!!S.sheenColorMap,be=V&&!!S.sheenRoughnessMap,xe=!!S.specularMap,ae=!!S.specularColorMap,Le=!!S.specularIntensityMap,P=K&&!!S.transmissionMap,te=K&&!!S.thicknessMap,ie=!!S.gradientMap,he=!!S.alphaMap,J=S.alphaTest>0,$=!!S.alphaHash,pe=!!S.extensions;let Pe=pn;S.toneMapped&&(j===null||j.isXRRenderTarget===!0)&&(Pe=i.toneMapping);const Ze={shaderID:se,shaderType:S.type,shaderName:S.name,vertexShader:Ke,fragmentShader:Je,defines:S.defines,customVertexShaderID:We,customFragmentShaderID:Y,isRawShaderMaterial:S.isRawShaderMaterial===!0,glslVersion:S.glslVersion,precision:m,batching:Se,batchingColor:Se&&z._colorsTexture!==null,instancing:Ce,instancingColor:Ce&&z.instanceColor!==null,instancingMorph:Ce&&z.morphTexture!==null,supportsVertexTextures:f,outputColorSpace:j===null?i.outputColorSpace:j.isXRRenderTarget===!0?j.texture.colorSpace:ii,alphaToCoverage:!!S.alphaToCoverage,map:ze,matcap:ft,envMap:T,envMapMode:T&&Z.mapping,envMapCubeUVHeight:G,aoMap:Qe,lightMap:De,bumpMap:we,normalMap:me,displacementMap:f&&et,emissiveMap:ge,normalMapObjectSpace:me&&S.normalMapType===Ml,normalMapTangentSpace:me&&S.normalMapType===fo,metalnessMap:Ue,roughnessMap:ut,anisotropy:at,anisotropyMap:k,clearcoat:y,clearcoatMap:Me,clearcoatNormalMap:ne,clearcoatRoughnessMap:_e,dispersion:g,iridescence:N,iridescenceMap:ve,iridescenceThicknessMap:ee,sheen:V,sheenColorMap:le,sheenRoughnessMap:be,specularMap:xe,specularColorMap:ae,specularIntensityMap:Le,transmission:K,transmissionMap:P,thicknessMap:te,gradientMap:ie,opaque:S.transparent===!1&&S.blending===Jn&&S.alphaToCoverage===!1,alphaMap:he,alphaTest:J,alphaHash:$,combine:S.combine,mapUv:ze&&x(S.map.channel),aoMapUv:Qe&&x(S.aoMap.channel),lightMapUv:De&&x(S.lightMap.channel),bumpMapUv:we&&x(S.bumpMap.channel),normalMapUv:me&&x(S.normalMap.channel),displacementMapUv:et&&x(S.displacementMap.channel),emissiveMapUv:ge&&x(S.emissiveMap.channel),metalnessMapUv:Ue&&x(S.metalnessMap.channel),roughnessMapUv:ut&&x(S.roughnessMap.channel),anisotropyMapUv:k&&x(S.anisotropyMap.channel),clearcoatMapUv:Me&&x(S.clearcoatMap.channel),clearcoatNormalMapUv:ne&&x(S.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:_e&&x(S.clearcoatRoughnessMap.channel),iridescenceMapUv:ve&&x(S.iridescenceMap.channel),iridescenceThicknessMapUv:ee&&x(S.iridescenceThicknessMap.channel),sheenColorMapUv:le&&x(S.sheenColorMap.channel),sheenRoughnessMapUv:be&&x(S.sheenRoughnessMap.channel),specularMapUv:xe&&x(S.specularMap.channel),specularColorMapUv:ae&&x(S.specularColorMap.channel),specularIntensityMapUv:Le&&x(S.specularIntensityMap.channel),transmissionMapUv:P&&x(S.transmissionMap.channel),thicknessMapUv:te&&x(S.thicknessMap.channel),alphaMapUv:he&&x(S.alphaMap.channel),vertexTangents:!!W.attributes.tangent&&(me||at),vertexColors:S.vertexColors,vertexAlphas:S.vertexColors===!0&&!!W.attributes.color&&W.attributes.color.itemSize===4,pointsUvs:z.isPoints===!0&&!!W.attributes.uv&&(ze||he),fog:!!q,useFog:S.fog===!0,fogExp2:!!q&&q.isFogExp2,flatShading:S.flatShading===!0&&S.wireframe===!1,sizeAttenuation:S.sizeAttenuation===!0,logarithmicDepthBuffer:d,reversedDepthBuffer:de,skinning:z.isSkinnedMesh===!0,morphTargets:W.morphAttributes.position!==void 0,morphNormals:W.morphAttributes.normal!==void 0,morphColors:W.morphAttributes.color!==void 0,morphTargetsCount:Ee,morphTextureStride:Fe,numDirLights:M.directional.length,numPointLights:M.point.length,numSpotLights:M.spot.length,numSpotLightMaps:M.spotLightMap.length,numRectAreaLights:M.rectArea.length,numHemiLights:M.hemi.length,numDirLightShadows:M.directionalShadowMap.length,numPointLightShadows:M.pointShadowMap.length,numSpotLightShadows:M.spotShadowMap.length,numSpotLightShadowsWithMaps:M.numSpotLightShadowsWithMaps,numLightProbes:M.numLightProbes,numClippingPlanes:a.numPlanes,numClipIntersection:a.numIntersection,dithering:S.dithering,shadowMapEnabled:i.shadowMap.enabled&&C.length>0,shadowMapType:i.shadowMap.type,toneMapping:Pe,decodeVideoTexture:ze&&S.map.isVideoTexture===!0&&Ve.getTransfer(S.map.colorSpace)===Ye,decodeVideoTextureEmissive:ge&&S.emissiveMap.isVideoTexture===!0&&Ve.getTransfer(S.emissiveMap.colorSpace)===Ye,premultipliedAlpha:S.premultipliedAlpha,doubleSided:S.side===Bt,flipSided:S.side===Et,useDepthPacking:S.depthPacking>=0,depthPacking:S.depthPacking||0,index0AttributeName:S.index0AttributeName,extensionClipCullDistance:pe&&S.extensions.clipCullDistance===!0&&n.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(pe&&S.extensions.multiDraw===!0||Se)&&n.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:n.has("KHR_parallel_shader_compile"),customProgramCacheKey:S.customProgramCacheKey()};return Ze.vertexUv1s=l.has(1),Ze.vertexUv2s=l.has(2),Ze.vertexUv3s=l.has(3),l.clear(),Ze}function u(S){const M=[];if(S.shaderID?M.push(S.shaderID):(M.push(S.customVertexShaderID),M.push(S.customFragmentShaderID)),S.defines!==void 0)for(const C in S.defines)M.push(C),M.push(S.defines[C]);return S.isRawShaderMaterial===!1&&(b(M,S),A(M,S),M.push(i.outputColorSpace)),M.push(S.customProgramCacheKey),M.join()}function b(S,M){S.push(M.precision),S.push(M.outputColorSpace),S.push(M.envMapMode),S.push(M.envMapCubeUVHeight),S.push(M.mapUv),S.push(M.alphaMapUv),S.push(M.lightMapUv),S.push(M.aoMapUv),S.push(M.bumpMapUv),S.push(M.normalMapUv),S.push(M.displacementMapUv),S.push(M.emissiveMapUv),S.push(M.metalnessMapUv),S.push(M.roughnessMapUv),S.push(M.anisotropyMapUv),S.push(M.clearcoatMapUv),S.push(M.clearcoatNormalMapUv),S.push(M.clearcoatRoughnessMapUv),S.push(M.iridescenceMapUv),S.push(M.iridescenceThicknessMapUv),S.push(M.sheenColorMapUv),S.push(M.sheenRoughnessMapUv),S.push(M.specularMapUv),S.push(M.specularColorMapUv),S.push(M.specularIntensityMapUv),S.push(M.transmissionMapUv),S.push(M.thicknessMapUv),S.push(M.combine),S.push(M.fogExp2),S.push(M.sizeAttenuation),S.push(M.morphTargetsCount),S.push(M.morphAttributeCount),S.push(M.numDirLights),S.push(M.numPointLights),S.push(M.numSpotLights),S.push(M.numSpotLightMaps),S.push(M.numHemiLights),S.push(M.numRectAreaLights),S.push(M.numDirLightShadows),S.push(M.numPointLightShadows),S.push(M.numSpotLightShadows),S.push(M.numSpotLightShadowsWithMaps),S.push(M.numLightProbes),S.push(M.shadowMapType),S.push(M.toneMapping),S.push(M.numClippingPlanes),S.push(M.numClipIntersection),S.push(M.depthPacking)}function A(S,M){o.disableAll(),M.supportsVertexTextures&&o.enable(0),M.instancing&&o.enable(1),M.instancingColor&&o.enable(2),M.instancingMorph&&o.enable(3),M.matcap&&o.enable(4),M.envMap&&o.enable(5),M.normalMapObjectSpace&&o.enable(6),M.normalMapTangentSpace&&o.enable(7),M.clearcoat&&o.enable(8),M.iridescence&&o.enable(9),M.alphaTest&&o.enable(10),M.vertexColors&&o.enable(11),M.vertexAlphas&&o.enable(12),M.vertexUv1s&&o.enable(13),M.vertexUv2s&&o.enable(14),M.vertexUv3s&&o.enable(15),M.vertexTangents&&o.enable(16),M.anisotropy&&o.enable(17),M.alphaHash&&o.enable(18),M.batching&&o.enable(19),M.dispersion&&o.enable(20),M.batchingColor&&o.enable(21),M.gradientMap&&o.enable(22),S.push(o.mask),o.disableAll(),M.fog&&o.enable(0),M.useFog&&o.enable(1),M.flatShading&&o.enable(2),M.logarithmicDepthBuffer&&o.enable(3),M.reversedDepthBuffer&&o.enable(4),M.skinning&&o.enable(5),M.morphTargets&&o.enable(6),M.morphNormals&&o.enable(7),M.morphColors&&o.enable(8),M.premultipliedAlpha&&o.enable(9),M.shadowMapEnabled&&o.enable(10),M.doubleSided&&o.enable(11),M.flipSided&&o.enable(12),M.useDepthPacking&&o.enable(13),M.dithering&&o.enable(14),M.transmission&&o.enable(15),M.sheen&&o.enable(16),M.opaque&&o.enable(17),M.pointsUvs&&o.enable(18),M.decodeVideoTexture&&o.enable(19),M.decodeVideoTextureEmissive&&o.enable(20),M.alphaToCoverage&&o.enable(21),S.push(o.mask)}function E(S){const M=_[S.type];let C;if(M){const O=Vt[M];C=Kl.clone(O.uniforms)}else C=S.uniforms;return C}function D(S,M){let C;for(let O=0,z=h.length;O0?n.push(u):m.transparent===!0?r.push(u):t.push(u)}function c(d,f,m,_,x,p){const u=a(d,f,m,_,x,p);m.transmission>0?n.unshift(u):m.transparent===!0?r.unshift(u):t.unshift(u)}function l(d,f){t.length>1&&t.sort(d||Lf),n.length>1&&n.sort(f||Za),r.length>1&&r.sort(f||Za)}function h(){for(let d=e,f=i.length;d=s.length?(a=new ja,s.push(a)):a=s[r],a}function t(){i=new WeakMap}return{get:e,dispose:t}}function Uf(){const i={};return{get:function(e){if(i[e.id]!==void 0)return i[e.id];let t;switch(e.type){case"DirectionalLight":t={direction:new F,color:new Oe};break;case"SpotLight":t={position:new F,direction:new F,color:new Oe,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":t={position:new F,color:new Oe,distance:0,decay:0};break;case"HemisphereLight":t={direction:new F,skyColor:new Oe,groundColor:new Oe};break;case"RectAreaLight":t={color:new Oe,position:new F,halfWidth:new F,halfHeight:new F};break}return i[e.id]=t,t}}}function Nf(){const i={};return{get:function(e){if(i[e.id]!==void 0)return i[e.id];let t;switch(e.type){case"DirectionalLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge};break;case"SpotLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge};break;case"PointLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new Ge,shadowCameraNear:1,shadowCameraFar:1e3};break}return i[e.id]=t,t}}}let Ff=0;function Of(i,e){return(e.castShadow?2:0)-(i.castShadow?2:0)+(e.map?1:0)-(i.map?1:0)}function Bf(i){const e=new Uf,t=Nf(),n={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let l=0;l<9;l++)n.probe.push(new F);const r=new F,s=new st,a=new st;function o(l){let h=0,d=0,f=0;for(let S=0;S<9;S++)n.probe[S].set(0,0,0);let m=0,_=0,x=0,p=0,u=0,b=0,A=0,E=0,D=0,R=0,w=0;l.sort(Of);for(let S=0,M=l.length;S0&&(i.has("OES_texture_float_linear")===!0?(n.rectAreaLTC1=re.LTC_FLOAT_1,n.rectAreaLTC2=re.LTC_FLOAT_2):(n.rectAreaLTC1=re.LTC_HALF_1,n.rectAreaLTC2=re.LTC_HALF_2)),n.ambient[0]=h,n.ambient[1]=d,n.ambient[2]=f;const U=n.hash;(U.directionalLength!==m||U.pointLength!==_||U.spotLength!==x||U.rectAreaLength!==p||U.hemiLength!==u||U.numDirectionalShadows!==b||U.numPointShadows!==A||U.numSpotShadows!==E||U.numSpotMaps!==D||U.numLightProbes!==w)&&(n.directional.length=m,n.spot.length=x,n.rectArea.length=p,n.point.length=_,n.hemi.length=u,n.directionalShadow.length=b,n.directionalShadowMap.length=b,n.pointShadow.length=A,n.pointShadowMap.length=A,n.spotShadow.length=E,n.spotShadowMap.length=E,n.directionalShadowMatrix.length=b,n.pointShadowMatrix.length=A,n.spotLightMatrix.length=E+D-R,n.spotLightMap.length=D,n.numSpotLightShadowsWithMaps=R,n.numLightProbes=w,U.directionalLength=m,U.pointLength=_,U.spotLength=x,U.rectAreaLength=p,U.hemiLength=u,U.numDirectionalShadows=b,U.numPointShadows=A,U.numSpotShadows=E,U.numSpotMaps=D,U.numLightProbes=w,n.version=Ff++)}function c(l,h){let d=0,f=0,m=0,_=0,x=0;const p=h.matrixWorldInverse;for(let u=0,b=l.length;u=a.length?(o=new Ja(i),a.push(o)):o=a[s],o}function n(){e=new WeakMap}return{get:t,dispose:n}}const zf=`void main() { gl_Position = vec4( position, 1.0 ); -}`,Zf=`uniform sampler2D shadow_pass; +}`,Gf=`uniform sampler2D shadow_pass; uniform vec2 resolution; uniform float radius; #include @@ -3813,12 +3813,12 @@ void main() { squared_mean = squared_mean / samples; float std_dev = sqrt( squared_mean - mean * mean ); gl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) ); -}`;function jf(i,e,t){let n=new js;const r=new Ge,s=new Ge,a=new st,o=new _l({depthPacking:Rc}),l=new vl,c={},d=t.maxTextureSize,h={[pn]:yt,[yt]:pn,[kt]:kt},f=new mn({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new Ge},radius:{value:4}},vertexShader:Kf,fragmentShader:Zf}),m=f.clone();m.defines.HORIZONTAL_PASS=1;const _=new Nt;_.setAttribute("position",new qt(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const x=new Et(_,f),p=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=po;let u=this.type;this.render=function(R,w,U){if(p.enabled===!1||p.autoUpdate===!1&&p.needsUpdate===!1||R.length===0)return;const S=i.getRenderTarget(),M=i.getActiveCubeFace(),P=i.getActiveMipmapLevel(),O=i.state;O.setBlending(dn),O.buffers.depth.getReversed()===!0?O.buffers.color.setClear(0,0,0,0):O.buffers.color.setClear(1,1,1,1),O.buffers.depth.setTest(!0),O.setScissorTest(!1);const H=u!==tn&&this.type===tn,q=u===tn&&this.type!==tn;for(let W=0,X=R.length;Wd||r.y>d)&&(r.x>d&&(s.x=Math.floor(d/se.x),r.x=s.x*se.x,G.mapSize.x=s.x),r.y>d&&(s.y=Math.floor(d/se.y),r.y=s.y*se.y,G.mapSize.y=s.y)),G.map===null||H===!0||q===!0){const Ee=this.type!==tn?{minFilter:Ht,magFilter:Ht}:{};G.map!==null&&G.map.dispose(),G.map=new Dn(r.x,r.y,Ee),G.map.texture.name=Z.name+".shadowMap",G.camera.updateProjectionMatrix()}i.setRenderTarget(G.map),i.clear();const le=G.getViewportCount();for(let Ee=0;Ee0||w.map&&w.alphaTest>0||w.alphaToCoverage===!0){const O=M.uuid,H=w.uuid;let q=c[O];q===void 0&&(q={},c[O]=q);let W=q[H];W===void 0&&(W=M.clone(),q[H]=W,w.addEventListener("dispose",C)),M=W}if(M.visible=w.visible,M.wireframe=w.wireframe,S===tn?M.side=w.shadowSide!==null?w.shadowSide:w.side:M.side=w.shadowSide!==null?w.shadowSide:h[w.side],M.alphaMap=w.alphaMap,M.alphaTest=w.alphaToCoverage===!0?.5:w.alphaTest,M.map=w.map,M.clipShadows=w.clipShadows,M.clippingPlanes=w.clippingPlanes,M.clipIntersection=w.clipIntersection,M.displacementMap=w.displacementMap,M.displacementScale=w.displacementScale,M.displacementBias=w.displacementBias,M.wireframeLinewidth=w.wireframeLinewidth,M.linewidth=w.linewidth,U.isPointLight===!0&&M.isMeshDistanceMaterial===!0){const O=i.properties.get(M);O.light=U}return M}function E(R,w,U,S,M){if(R.visible===!1)return;if(R.layers.test(w.layers)&&(R.isMesh||R.isLine||R.isPoints)&&(R.castShadow||R.receiveShadow&&M===tn)&&(!R.frustumCulled||n.intersectsObject(R))){R.modelViewMatrix.multiplyMatrices(U.matrixWorldInverse,R.matrixWorld);const H=e.update(R),q=R.material;if(Array.isArray(q)){const W=H.groups;for(let X=0,Z=W.length;X=1):G.indexOf("OpenGL ES")!==-1&&(Z=parseFloat(/^OpenGL ES (\d)/.exec(G)[1]),X=Z>=2);let se=null,le={};const Ee=i.getParameter(i.SCISSOR_BOX),Oe=i.getParameter(i.VIEWPORT),Ke=new st().fromArray(Ee),Je=new st().fromArray(Oe);function We(D,te,ie,he){const J=new Uint8Array(4),$=i.createTexture();i.bindTexture(D,$),i.texParameteri(D,i.TEXTURE_MIN_FILTER,i.NEAREST),i.texParameteri(D,i.TEXTURE_MAG_FILTER,i.NEAREST);for(let pe=0;pe"u"?!1:/OculusBrowser/g.test(navigator.userAgent),c=new Ge,d=new WeakMap;let h;const f=new WeakMap;let m=!1;try{m=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function _(y,g){return m?new OffscreenCanvas(y,g):or("canvas")}function x(y,g,F){let k=1;const K=at(y);if((K.width>F||K.height>F)&&(k=F/Math.max(K.width,K.height)),k<1)if(typeof HTMLImageElement<"u"&&y instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&y instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&y instanceof ImageBitmap||typeof VideoFrame<"u"&&y instanceof VideoFrame){const V=Math.floor(k*K.width),Me=Math.floor(k*K.height);h===void 0&&(h=_(V,Me));const ne=g?_(V,Me):h;return ne.width=V,ne.height=Me,ne.getContext("2d").drawImage(y,0,0,V,Me),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+K.width+"x"+K.height+") to ("+V+"x"+Me+")."),ne}else return"data"in y&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+K.width+"x"+K.height+")."),y;return y}function p(y){return y.generateMipmaps}function u(y){i.generateMipmap(y)}function b(y){return y.isWebGLCubeRenderTarget?i.TEXTURE_CUBE_MAP:y.isWebGL3DRenderTarget?i.TEXTURE_3D:y.isWebGLArrayRenderTarget||y.isCompressedArrayTexture?i.TEXTURE_2D_ARRAY:i.TEXTURE_2D}function A(y,g,F,k,K=!1){if(y!==null){if(i[y]!==void 0)return i[y];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+y+"'")}let V=g;if(g===i.RED&&(F===i.FLOAT&&(V=i.R32F),F===i.HALF_FLOAT&&(V=i.R16F),F===i.UNSIGNED_BYTE&&(V=i.R8)),g===i.RED_INTEGER&&(F===i.UNSIGNED_BYTE&&(V=i.R8UI),F===i.UNSIGNED_SHORT&&(V=i.R16UI),F===i.UNSIGNED_INT&&(V=i.R32UI),F===i.BYTE&&(V=i.R8I),F===i.SHORT&&(V=i.R16I),F===i.INT&&(V=i.R32I)),g===i.RG&&(F===i.FLOAT&&(V=i.RG32F),F===i.HALF_FLOAT&&(V=i.RG16F),F===i.UNSIGNED_BYTE&&(V=i.RG8)),g===i.RG_INTEGER&&(F===i.UNSIGNED_BYTE&&(V=i.RG8UI),F===i.UNSIGNED_SHORT&&(V=i.RG16UI),F===i.UNSIGNED_INT&&(V=i.RG32UI),F===i.BYTE&&(V=i.RG8I),F===i.SHORT&&(V=i.RG16I),F===i.INT&&(V=i.RG32I)),g===i.RGB_INTEGER&&(F===i.UNSIGNED_BYTE&&(V=i.RGB8UI),F===i.UNSIGNED_SHORT&&(V=i.RGB16UI),F===i.UNSIGNED_INT&&(V=i.RGB32UI),F===i.BYTE&&(V=i.RGB8I),F===i.SHORT&&(V=i.RGB16I),F===i.INT&&(V=i.RGB32I)),g===i.RGBA_INTEGER&&(F===i.UNSIGNED_BYTE&&(V=i.RGBA8UI),F===i.UNSIGNED_SHORT&&(V=i.RGBA16UI),F===i.UNSIGNED_INT&&(V=i.RGBA32UI),F===i.BYTE&&(V=i.RGBA8I),F===i.SHORT&&(V=i.RGBA16I),F===i.INT&&(V=i.RGBA32I)),g===i.RGB&&(F===i.UNSIGNED_INT_5_9_9_9_REV&&(V=i.RGB9_E5),F===i.UNSIGNED_INT_10F_11F_11F_REV&&(V=i.R11F_G11F_B10F)),g===i.RGBA){const Me=K?sr:ke.getTransfer(k);F===i.FLOAT&&(V=i.RGBA32F),F===i.HALF_FLOAT&&(V=i.RGBA16F),F===i.UNSIGNED_BYTE&&(V=Me===Ye?i.SRGB8_ALPHA8:i.RGBA8),F===i.UNSIGNED_SHORT_4_4_4_4&&(V=i.RGBA4),F===i.UNSIGNED_SHORT_5_5_5_1&&(V=i.RGB5_A1)}return(V===i.R16F||V===i.R32F||V===i.RG16F||V===i.RG32F||V===i.RGBA16F||V===i.RGBA32F)&&e.get("EXT_color_buffer_float"),V}function E(y,g){let F;return y?g===null||g===Pn||g===mi?F=i.DEPTH24_STENCIL8:g===nn?F=i.DEPTH32F_STENCIL8:g===pi&&(F=i.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):g===null||g===Pn||g===mi?F=i.DEPTH_COMPONENT24:g===nn?F=i.DEPTH_COMPONENT32F:g===pi&&(F=i.DEPTH_COMPONENT16),F}function C(y,g){return p(y)===!0||y.isFramebufferTexture&&y.minFilter!==Ht&&y.minFilter!==Wt?Math.log2(Math.max(g.width,g.height))+1:y.mipmaps!==void 0&&y.mipmaps.length>0?y.mipmaps.length:y.isCompressedTexture&&Array.isArray(y.image)?g.mipmaps.length:1}function R(y){const g=y.target;g.removeEventListener("dispose",R),U(g),g.isVideoTexture&&d.delete(g)}function w(y){const g=y.target;g.removeEventListener("dispose",w),M(g)}function U(y){const g=n.get(y);if(g.__webglInit===void 0)return;const F=y.source,k=f.get(F);if(k){const K=k[g.__cacheKey];K.usedTimes--,K.usedTimes===0&&S(y),Object.keys(k).length===0&&f.delete(F)}n.remove(y)}function S(y){const g=n.get(y);i.deleteTexture(g.__webglTexture);const F=y.source,k=f.get(F);delete k[g.__cacheKey],a.memory.textures--}function M(y){const g=n.get(y);if(y.depthTexture&&(y.depthTexture.dispose(),n.remove(y.depthTexture)),y.isWebGLCubeRenderTarget)for(let k=0;k<6;k++){if(Array.isArray(g.__webglFramebuffer[k]))for(let K=0;K=r.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+y+" texture units while this GPU supports only "+r.maxTextures),P+=1,y}function q(y){const g=[];return g.push(y.wrapS),g.push(y.wrapT),g.push(y.wrapR||0),g.push(y.magFilter),g.push(y.minFilter),g.push(y.anisotropy),g.push(y.internalFormat),g.push(y.format),g.push(y.type),g.push(y.generateMipmaps),g.push(y.premultiplyAlpha),g.push(y.flipY),g.push(y.unpackAlignment),g.push(y.colorSpace),g.join()}function W(y,g){const F=n.get(y);if(y.isVideoTexture&&Ue(y),y.isRenderTargetTexture===!1&&y.isExternalTexture!==!0&&y.version>0&&F.__version!==y.version){const k=y.image;if(k===null)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else if(k.complete===!1)console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete");else{Y(F,y,g);return}}else y.isExternalTexture&&(F.__webglTexture=y.sourceTexture?y.sourceTexture:null);t.bindTexture(i.TEXTURE_2D,F.__webglTexture,i.TEXTURE0+g)}function X(y,g){const F=n.get(y);if(y.isRenderTargetTexture===!1&&y.version>0&&F.__version!==y.version){Y(F,y,g);return}t.bindTexture(i.TEXTURE_2D_ARRAY,F.__webglTexture,i.TEXTURE0+g)}function Z(y,g){const F=n.get(y);if(y.isRenderTargetTexture===!1&&y.version>0&&F.__version!==y.version){Y(F,y,g);return}t.bindTexture(i.TEXTURE_3D,F.__webglTexture,i.TEXTURE0+g)}function G(y,g){const F=n.get(y);if(y.version>0&&F.__version!==y.version){j(F,y,g);return}t.bindTexture(i.TEXTURE_CUBE_MAP,F.__webglTexture,i.TEXTURE0+g)}const se={[os]:i.REPEAT,[Rn]:i.CLAMP_TO_EDGE,[cs]:i.MIRRORED_REPEAT},le={[Ht]:i.NEAREST,[bc]:i.NEAREST_MIPMAP_NEAREST,[wi]:i.NEAREST_MIPMAP_LINEAR,[Wt]:i.LINEAR,[_r]:i.LINEAR_MIPMAP_NEAREST,[Cn]:i.LINEAR_MIPMAP_LINEAR},Ee={[Pc]:i.NEVER,[Fc]:i.ALWAYS,[Dc]:i.LESS,[bo]:i.LEQUAL,[Lc]:i.EQUAL,[Nc]:i.GEQUAL,[Ic]:i.GREATER,[Uc]:i.NOTEQUAL};function Oe(y,g){if(g.type===nn&&e.has("OES_texture_float_linear")===!1&&(g.magFilter===Wt||g.magFilter===_r||g.magFilter===wi||g.magFilter===Cn||g.minFilter===Wt||g.minFilter===_r||g.minFilter===wi||g.minFilter===Cn)&&console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),i.texParameteri(y,i.TEXTURE_WRAP_S,se[g.wrapS]),i.texParameteri(y,i.TEXTURE_WRAP_T,se[g.wrapT]),(y===i.TEXTURE_3D||y===i.TEXTURE_2D_ARRAY)&&i.texParameteri(y,i.TEXTURE_WRAP_R,se[g.wrapR]),i.texParameteri(y,i.TEXTURE_MAG_FILTER,le[g.magFilter]),i.texParameteri(y,i.TEXTURE_MIN_FILTER,le[g.minFilter]),g.compareFunction&&(i.texParameteri(y,i.TEXTURE_COMPARE_MODE,i.COMPARE_REF_TO_TEXTURE),i.texParameteri(y,i.TEXTURE_COMPARE_FUNC,Ee[g.compareFunction])),e.has("EXT_texture_filter_anisotropic")===!0){if(g.magFilter===Ht||g.minFilter!==wi&&g.minFilter!==Cn||g.type===nn&&e.has("OES_texture_float_linear")===!1)return;if(g.anisotropy>1||n.get(g).__currentAnisotropy){const F=e.get("EXT_texture_filter_anisotropic");i.texParameterf(y,F.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(g.anisotropy,r.getMaxAnisotropy())),n.get(g).__currentAnisotropy=g.anisotropy}}}function Ke(y,g){let F=!1;y.__webglInit===void 0&&(y.__webglInit=!0,g.addEventListener("dispose",R));const k=g.source;let K=f.get(k);K===void 0&&(K={},f.set(k,K));const V=q(g);if(V!==y.__cacheKey){K[V]===void 0&&(K[V]={texture:i.createTexture(),usedTimes:0},a.memory.textures++,F=!0),K[V].usedTimes++;const Me=K[y.__cacheKey];Me!==void 0&&(K[y.__cacheKey].usedTimes--,Me.usedTimes===0&&S(g)),y.__cacheKey=V,y.__webglTexture=K[V].texture}return F}function Je(y,g,F){return Math.floor(Math.floor(y/F)/g)}function We(y,g,F,k){const V=y.updateRanges;if(V.length===0)t.texSubImage2D(i.TEXTURE_2D,0,0,0,g.width,g.height,F,k,g.data);else{V.sort((ee,ce)=>ee.start-ce.start);let Me=0;for(let ee=1;ee0){D&&te&&t.texStorage2D(i.TEXTURE_2D,he,xe,Le[0].width,Le[0].height);for(let J=0,$=Le.length;J<$;J++)ae=Le[J],D?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,ce,be,ae.data):t.texImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,ce,be,ae.data);g.generateMipmaps=!1}else D?(te&&t.texStorage2D(i.TEXTURE_2D,he,xe,ee.width,ee.height),ie&&We(g,ee,ce,be)):t.texImage2D(i.TEXTURE_2D,0,xe,ee.width,ee.height,0,ce,be,ee.data);else if(g.isCompressedTexture)if(g.isCompressedArrayTexture){D&&te&&t.texStorage3D(i.TEXTURE_2D_ARRAY,he,xe,Le[0].width,Le[0].height,ee.depth);for(let J=0,$=Le.length;J<$;J++)if(ae=Le[J],g.format!==zt)if(ce!==null)if(D){if(ie)if(g.layerUpdates.size>0){const pe=Ha(ae.width,ae.height,g.format,g.type);for(const Pe of g.layerUpdates){const Ze=ae.data.subarray(Pe*pe/ae.data.BYTES_PER_ELEMENT,(Pe+1)*pe/ae.data.BYTES_PER_ELEMENT);t.compressedTexSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,Pe,ae.width,ae.height,1,ce,Ze)}g.clearLayerUpdates()}else t.compressedTexSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,0,ae.width,ae.height,ee.depth,ce,ae.data)}else t.compressedTexImage3D(i.TEXTURE_2D_ARRAY,J,xe,ae.width,ae.height,ee.depth,0,ae.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else D?ie&&t.texSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,0,ae.width,ae.height,ee.depth,ce,be,ae.data):t.texImage3D(i.TEXTURE_2D_ARRAY,J,xe,ae.width,ae.height,ee.depth,0,ce,be,ae.data)}else{D&&te&&t.texStorage2D(i.TEXTURE_2D,he,xe,Le[0].width,Le[0].height);for(let J=0,$=Le.length;J<$;J++)ae=Le[J],g.format!==zt?ce!==null?D?ie&&t.compressedTexSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,ce,ae.data):t.compressedTexImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,ae.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):D?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,ce,be,ae.data):t.texImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,ce,be,ae.data)}else if(g.isDataArrayTexture)if(D){if(te&&t.texStorage3D(i.TEXTURE_2D_ARRAY,he,xe,ee.width,ee.height,ee.depth),ie)if(g.layerUpdates.size>0){const J=Ha(ee.width,ee.height,g.format,g.type);for(const $ of g.layerUpdates){const pe=ee.data.subarray($*J/ee.data.BYTES_PER_ELEMENT,($+1)*J/ee.data.BYTES_PER_ELEMENT);t.texSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,$,ee.width,ee.height,1,ce,be,pe)}g.clearLayerUpdates()}else t.texSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,0,ee.width,ee.height,ee.depth,ce,be,ee.data)}else t.texImage3D(i.TEXTURE_2D_ARRAY,0,xe,ee.width,ee.height,ee.depth,0,ce,be,ee.data);else if(g.isData3DTexture)D?(te&&t.texStorage3D(i.TEXTURE_3D,he,xe,ee.width,ee.height,ee.depth),ie&&t.texSubImage3D(i.TEXTURE_3D,0,0,0,0,ee.width,ee.height,ee.depth,ce,be,ee.data)):t.texImage3D(i.TEXTURE_3D,0,xe,ee.width,ee.height,ee.depth,0,ce,be,ee.data);else if(g.isFramebufferTexture){if(te)if(D)t.texStorage2D(i.TEXTURE_2D,he,xe,ee.width,ee.height);else{let J=ee.width,$=ee.height;for(let pe=0;pe>=1,$>>=1}}else if(Le.length>0){if(D&&te){const J=at(Le[0]);t.texStorage2D(i.TEXTURE_2D,he,xe,J.width,J.height)}for(let J=0,$=Le.length;J<$;J++)ae=Le[J],D?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,ce,be,ae):t.texImage2D(i.TEXTURE_2D,J,xe,ce,be,ae);g.generateMipmaps=!1}else if(D){if(te){const J=at(ee);t.texStorage2D(i.TEXTURE_2D,he,xe,J.width,J.height)}ie&&t.texSubImage2D(i.TEXTURE_2D,0,0,0,ce,be,ee)}else t.texImage2D(i.TEXTURE_2D,0,xe,ce,be,ee);p(g)&&u(k),Me.__version=V.version,g.onUpdate&&g.onUpdate(g)}y.__version=g.version}function j(y,g,F){if(g.image.length!==6)return;const k=Ke(y,g),K=g.source;t.bindTexture(i.TEXTURE_CUBE_MAP,y.__webglTexture,i.TEXTURE0+F);const V=n.get(K);if(K.version!==V.__version||k===!0){t.activeTexture(i.TEXTURE0+F);const Me=ke.getPrimaries(ke.workingColorSpace),ne=g.colorSpace===hn?null:ke.getPrimaries(g.colorSpace),_e=g.colorSpace===hn||Me===ne?i.NONE:i.BROWSER_DEFAULT_WEBGL;i.pixelStorei(i.UNPACK_FLIP_Y_WEBGL,g.flipY),i.pixelStorei(i.UNPACK_PREMULTIPLY_ALPHA_WEBGL,g.premultiplyAlpha),i.pixelStorei(i.UNPACK_ALIGNMENT,g.unpackAlignment),i.pixelStorei(i.UNPACK_COLORSPACE_CONVERSION_WEBGL,_e);const ve=g.isCompressedTexture||g.image[0].isCompressedTexture,ee=g.image[0]&&g.image[0].isDataTexture,ce=[];for(let $=0;$<6;$++)!ve&&!ee?ce[$]=x(g.image[$],!0,r.maxCubemapSize):ce[$]=ee?g.image[$].image:g.image[$],ce[$]=ht(g,ce[$]);const be=ce[0],xe=s.convert(g.format,g.colorSpace),ae=s.convert(g.type),Le=A(g.internalFormat,xe,ae,g.colorSpace),D=g.isVideoTexture!==!0,te=V.__version===void 0||k===!0,ie=K.dataReady;let he=C(g,be);Oe(i.TEXTURE_CUBE_MAP,g);let J;if(ve){D&&te&&t.texStorage2D(i.TEXTURE_CUBE_MAP,he,Le,be.width,be.height);for(let $=0;$<6;$++){J=ce[$].mipmaps;for(let pe=0;pe0&&he++;const $=at(ce[0]);t.texStorage2D(i.TEXTURE_CUBE_MAP,he,Le,$.width,$.height)}for(let $=0;$<6;$++)if(ee){D?ie&&t.texSubImage2D(i.TEXTURE_CUBE_MAP_POSITIVE_X+$,0,0,0,ce[$].width,ce[$].height,xe,ae,ce[$].data):t.texImage2D(i.TEXTURE_CUBE_MAP_POSITIVE_X+$,0,Le,ce[$].width,ce[$].height,0,xe,ae,ce[$].data);for(let pe=0;pe>V),be=Math.max(1,g.height>>V);K===i.TEXTURE_3D||K===i.TEXTURE_2D_ARRAY?t.texImage3D(K,V,_e,ce,be,g.depth,0,Me,ne,null):t.texImage2D(K,V,_e,ce,be,0,Me,ne,null)}t.bindFramebuffer(i.FRAMEBUFFER,y),ge(g)?o.framebufferTexture2DMultisampleEXT(i.FRAMEBUFFER,k,K,ee.__webglTexture,0,et(g)):(K===i.TEXTURE_2D||K>=i.TEXTURE_CUBE_MAP_POSITIVE_X&&K<=i.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&i.framebufferTexture2D(i.FRAMEBUFFER,k,K,ee.__webglTexture,V),t.bindFramebuffer(i.FRAMEBUFFER,null)}function Ce(y,g,F){if(i.bindRenderbuffer(i.RENDERBUFFER,y),g.depthBuffer){const k=g.depthTexture,K=k&&k.isDepthTexture?k.type:null,V=E(g.stencilBuffer,K),Me=g.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,ne=et(g);ge(g)?o.renderbufferStorageMultisampleEXT(i.RENDERBUFFER,ne,V,g.width,g.height):F?i.renderbufferStorageMultisample(i.RENDERBUFFER,ne,V,g.width,g.height):i.renderbufferStorage(i.RENDERBUFFER,V,g.width,g.height),i.framebufferRenderbuffer(i.FRAMEBUFFER,Me,i.RENDERBUFFER,y)}else{const k=g.textures;for(let K=0;K{delete g.__boundDepthTexture,delete g.__depthDisposeCallback,k.removeEventListener("dispose",K)};k.addEventListener("dispose",K),g.__depthDisposeCallback=K}g.__boundDepthTexture=k}if(y.depthTexture&&!g.__autoAllocateDepthBuffer){if(F)throw new Error("target.depthTexture not supported in Cube render targets");const k=y.texture.mipmaps;k&&k.length>0?Se(g.__webglFramebuffer[0],y):Se(g.__webglFramebuffer,y)}else if(F){g.__webglDepthbuffer=[];for(let k=0;k<6;k++)if(t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer[k]),g.__webglDepthbuffer[k]===void 0)g.__webglDepthbuffer[k]=i.createRenderbuffer(),Ce(g.__webglDepthbuffer[k],y,!1);else{const K=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,V=g.__webglDepthbuffer[k];i.bindRenderbuffer(i.RENDERBUFFER,V),i.framebufferRenderbuffer(i.FRAMEBUFFER,K,i.RENDERBUFFER,V)}}else{const k=y.texture.mipmaps;if(k&&k.length>0?t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer[0]):t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer),g.__webglDepthbuffer===void 0)g.__webglDepthbuffer=i.createRenderbuffer(),Ce(g.__webglDepthbuffer,y,!1);else{const K=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,V=g.__webglDepthbuffer;i.bindRenderbuffer(i.RENDERBUFFER,V),i.framebufferRenderbuffer(i.FRAMEBUFFER,K,i.RENDERBUFFER,V)}}t.bindFramebuffer(i.FRAMEBUFFER,null)}function mt(y,g,F){const k=n.get(y);g!==void 0&&de(k.__webglFramebuffer,y,y.texture,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,0),F!==void 0&&He(y)}function T(y){const g=y.texture,F=n.get(y),k=n.get(g);y.addEventListener("dispose",w);const K=y.textures,V=y.isWebGLCubeRenderTarget===!0,Me=K.length>1;if(Me||(k.__webglTexture===void 0&&(k.__webglTexture=i.createTexture()),k.__version=g.version,a.memory.textures++),V){F.__webglFramebuffer=[];for(let ne=0;ne<6;ne++)if(g.mipmaps&&g.mipmaps.length>0){F.__webglFramebuffer[ne]=[];for(let _e=0;_e0){F.__webglFramebuffer=[];for(let ne=0;ne0&&ge(y)===!1){F.__webglMultisampledFramebuffer=i.createFramebuffer(),F.__webglColorRenderbuffer=[],t.bindFramebuffer(i.FRAMEBUFFER,F.__webglMultisampledFramebuffer);for(let ne=0;ne0)for(let _e=0;_e0)for(let _e=0;_e0){if(ge(y)===!1){const g=y.textures,F=y.width,k=y.height;let K=i.COLOR_BUFFER_BIT;const V=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,Me=n.get(y),ne=g.length>1;if(ne)for(let ve=0;ve0?t.bindFramebuffer(i.DRAW_FRAMEBUFFER,Me.__webglFramebuffer[0]):t.bindFramebuffer(i.DRAW_FRAMEBUFFER,Me.__webglFramebuffer);for(let ve=0;ve0&&e.has("WEBGL_multisampled_render_to_texture")===!0&&g.__useRenderToTexture!==!1}function Ue(y){const g=a.render.frame;d.get(y)!==g&&(d.set(y,g),y.update())}function ht(y,g){const F=y.colorSpace,k=y.format,K=y.type;return y.isCompressedTexture===!0||y.isVideoTexture===!0||F!==Qn&&F!==hn&&(ke.getTransfer(F)===Ye?(k!==zt||K!==Yt)&&console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",F)),g}function at(y){return typeof HTMLImageElement<"u"&&y instanceof HTMLImageElement?(c.width=y.naturalWidth||y.width,c.height=y.naturalHeight||y.height):typeof VideoFrame<"u"&&y instanceof VideoFrame?(c.width=y.displayWidth,c.height=y.displayHeight):(c.width=y.width,c.height=y.height),c}this.allocateTextureUnit=H,this.resetTextureUnits=O,this.setTexture2D=W,this.setTexture2DArray=X,this.setTexture3D=Z,this.setTextureCube=G,this.rebindTextures=mt,this.setupRenderTarget=T,this.updateRenderTargetMipmap=Qe,this.updateMultisampleRenderTarget=me,this.setupDepthRenderbuffer=He,this.setupFrameBufferTexture=de,this.useMultisampledRTT=ge}function tp(i,e){function t(n,r=hn){let s;const a=ke.getTransfer(r);if(n===Yt)return i.UNSIGNED_BYTE;if(n===ks)return i.UNSIGNED_SHORT_4_4_4_4;if(n===Ws)return i.UNSIGNED_SHORT_5_5_5_1;if(n===xo)return i.UNSIGNED_INT_5_9_9_9_REV;if(n===Mo)return i.UNSIGNED_INT_10F_11F_11F_REV;if(n===_o)return i.BYTE;if(n===vo)return i.SHORT;if(n===pi)return i.UNSIGNED_SHORT;if(n===Vs)return i.INT;if(n===Pn)return i.UNSIGNED_INT;if(n===nn)return i.FLOAT;if(n===xi)return i.HALF_FLOAT;if(n===So)return i.ALPHA;if(n===Eo)return i.RGB;if(n===zt)return i.RGBA;if(n===gi)return i.DEPTH_COMPONENT;if(n===_i)return i.DEPTH_STENCIL;if(n===yo)return i.RED;if(n===Xs)return i.RED_INTEGER;if(n===To)return i.RG;if(n===qs)return i.RG_INTEGER;if(n===Ys)return i.RGBA_INTEGER;if(n===Qi||n===er||n===tr||n===nr)if(a===Ye)if(s=e.get("WEBGL_compressed_texture_s3tc_srgb"),s!==null){if(n===Qi)return s.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(n===er)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(n===tr)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(n===nr)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(s=e.get("WEBGL_compressed_texture_s3tc"),s!==null){if(n===Qi)return s.COMPRESSED_RGB_S3TC_DXT1_EXT;if(n===er)return s.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(n===tr)return s.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(n===nr)return s.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(n===ls||n===us||n===hs||n===ds)if(s=e.get("WEBGL_compressed_texture_pvrtc"),s!==null){if(n===ls)return s.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(n===us)return s.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(n===hs)return s.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(n===ds)return s.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(n===fs||n===ps||n===ms)if(s=e.get("WEBGL_compressed_texture_etc"),s!==null){if(n===fs||n===ps)return a===Ye?s.COMPRESSED_SRGB8_ETC2:s.COMPRESSED_RGB8_ETC2;if(n===ms)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:s.COMPRESSED_RGBA8_ETC2_EAC}else return null;if(n===gs||n===_s||n===vs||n===xs||n===Ms||n===Ss||n===Es||n===ys||n===Ts||n===As||n===bs||n===ws||n===Rs||n===Cs)if(s=e.get("WEBGL_compressed_texture_astc"),s!==null){if(n===gs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:s.COMPRESSED_RGBA_ASTC_4x4_KHR;if(n===_s)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:s.COMPRESSED_RGBA_ASTC_5x4_KHR;if(n===vs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:s.COMPRESSED_RGBA_ASTC_5x5_KHR;if(n===xs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:s.COMPRESSED_RGBA_ASTC_6x5_KHR;if(n===Ms)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:s.COMPRESSED_RGBA_ASTC_6x6_KHR;if(n===Ss)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:s.COMPRESSED_RGBA_ASTC_8x5_KHR;if(n===Es)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:s.COMPRESSED_RGBA_ASTC_8x6_KHR;if(n===ys)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:s.COMPRESSED_RGBA_ASTC_8x8_KHR;if(n===Ts)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:s.COMPRESSED_RGBA_ASTC_10x5_KHR;if(n===As)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:s.COMPRESSED_RGBA_ASTC_10x6_KHR;if(n===bs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:s.COMPRESSED_RGBA_ASTC_10x8_KHR;if(n===ws)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:s.COMPRESSED_RGBA_ASTC_10x10_KHR;if(n===Rs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:s.COMPRESSED_RGBA_ASTC_12x10_KHR;if(n===Cs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:s.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(n===Ps||n===Ds||n===Ls)if(s=e.get("EXT_texture_compression_bptc"),s!==null){if(n===Ps)return a===Ye?s.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:s.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(n===Ds)return s.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(n===Ls)return s.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(n===Is||n===Us||n===Ns||n===Fs)if(s=e.get("EXT_texture_compression_rgtc"),s!==null){if(n===Is)return s.COMPRESSED_RED_RGTC1_EXT;if(n===Us)return s.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(n===Ns)return s.COMPRESSED_RED_GREEN_RGTC2_EXT;if(n===Fs)return s.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return n===mi?i.UNSIGNED_INT_24_8:i[n]!==void 0?i[n]:null}return{convert:t}}const np=` +}`;function kf(i,e,t){let n=new ks;const r=new Ge,s=new Ge,a=new rt,o=new sc({depthPacking:xl}),c=new ac,l={},h=t.maxTextureSize,d={[mn]:Et,[Et]:mn,[Bt]:Bt},f=new gn({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new Ge},radius:{value:4}},vertexShader:zf,fragmentShader:Gf}),m=f.clone();m.defines.HORIZONTAL_PASS=1;const _=new sn;_.setAttribute("position",new Xt(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const x=new wt(_,f),p=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=to;let u=this.type;this.render=function(R,w,U){if(p.enabled===!1||p.autoUpdate===!1&&p.needsUpdate===!1||R.length===0)return;const S=i.getRenderTarget(),M=i.getActiveCubeFace(),C=i.getActiveMipmapLevel(),O=i.state;O.setBlending(fn),O.buffers.depth.getReversed()===!0?O.buffers.color.setClear(0,0,0,0):O.buffers.color.setClear(1,1,1,1),O.buffers.depth.setTest(!0),O.setScissorTest(!1);const z=u!==en&&this.type===en,q=u===en&&this.type!==en;for(let W=0,X=R.length;Wh||r.y>h)&&(r.x>h&&(s.x=Math.floor(h/se.x),r.x=s.x*se.x,G.mapSize.x=s.x),r.y>h&&(s.y=Math.floor(h/se.y),r.y=s.y*se.y,G.mapSize.y=s.y)),G.map===null||z===!0||q===!0){const Ee=this.type!==en?{minFilter:Gt,magFilter:Gt}:{};G.map!==null&&G.map.dispose(),G.map=new In(r.x,r.y,Ee),G.map.texture.name=Z.name+".shadowMap",G.camera.updateProjectionMatrix()}i.setRenderTarget(G.map),i.clear();const ce=G.getViewportCount();for(let Ee=0;Ee0||w.map&&w.alphaTest>0||w.alphaToCoverage===!0){const O=M.uuid,z=w.uuid;let q=l[O];q===void 0&&(q={},l[O]=q);let W=q[z];W===void 0&&(W=M.clone(),q[z]=W,w.addEventListener("dispose",D)),M=W}if(M.visible=w.visible,M.wireframe=w.wireframe,S===en?M.side=w.shadowSide!==null?w.shadowSide:w.side:M.side=w.shadowSide!==null?w.shadowSide:d[w.side],M.alphaMap=w.alphaMap,M.alphaTest=w.alphaToCoverage===!0?.5:w.alphaTest,M.map=w.map,M.clipShadows=w.clipShadows,M.clippingPlanes=w.clippingPlanes,M.clipIntersection=w.clipIntersection,M.displacementMap=w.displacementMap,M.displacementScale=w.displacementScale,M.displacementBias=w.displacementBias,M.wireframeLinewidth=w.wireframeLinewidth,M.linewidth=w.linewidth,U.isPointLight===!0&&M.isMeshDistanceMaterial===!0){const O=i.properties.get(M);O.light=U}return M}function E(R,w,U,S,M){if(R.visible===!1)return;if(R.layers.test(w.layers)&&(R.isMesh||R.isLine||R.isPoints)&&(R.castShadow||R.receiveShadow&&M===en)&&(!R.frustumCulled||n.intersectsObject(R))){R.modelViewMatrix.multiplyMatrices(U.matrixWorldInverse,R.matrixWorld);const z=e.update(R),q=R.material;if(Array.isArray(q)){const W=z.groups;for(let X=0,Z=W.length;X=1):G.indexOf("OpenGL ES")!==-1&&(Z=parseFloat(/^OpenGL ES (\d)/.exec(G)[1]),X=Z>=2);let se=null,ce={};const Ee=i.getParameter(i.SCISSOR_BOX),Fe=i.getParameter(i.VIEWPORT),Ke=new rt().fromArray(Ee),Je=new rt().fromArray(Fe);function We(P,te,ie,he){const J=new Uint8Array(4),$=i.createTexture();i.bindTexture(P,$),i.texParameteri(P,i.TEXTURE_MIN_FILTER,i.NEAREST),i.texParameteri(P,i.TEXTURE_MAG_FILTER,i.NEAREST);for(let pe=0;pe"u"?!1:/OculusBrowser/g.test(navigator.userAgent),l=new Ge,h=new WeakMap;let d;const f=new WeakMap;let m=!1;try{m=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function _(y,g){return m?new OffscreenCanvas(y,g):Si("canvas")}function x(y,g,N){let V=1;const K=at(y);if((K.width>N||K.height>N)&&(V=N/Math.max(K.width,K.height)),V<1)if(typeof HTMLImageElement<"u"&&y instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&y instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&y instanceof ImageBitmap||typeof VideoFrame<"u"&&y instanceof VideoFrame){const k=Math.floor(V*K.width),Me=Math.floor(V*K.height);d===void 0&&(d=_(k,Me));const ne=g?_(k,Me):d;return ne.width=k,ne.height=Me,ne.getContext("2d").drawImage(y,0,0,k,Me),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+K.width+"x"+K.height+") to ("+k+"x"+Me+")."),ne}else return"data"in y&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+K.width+"x"+K.height+")."),y;return y}function p(y){return y.generateMipmaps}function u(y){i.generateMipmap(y)}function b(y){return y.isWebGLCubeRenderTarget?i.TEXTURE_CUBE_MAP:y.isWebGL3DRenderTarget?i.TEXTURE_3D:y.isWebGLArrayRenderTarget||y.isCompressedArrayTexture?i.TEXTURE_2D_ARRAY:i.TEXTURE_2D}function A(y,g,N,V,K=!1){if(y!==null){if(i[y]!==void 0)return i[y];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+y+"'")}let k=g;if(g===i.RED&&(N===i.FLOAT&&(k=i.R32F),N===i.HALF_FLOAT&&(k=i.R16F),N===i.UNSIGNED_BYTE&&(k=i.R8)),g===i.RED_INTEGER&&(N===i.UNSIGNED_BYTE&&(k=i.R8UI),N===i.UNSIGNED_SHORT&&(k=i.R16UI),N===i.UNSIGNED_INT&&(k=i.R32UI),N===i.BYTE&&(k=i.R8I),N===i.SHORT&&(k=i.R16I),N===i.INT&&(k=i.R32I)),g===i.RG&&(N===i.FLOAT&&(k=i.RG32F),N===i.HALF_FLOAT&&(k=i.RG16F),N===i.UNSIGNED_BYTE&&(k=i.RG8)),g===i.RG_INTEGER&&(N===i.UNSIGNED_BYTE&&(k=i.RG8UI),N===i.UNSIGNED_SHORT&&(k=i.RG16UI),N===i.UNSIGNED_INT&&(k=i.RG32UI),N===i.BYTE&&(k=i.RG8I),N===i.SHORT&&(k=i.RG16I),N===i.INT&&(k=i.RG32I)),g===i.RGB_INTEGER&&(N===i.UNSIGNED_BYTE&&(k=i.RGB8UI),N===i.UNSIGNED_SHORT&&(k=i.RGB16UI),N===i.UNSIGNED_INT&&(k=i.RGB32UI),N===i.BYTE&&(k=i.RGB8I),N===i.SHORT&&(k=i.RGB16I),N===i.INT&&(k=i.RGB32I)),g===i.RGBA_INTEGER&&(N===i.UNSIGNED_BYTE&&(k=i.RGBA8UI),N===i.UNSIGNED_SHORT&&(k=i.RGBA16UI),N===i.UNSIGNED_INT&&(k=i.RGBA32UI),N===i.BYTE&&(k=i.RGBA8I),N===i.SHORT&&(k=i.RGBA16I),N===i.INT&&(k=i.RGBA32I)),g===i.RGB&&(N===i.UNSIGNED_INT_5_9_9_9_REV&&(k=i.RGB9_E5),N===i.UNSIGNED_INT_10F_11F_11F_REV&&(k=i.R11F_G11F_B10F)),g===i.RGBA){const Me=K?rr:Ve.getTransfer(V);N===i.FLOAT&&(k=i.RGBA32F),N===i.HALF_FLOAT&&(k=i.RGBA16F),N===i.UNSIGNED_BYTE&&(k=Me===Ye?i.SRGB8_ALPHA8:i.RGBA8),N===i.UNSIGNED_SHORT_4_4_4_4&&(k=i.RGBA4),N===i.UNSIGNED_SHORT_5_5_5_1&&(k=i.RGB5_A1)}return(k===i.R16F||k===i.R32F||k===i.RG16F||k===i.RG32F||k===i.RGBA16F||k===i.RGBA32F)&&e.get("EXT_color_buffer_float"),k}function E(y,g){let N;return y?g===null||g===Ln||g===vi?N=i.DEPTH24_STENCIL8:g===nn?N=i.DEPTH32F_STENCIL8:g===_i&&(N=i.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):g===null||g===Ln||g===vi?N=i.DEPTH_COMPONENT24:g===nn?N=i.DEPTH_COMPONENT32F:g===_i&&(N=i.DEPTH_COMPONENT16),N}function D(y,g){return p(y)===!0||y.isFramebufferTexture&&y.minFilter!==Gt&&y.minFilter!==Ut?Math.log2(Math.max(g.width,g.height))+1:y.mipmaps!==void 0&&y.mipmaps.length>0?y.mipmaps.length:y.isCompressedTexture&&Array.isArray(y.image)?g.mipmaps.length:1}function R(y){const g=y.target;g.removeEventListener("dispose",R),U(g),g.isVideoTexture&&h.delete(g)}function w(y){const g=y.target;g.removeEventListener("dispose",w),M(g)}function U(y){const g=n.get(y);if(g.__webglInit===void 0)return;const N=y.source,V=f.get(N);if(V){const K=V[g.__cacheKey];K.usedTimes--,K.usedTimes===0&&S(y),Object.keys(V).length===0&&f.delete(N)}n.remove(y)}function S(y){const g=n.get(y);i.deleteTexture(g.__webglTexture);const N=y.source,V=f.get(N);delete V[g.__cacheKey],a.memory.textures--}function M(y){const g=n.get(y);if(y.depthTexture&&(y.depthTexture.dispose(),n.remove(y.depthTexture)),y.isWebGLCubeRenderTarget)for(let V=0;V<6;V++){if(Array.isArray(g.__webglFramebuffer[V]))for(let K=0;K=r.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+y+" texture units while this GPU supports only "+r.maxTextures),C+=1,y}function q(y){const g=[];return g.push(y.wrapS),g.push(y.wrapT),g.push(y.wrapR||0),g.push(y.magFilter),g.push(y.minFilter),g.push(y.anisotropy),g.push(y.internalFormat),g.push(y.format),g.push(y.type),g.push(y.generateMipmaps),g.push(y.premultiplyAlpha),g.push(y.flipY),g.push(y.unpackAlignment),g.push(y.colorSpace),g.join()}function W(y,g){const N=n.get(y);if(y.isVideoTexture&&Ue(y),y.isRenderTargetTexture===!1&&y.isExternalTexture!==!0&&y.version>0&&N.__version!==y.version){const V=y.image;if(V===null)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else if(V.complete===!1)console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete");else{Y(N,y,g);return}}else y.isExternalTexture&&(N.__webglTexture=y.sourceTexture?y.sourceTexture:null);t.bindTexture(i.TEXTURE_2D,N.__webglTexture,i.TEXTURE0+g)}function X(y,g){const N=n.get(y);if(y.isRenderTargetTexture===!1&&y.version>0&&N.__version!==y.version){Y(N,y,g);return}t.bindTexture(i.TEXTURE_2D_ARRAY,N.__webglTexture,i.TEXTURE0+g)}function Z(y,g){const N=n.get(y);if(y.isRenderTargetTexture===!1&&y.version>0&&N.__version!==y.version){Y(N,y,g);return}t.bindTexture(i.TEXTURE_3D,N.__webglTexture,i.TEXTURE0+g)}function G(y,g){const N=n.get(y);if(y.version>0&&N.__version!==y.version){j(N,y,g);return}t.bindTexture(i.TEXTURE_CUBE_MAP,N.__webglTexture,i.TEXTURE0+g)}const se={[Cn]:i.REPEAT,[Pn]:i.CLAMP_TO_EDGE,[es]:i.MIRRORED_REPEAT},ce={[Gt]:i.NEAREST,[_l]:i.NEAREST_MIPMAP_NEAREST,[Di]:i.NEAREST_MIPMAP_LINEAR,[Ut]:i.LINEAR,[ur]:i.LINEAR_MIPMAP_NEAREST,[Dn]:i.LINEAR_MIPMAP_LINEAR},Ee={[Sl]:i.NEVER,[wl]:i.ALWAYS,[El]:i.LESS,[po]:i.LEQUAL,[yl]:i.EQUAL,[bl]:i.GEQUAL,[Tl]:i.GREATER,[Al]:i.NOTEQUAL};function Fe(y,g){if(g.type===nn&&e.has("OES_texture_float_linear")===!1&&(g.magFilter===Ut||g.magFilter===ur||g.magFilter===Di||g.magFilter===Dn||g.minFilter===Ut||g.minFilter===ur||g.minFilter===Di||g.minFilter===Dn)&&console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),i.texParameteri(y,i.TEXTURE_WRAP_S,se[g.wrapS]),i.texParameteri(y,i.TEXTURE_WRAP_T,se[g.wrapT]),(y===i.TEXTURE_3D||y===i.TEXTURE_2D_ARRAY)&&i.texParameteri(y,i.TEXTURE_WRAP_R,se[g.wrapR]),i.texParameteri(y,i.TEXTURE_MAG_FILTER,ce[g.magFilter]),i.texParameteri(y,i.TEXTURE_MIN_FILTER,ce[g.minFilter]),g.compareFunction&&(i.texParameteri(y,i.TEXTURE_COMPARE_MODE,i.COMPARE_REF_TO_TEXTURE),i.texParameteri(y,i.TEXTURE_COMPARE_FUNC,Ee[g.compareFunction])),e.has("EXT_texture_filter_anisotropic")===!0){if(g.magFilter===Gt||g.minFilter!==Di&&g.minFilter!==Dn||g.type===nn&&e.has("OES_texture_float_linear")===!1)return;if(g.anisotropy>1||n.get(g).__currentAnisotropy){const N=e.get("EXT_texture_filter_anisotropic");i.texParameterf(y,N.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(g.anisotropy,r.getMaxAnisotropy())),n.get(g).__currentAnisotropy=g.anisotropy}}}function Ke(y,g){let N=!1;y.__webglInit===void 0&&(y.__webglInit=!0,g.addEventListener("dispose",R));const V=g.source;let K=f.get(V);K===void 0&&(K={},f.set(V,K));const k=q(g);if(k!==y.__cacheKey){K[k]===void 0&&(K[k]={texture:i.createTexture(),usedTimes:0},a.memory.textures++,N=!0),K[k].usedTimes++;const Me=K[y.__cacheKey];Me!==void 0&&(K[y.__cacheKey].usedTimes--,Me.usedTimes===0&&S(g)),y.__cacheKey=k,y.__webglTexture=K[k].texture}return N}function Je(y,g,N){return Math.floor(Math.floor(y/N)/g)}function We(y,g,N,V){const k=y.updateRanges;if(k.length===0)t.texSubImage2D(i.TEXTURE_2D,0,0,0,g.width,g.height,N,V,g.data);else{k.sort((ee,le)=>ee.start-le.start);let Me=0;for(let ee=1;ee0){P&&te&&t.texStorage2D(i.TEXTURE_2D,he,xe,Le[0].width,Le[0].height);for(let J=0,$=Le.length;J<$;J++)ae=Le[J],P?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,le,be,ae.data):t.texImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,le,be,ae.data);g.generateMipmaps=!1}else P?(te&&t.texStorage2D(i.TEXTURE_2D,he,xe,ee.width,ee.height),ie&&We(g,ee,le,be)):t.texImage2D(i.TEXTURE_2D,0,xe,ee.width,ee.height,0,le,be,ee.data);else if(g.isCompressedTexture)if(g.isCompressedArrayTexture){P&&te&&t.texStorage3D(i.TEXTURE_2D_ARRAY,he,xe,Le[0].width,Le[0].height,ee.depth);for(let J=0,$=Le.length;J<$;J++)if(ae=Le[J],g.format!==zt)if(le!==null)if(P){if(ie)if(g.layerUpdates.size>0){const pe=Ra(ae.width,ae.height,g.format,g.type);for(const Pe of g.layerUpdates){const Ze=ae.data.subarray(Pe*pe/ae.data.BYTES_PER_ELEMENT,(Pe+1)*pe/ae.data.BYTES_PER_ELEMENT);t.compressedTexSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,Pe,ae.width,ae.height,1,le,Ze)}g.clearLayerUpdates()}else t.compressedTexSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,0,ae.width,ae.height,ee.depth,le,ae.data)}else t.compressedTexImage3D(i.TEXTURE_2D_ARRAY,J,xe,ae.width,ae.height,ee.depth,0,ae.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else P?ie&&t.texSubImage3D(i.TEXTURE_2D_ARRAY,J,0,0,0,ae.width,ae.height,ee.depth,le,be,ae.data):t.texImage3D(i.TEXTURE_2D_ARRAY,J,xe,ae.width,ae.height,ee.depth,0,le,be,ae.data)}else{P&&te&&t.texStorage2D(i.TEXTURE_2D,he,xe,Le[0].width,Le[0].height);for(let J=0,$=Le.length;J<$;J++)ae=Le[J],g.format!==zt?le!==null?P?ie&&t.compressedTexSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,le,ae.data):t.compressedTexImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,ae.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):P?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,ae.width,ae.height,le,be,ae.data):t.texImage2D(i.TEXTURE_2D,J,xe,ae.width,ae.height,0,le,be,ae.data)}else if(g.isDataArrayTexture)if(P){if(te&&t.texStorage3D(i.TEXTURE_2D_ARRAY,he,xe,ee.width,ee.height,ee.depth),ie)if(g.layerUpdates.size>0){const J=Ra(ee.width,ee.height,g.format,g.type);for(const $ of g.layerUpdates){const pe=ee.data.subarray($*J/ee.data.BYTES_PER_ELEMENT,($+1)*J/ee.data.BYTES_PER_ELEMENT);t.texSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,$,ee.width,ee.height,1,le,be,pe)}g.clearLayerUpdates()}else t.texSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,0,ee.width,ee.height,ee.depth,le,be,ee.data)}else t.texImage3D(i.TEXTURE_2D_ARRAY,0,xe,ee.width,ee.height,ee.depth,0,le,be,ee.data);else if(g.isData3DTexture)P?(te&&t.texStorage3D(i.TEXTURE_3D,he,xe,ee.width,ee.height,ee.depth),ie&&t.texSubImage3D(i.TEXTURE_3D,0,0,0,0,ee.width,ee.height,ee.depth,le,be,ee.data)):t.texImage3D(i.TEXTURE_3D,0,xe,ee.width,ee.height,ee.depth,0,le,be,ee.data);else if(g.isFramebufferTexture){if(te)if(P)t.texStorage2D(i.TEXTURE_2D,he,xe,ee.width,ee.height);else{let J=ee.width,$=ee.height;for(let pe=0;pe>=1,$>>=1}}else if(Le.length>0){if(P&&te){const J=at(Le[0]);t.texStorage2D(i.TEXTURE_2D,he,xe,J.width,J.height)}for(let J=0,$=Le.length;J<$;J++)ae=Le[J],P?ie&&t.texSubImage2D(i.TEXTURE_2D,J,0,0,le,be,ae):t.texImage2D(i.TEXTURE_2D,J,xe,le,be,ae);g.generateMipmaps=!1}else if(P){if(te){const J=at(ee);t.texStorage2D(i.TEXTURE_2D,he,xe,J.width,J.height)}ie&&t.texSubImage2D(i.TEXTURE_2D,0,0,0,le,be,ee)}else t.texImage2D(i.TEXTURE_2D,0,xe,le,be,ee);p(g)&&u(V),Me.__version=k.version,g.onUpdate&&g.onUpdate(g)}y.__version=g.version}function j(y,g,N){if(g.image.length!==6)return;const V=Ke(y,g),K=g.source;t.bindTexture(i.TEXTURE_CUBE_MAP,y.__webglTexture,i.TEXTURE0+N);const k=n.get(K);if(K.version!==k.__version||V===!0){t.activeTexture(i.TEXTURE0+N);const Me=Ve.getPrimaries(Ve.workingColorSpace),ne=g.colorSpace===dn?null:Ve.getPrimaries(g.colorSpace),_e=g.colorSpace===dn||Me===ne?i.NONE:i.BROWSER_DEFAULT_WEBGL;i.pixelStorei(i.UNPACK_FLIP_Y_WEBGL,g.flipY),i.pixelStorei(i.UNPACK_PREMULTIPLY_ALPHA_WEBGL,g.premultiplyAlpha),i.pixelStorei(i.UNPACK_ALIGNMENT,g.unpackAlignment),i.pixelStorei(i.UNPACK_COLORSPACE_CONVERSION_WEBGL,_e);const ve=g.isCompressedTexture||g.image[0].isCompressedTexture,ee=g.image[0]&&g.image[0].isDataTexture,le=[];for(let $=0;$<6;$++)!ve&&!ee?le[$]=x(g.image[$],!0,r.maxCubemapSize):le[$]=ee?g.image[$].image:g.image[$],le[$]=ut(g,le[$]);const be=le[0],xe=s.convert(g.format,g.colorSpace),ae=s.convert(g.type),Le=A(g.internalFormat,xe,ae,g.colorSpace),P=g.isVideoTexture!==!0,te=k.__version===void 0||V===!0,ie=K.dataReady;let he=D(g,be);Fe(i.TEXTURE_CUBE_MAP,g);let J;if(ve){P&&te&&t.texStorage2D(i.TEXTURE_CUBE_MAP,he,Le,be.width,be.height);for(let $=0;$<6;$++){J=le[$].mipmaps;for(let pe=0;pe0&&he++;const $=at(le[0]);t.texStorage2D(i.TEXTURE_CUBE_MAP,he,Le,$.width,$.height)}for(let $=0;$<6;$++)if(ee){P?ie&&t.texSubImage2D(i.TEXTURE_CUBE_MAP_POSITIVE_X+$,0,0,0,le[$].width,le[$].height,xe,ae,le[$].data):t.texImage2D(i.TEXTURE_CUBE_MAP_POSITIVE_X+$,0,Le,le[$].width,le[$].height,0,xe,ae,le[$].data);for(let pe=0;pe>k),be=Math.max(1,g.height>>k);K===i.TEXTURE_3D||K===i.TEXTURE_2D_ARRAY?t.texImage3D(K,k,_e,le,be,g.depth,0,Me,ne,null):t.texImage2D(K,k,_e,le,be,0,Me,ne,null)}t.bindFramebuffer(i.FRAMEBUFFER,y),ge(g)?o.framebufferTexture2DMultisampleEXT(i.FRAMEBUFFER,V,K,ee.__webglTexture,0,et(g)):(K===i.TEXTURE_2D||K>=i.TEXTURE_CUBE_MAP_POSITIVE_X&&K<=i.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&i.framebufferTexture2D(i.FRAMEBUFFER,V,K,ee.__webglTexture,k),t.bindFramebuffer(i.FRAMEBUFFER,null)}function Ce(y,g,N){if(i.bindRenderbuffer(i.RENDERBUFFER,y),g.depthBuffer){const V=g.depthTexture,K=V&&V.isDepthTexture?V.type:null,k=E(g.stencilBuffer,K),Me=g.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,ne=et(g);ge(g)?o.renderbufferStorageMultisampleEXT(i.RENDERBUFFER,ne,k,g.width,g.height):N?i.renderbufferStorageMultisample(i.RENDERBUFFER,ne,k,g.width,g.height):i.renderbufferStorage(i.RENDERBUFFER,k,g.width,g.height),i.framebufferRenderbuffer(i.FRAMEBUFFER,Me,i.RENDERBUFFER,y)}else{const V=g.textures;for(let K=0;K{delete g.__boundDepthTexture,delete g.__depthDisposeCallback,V.removeEventListener("dispose",K)};V.addEventListener("dispose",K),g.__depthDisposeCallback=K}g.__boundDepthTexture=V}if(y.depthTexture&&!g.__autoAllocateDepthBuffer){if(N)throw new Error("target.depthTexture not supported in Cube render targets");const V=y.texture.mipmaps;V&&V.length>0?Se(g.__webglFramebuffer[0],y):Se(g.__webglFramebuffer,y)}else if(N){g.__webglDepthbuffer=[];for(let V=0;V<6;V++)if(t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer[V]),g.__webglDepthbuffer[V]===void 0)g.__webglDepthbuffer[V]=i.createRenderbuffer(),Ce(g.__webglDepthbuffer[V],y,!1);else{const K=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,k=g.__webglDepthbuffer[V];i.bindRenderbuffer(i.RENDERBUFFER,k),i.framebufferRenderbuffer(i.FRAMEBUFFER,K,i.RENDERBUFFER,k)}}else{const V=y.texture.mipmaps;if(V&&V.length>0?t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer[0]):t.bindFramebuffer(i.FRAMEBUFFER,g.__webglFramebuffer),g.__webglDepthbuffer===void 0)g.__webglDepthbuffer=i.createRenderbuffer(),Ce(g.__webglDepthbuffer,y,!1);else{const K=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,k=g.__webglDepthbuffer;i.bindRenderbuffer(i.RENDERBUFFER,k),i.framebufferRenderbuffer(i.FRAMEBUFFER,K,i.RENDERBUFFER,k)}}t.bindFramebuffer(i.FRAMEBUFFER,null)}function ft(y,g,N){const V=n.get(y);g!==void 0&&de(V.__webglFramebuffer,y,y.texture,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,0),N!==void 0&&ze(y)}function T(y){const g=y.texture,N=n.get(y),V=n.get(g);y.addEventListener("dispose",w);const K=y.textures,k=y.isWebGLCubeRenderTarget===!0,Me=K.length>1;if(Me||(V.__webglTexture===void 0&&(V.__webglTexture=i.createTexture()),V.__version=g.version,a.memory.textures++),k){N.__webglFramebuffer=[];for(let ne=0;ne<6;ne++)if(g.mipmaps&&g.mipmaps.length>0){N.__webglFramebuffer[ne]=[];for(let _e=0;_e0){N.__webglFramebuffer=[];for(let ne=0;ne0&&ge(y)===!1){N.__webglMultisampledFramebuffer=i.createFramebuffer(),N.__webglColorRenderbuffer=[],t.bindFramebuffer(i.FRAMEBUFFER,N.__webglMultisampledFramebuffer);for(let ne=0;ne0)for(let _e=0;_e0)for(let _e=0;_e0){if(ge(y)===!1){const g=y.textures,N=y.width,V=y.height;let K=i.COLOR_BUFFER_BIT;const k=y.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,Me=n.get(y),ne=g.length>1;if(ne)for(let ve=0;ve0?t.bindFramebuffer(i.DRAW_FRAMEBUFFER,Me.__webglFramebuffer[0]):t.bindFramebuffer(i.DRAW_FRAMEBUFFER,Me.__webglFramebuffer);for(let ve=0;ve0&&e.has("WEBGL_multisampled_render_to_texture")===!0&&g.__useRenderToTexture!==!1}function Ue(y){const g=a.render.frame;h.get(y)!==g&&(h.set(y,g),y.update())}function ut(y,g){const N=y.colorSpace,V=y.format,K=y.type;return y.isCompressedTexture===!0||y.isVideoTexture===!0||N!==ii&&N!==dn&&(Ve.getTransfer(N)===Ye?(V!==zt||K!==qt)&&console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",N)),g}function at(y){return typeof HTMLImageElement<"u"&&y instanceof HTMLImageElement?(l.width=y.naturalWidth||y.width,l.height=y.naturalHeight||y.height):typeof VideoFrame<"u"&&y instanceof VideoFrame?(l.width=y.displayWidth,l.height=y.displayHeight):(l.width=y.width,l.height=y.height),l}this.allocateTextureUnit=z,this.resetTextureUnits=O,this.setTexture2D=W,this.setTexture2DArray=X,this.setTexture3D=Z,this.setTextureCube=G,this.rebindTextures=ft,this.setupRenderTarget=T,this.updateRenderTargetMipmap=Qe,this.updateMultisampleRenderTarget=me,this.setupDepthRenderbuffer=ze,this.setupFrameBufferTexture=de,this.useMultisampledRTT=ge}function qf(i,e){function t(n,r=dn){let s;const a=Ve.getTransfer(r);if(n===qt)return i.UNSIGNED_BYTE;if(n===Us)return i.UNSIGNED_SHORT_4_4_4_4;if(n===Ns)return i.UNSIGNED_SHORT_5_5_5_1;if(n===ao)return i.UNSIGNED_INT_5_9_9_9_REV;if(n===oo)return i.UNSIGNED_INT_10F_11F_11F_REV;if(n===ro)return i.BYTE;if(n===so)return i.SHORT;if(n===_i)return i.UNSIGNED_SHORT;if(n===Is)return i.INT;if(n===Ln)return i.UNSIGNED_INT;if(n===nn)return i.FLOAT;if(n===yi)return i.HALF_FLOAT;if(n===lo)return i.ALPHA;if(n===co)return i.RGB;if(n===zt)return i.RGBA;if(n===xi)return i.DEPTH_COMPONENT;if(n===Mi)return i.DEPTH_STENCIL;if(n===uo)return i.RED;if(n===Fs)return i.RED_INTEGER;if(n===ho)return i.RG;if(n===Os)return i.RG_INTEGER;if(n===Bs)return i.RGBA_INTEGER;if(n===Ji||n===Qi||n===er||n===tr)if(a===Ye)if(s=e.get("WEBGL_compressed_texture_s3tc_srgb"),s!==null){if(n===Ji)return s.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(n===Qi)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(n===er)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(n===tr)return s.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(s=e.get("WEBGL_compressed_texture_s3tc"),s!==null){if(n===Ji)return s.COMPRESSED_RGB_S3TC_DXT1_EXT;if(n===Qi)return s.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(n===er)return s.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(n===tr)return s.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(n===ts||n===ns||n===is||n===rs)if(s=e.get("WEBGL_compressed_texture_pvrtc"),s!==null){if(n===ts)return s.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(n===ns)return s.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(n===is)return s.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(n===rs)return s.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(n===ss||n===as||n===os)if(s=e.get("WEBGL_compressed_texture_etc"),s!==null){if(n===ss||n===as)return a===Ye?s.COMPRESSED_SRGB8_ETC2:s.COMPRESSED_RGB8_ETC2;if(n===os)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:s.COMPRESSED_RGBA8_ETC2_EAC}else return null;if(n===ls||n===cs||n===us||n===hs||n===ds||n===fs||n===ps||n===ms||n===gs||n===_s||n===vs||n===xs||n===Ms||n===Ss)if(s=e.get("WEBGL_compressed_texture_astc"),s!==null){if(n===ls)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:s.COMPRESSED_RGBA_ASTC_4x4_KHR;if(n===cs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:s.COMPRESSED_RGBA_ASTC_5x4_KHR;if(n===us)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:s.COMPRESSED_RGBA_ASTC_5x5_KHR;if(n===hs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:s.COMPRESSED_RGBA_ASTC_6x5_KHR;if(n===ds)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:s.COMPRESSED_RGBA_ASTC_6x6_KHR;if(n===fs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:s.COMPRESSED_RGBA_ASTC_8x5_KHR;if(n===ps)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:s.COMPRESSED_RGBA_ASTC_8x6_KHR;if(n===ms)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:s.COMPRESSED_RGBA_ASTC_8x8_KHR;if(n===gs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:s.COMPRESSED_RGBA_ASTC_10x5_KHR;if(n===_s)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:s.COMPRESSED_RGBA_ASTC_10x6_KHR;if(n===vs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:s.COMPRESSED_RGBA_ASTC_10x8_KHR;if(n===xs)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:s.COMPRESSED_RGBA_ASTC_10x10_KHR;if(n===Ms)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:s.COMPRESSED_RGBA_ASTC_12x10_KHR;if(n===Ss)return a===Ye?s.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:s.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(n===Es||n===ys||n===Ts)if(s=e.get("EXT_texture_compression_bptc"),s!==null){if(n===Es)return a===Ye?s.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:s.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(n===ys)return s.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(n===Ts)return s.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(n===As||n===bs||n===ws||n===Rs)if(s=e.get("EXT_texture_compression_rgtc"),s!==null){if(n===As)return s.COMPRESSED_RED_RGTC1_EXT;if(n===bs)return s.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(n===ws)return s.COMPRESSED_RED_GREEN_RGTC2_EXT;if(n===Rs)return s.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return n===vi?i.UNSIGNED_INT_24_8:i[n]!==void 0?i[n]:null}return{convert:t}}const Yf=` void main() { gl_Position = vec4( position, 1.0 ); -}`,ip=` +}`,$f=` uniform sampler2DArray depthColor; uniform float depthWidth; uniform float depthHeight; @@ -3837,8 +3837,9 @@ void main() { } -}`;class rp{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t){if(this.texture===null){const n=new Oo(e.texture);(e.depthNear!==t.depthNear||e.depthFar!==t.depthFar)&&(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=n}}getMesh(e){if(this.texture!==null&&this.mesh===null){const t=e.cameras[0].viewport,n=new mn({vertexShader:np,fragmentShader:ip,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new Et(new Ti(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class sp extends ti{constructor(e,t){super();const n=this;let r=null,s=1,a=null,o="local-floor",l=1,c=null,d=null,h=null,f=null,m=null,_=null;const x=typeof XRWebGLBinding<"u",p=new rp,u={},b=t.getContextAttributes();let A=null,E=null;const C=[],R=[],w=new Ge;let U=null;const S=new It;S.viewport=new st;const M=new It;M.viewport=new st;const P=[S,M],O=new Tl;let H=null,q=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(Y){let j=C[Y];return j===void 0&&(j=new zr,C[Y]=j),j.getTargetRaySpace()},this.getControllerGrip=function(Y){let j=C[Y];return j===void 0&&(j=new zr,C[Y]=j),j.getGripSpace()},this.getHand=function(Y){let j=C[Y];return j===void 0&&(j=new zr,C[Y]=j),j.getHandSpace()};function W(Y){const j=R.indexOf(Y.inputSource);if(j===-1)return;const de=C[j];de!==void 0&&(de.update(Y.inputSource,Y.frame,c||a),de.dispatchEvent({type:Y.type,data:Y.inputSource}))}function X(){r.removeEventListener("select",W),r.removeEventListener("selectstart",W),r.removeEventListener("selectend",W),r.removeEventListener("squeeze",W),r.removeEventListener("squeezestart",W),r.removeEventListener("squeezeend",W),r.removeEventListener("end",X),r.removeEventListener("inputsourceschange",Z);for(let Y=0;Y=0&&(R[Ce]=null,C[Ce].disconnect(de))}for(let j=0;j=R.length){R.push(de),Ce=He;break}else if(R[He]===null){R[He]=de,Ce=He;break}if(Ce===-1)break}const Se=C[Ce];Se&&Se.connect(de)}}const G=new N,se=new N;function le(Y,j,de){G.setFromMatrixPosition(j.matrixWorld),se.setFromMatrixPosition(de.matrixWorld);const Ce=G.distanceTo(se),Se=j.projectionMatrix.elements,He=de.projectionMatrix.elements,mt=Se[14]/(Se[10]-1),T=Se[14]/(Se[10]+1),Qe=(Se[9]+1)/Se[5],De=(Se[9]-1)/Se[5],we=(Se[8]-1)/Se[0],me=(He[8]+1)/He[0],et=mt*we,ge=mt*me,Ue=Ce/(-we+me),ht=Ue*-we;if(j.matrixWorld.decompose(Y.position,Y.quaternion,Y.scale),Y.translateX(ht),Y.translateZ(Ue),Y.matrixWorld.compose(Y.position,Y.quaternion,Y.scale),Y.matrixWorldInverse.copy(Y.matrixWorld).invert(),Se[10]===-1)Y.projectionMatrix.copy(j.projectionMatrix),Y.projectionMatrixInverse.copy(j.projectionMatrixInverse);else{const at=mt+Ue,y=T+Ue,g=et-ht,F=ge+(Ce-ht),k=Qe*T/y*at,K=De*T/y*at;Y.projectionMatrix.makePerspective(g,F,k,K,at,y),Y.projectionMatrixInverse.copy(Y.projectionMatrix).invert()}}function Ee(Y,j){j===null?Y.matrixWorld.copy(Y.matrix):Y.matrixWorld.multiplyMatrices(j.matrixWorld,Y.matrix),Y.matrixWorldInverse.copy(Y.matrixWorld).invert()}this.updateCamera=function(Y){if(r===null)return;let j=Y.near,de=Y.far;p.texture!==null&&(p.depthNear>0&&(j=p.depthNear),p.depthFar>0&&(de=p.depthFar)),O.near=M.near=S.near=j,O.far=M.far=S.far=de,(H!==O.near||q!==O.far)&&(r.updateRenderState({depthNear:O.near,depthFar:O.far}),H=O.near,q=O.far),O.layers.mask=Y.layers.mask|6,S.layers.mask=O.layers.mask&3,M.layers.mask=O.layers.mask&5;const Ce=Y.parent,Se=O.cameras;Ee(O,Ce);for(let He=0;He0&&(p.alphaTest.value=u.alphaTest);const b=e.get(u),A=b.envMap,E=b.envMapRotation;A&&(p.envMap.value=A,yn.copy(E),yn.x*=-1,yn.y*=-1,yn.z*=-1,A.isCubeTexture&&A.isRenderTargetTexture===!1&&(yn.y*=-1,yn.z*=-1),p.envMapRotation.value.setFromMatrix4(ap.makeRotationFromEuler(yn)),p.flipEnvMap.value=A.isCubeTexture&&A.isRenderTargetTexture===!1?-1:1,p.reflectivity.value=u.reflectivity,p.ior.value=u.ior,p.refractionRatio.value=u.refractionRatio),u.lightMap&&(p.lightMap.value=u.lightMap,p.lightMapIntensity.value=u.lightMapIntensity,t(u.lightMap,p.lightMapTransform)),u.aoMap&&(p.aoMap.value=u.aoMap,p.aoMapIntensity.value=u.aoMapIntensity,t(u.aoMap,p.aoMapTransform))}function a(p,u){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,u.map&&(p.map.value=u.map,t(u.map,p.mapTransform))}function o(p,u){p.dashSize.value=u.dashSize,p.totalSize.value=u.dashSize+u.gapSize,p.scale.value=u.scale}function l(p,u,b,A){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,p.size.value=u.size*b,p.scale.value=A*.5,u.map&&(p.map.value=u.map,t(u.map,p.uvTransform)),u.alphaMap&&(p.alphaMap.value=u.alphaMap,t(u.alphaMap,p.alphaMapTransform)),u.alphaTest>0&&(p.alphaTest.value=u.alphaTest)}function c(p,u){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,p.rotation.value=u.rotation,u.map&&(p.map.value=u.map,t(u.map,p.mapTransform)),u.alphaMap&&(p.alphaMap.value=u.alphaMap,t(u.alphaMap,p.alphaMapTransform)),u.alphaTest>0&&(p.alphaTest.value=u.alphaTest)}function d(p,u){p.specular.value.copy(u.specular),p.shininess.value=Math.max(u.shininess,1e-4)}function h(p,u){u.gradientMap&&(p.gradientMap.value=u.gradientMap)}function f(p,u){p.metalness.value=u.metalness,u.metalnessMap&&(p.metalnessMap.value=u.metalnessMap,t(u.metalnessMap,p.metalnessMapTransform)),p.roughness.value=u.roughness,u.roughnessMap&&(p.roughnessMap.value=u.roughnessMap,t(u.roughnessMap,p.roughnessMapTransform)),u.envMap&&(p.envMapIntensity.value=u.envMapIntensity)}function m(p,u,b){p.ior.value=u.ior,u.sheen>0&&(p.sheenColor.value.copy(u.sheenColor).multiplyScalar(u.sheen),p.sheenRoughness.value=u.sheenRoughness,u.sheenColorMap&&(p.sheenColorMap.value=u.sheenColorMap,t(u.sheenColorMap,p.sheenColorMapTransform)),u.sheenRoughnessMap&&(p.sheenRoughnessMap.value=u.sheenRoughnessMap,t(u.sheenRoughnessMap,p.sheenRoughnessMapTransform))),u.clearcoat>0&&(p.clearcoat.value=u.clearcoat,p.clearcoatRoughness.value=u.clearcoatRoughness,u.clearcoatMap&&(p.clearcoatMap.value=u.clearcoatMap,t(u.clearcoatMap,p.clearcoatMapTransform)),u.clearcoatRoughnessMap&&(p.clearcoatRoughnessMap.value=u.clearcoatRoughnessMap,t(u.clearcoatRoughnessMap,p.clearcoatRoughnessMapTransform)),u.clearcoatNormalMap&&(p.clearcoatNormalMap.value=u.clearcoatNormalMap,t(u.clearcoatNormalMap,p.clearcoatNormalMapTransform),p.clearcoatNormalScale.value.copy(u.clearcoatNormalScale),u.side===yt&&p.clearcoatNormalScale.value.negate())),u.dispersion>0&&(p.dispersion.value=u.dispersion),u.iridescence>0&&(p.iridescence.value=u.iridescence,p.iridescenceIOR.value=u.iridescenceIOR,p.iridescenceThicknessMinimum.value=u.iridescenceThicknessRange[0],p.iridescenceThicknessMaximum.value=u.iridescenceThicknessRange[1],u.iridescenceMap&&(p.iridescenceMap.value=u.iridescenceMap,t(u.iridescenceMap,p.iridescenceMapTransform)),u.iridescenceThicknessMap&&(p.iridescenceThicknessMap.value=u.iridescenceThicknessMap,t(u.iridescenceThicknessMap,p.iridescenceThicknessMapTransform))),u.transmission>0&&(p.transmission.value=u.transmission,p.transmissionSamplerMap.value=b.texture,p.transmissionSamplerSize.value.set(b.width,b.height),u.transmissionMap&&(p.transmissionMap.value=u.transmissionMap,t(u.transmissionMap,p.transmissionMapTransform)),p.thickness.value=u.thickness,u.thicknessMap&&(p.thicknessMap.value=u.thicknessMap,t(u.thicknessMap,p.thicknessMapTransform)),p.attenuationDistance.value=u.attenuationDistance,p.attenuationColor.value.copy(u.attenuationColor)),u.anisotropy>0&&(p.anisotropyVector.value.set(u.anisotropy*Math.cos(u.anisotropyRotation),u.anisotropy*Math.sin(u.anisotropyRotation)),u.anisotropyMap&&(p.anisotropyMap.value=u.anisotropyMap,t(u.anisotropyMap,p.anisotropyMapTransform))),p.specularIntensity.value=u.specularIntensity,p.specularColor.value.copy(u.specularColor),u.specularColorMap&&(p.specularColorMap.value=u.specularColorMap,t(u.specularColorMap,p.specularColorMapTransform)),u.specularIntensityMap&&(p.specularIntensityMap.value=u.specularIntensityMap,t(u.specularIntensityMap,p.specularIntensityMapTransform))}function _(p,u){u.matcap&&(p.matcap.value=u.matcap)}function x(p,u){const b=e.get(u).light;p.referencePosition.value.setFromMatrixPosition(b.matrixWorld),p.nearDistance.value=b.shadow.camera.near,p.farDistance.value=b.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:r}}function cp(i,e,t,n){let r={},s={},a=[];const o=i.getParameter(i.MAX_UNIFORM_BUFFER_BINDINGS);function l(b,A){const E=A.program;n.uniformBlockBinding(b,E)}function c(b,A){let E=r[b.id];E===void 0&&(_(b),E=d(b),r[b.id]=E,b.addEventListener("dispose",p));const C=A.program;n.updateUBOMapping(b,C);const R=e.render.frame;s[b.id]!==R&&(f(b),s[b.id]=R)}function d(b){const A=h();b.__bindingPointIndex=A;const E=i.createBuffer(),C=b.__size,R=b.usage;return i.bindBuffer(i.UNIFORM_BUFFER,E),i.bufferData(i.UNIFORM_BUFFER,C,R),i.bindBuffer(i.UNIFORM_BUFFER,null),i.bindBufferBase(i.UNIFORM_BUFFER,A,E),E}function h(){for(let b=0;b0&&(E+=C-R),b.__size=E,b.__cache={},this}function x(b){const A={boundary:0,storage:0};return typeof b=="number"||typeof b=="boolean"?(A.boundary=4,A.storage=4):b.isVector2?(A.boundary=8,A.storage=8):b.isVector3||b.isColor?(A.boundary=16,A.storage=12):b.isVector4?(A.boundary=16,A.storage=16):b.isMatrix3?(A.boundary=48,A.storage=48):b.isMatrix4?(A.boundary=64,A.storage=64):b.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",b),A}function p(b){const A=b.target;A.removeEventListener("dispose",p);const E=a.indexOf(A.__bindingPointIndex);a.splice(E,1),i.deleteBuffer(r[A.id]),delete r[A.id],delete s[A.id]}function u(){for(const b in r)i.deleteBuffer(r[b]);a=[],r={},s={}}return{bind:l,update:c,dispose:u}}class lp{constructor(e={}){const{canvas:t=Bc(),context:n=null,depth:r=!0,stencil:s=!1,alpha:a=!1,antialias:o=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:d="default",failIfMajorPerformanceCaveat:h=!1,reversedDepthBuffer:f=!1}=e;this.isWebGLRenderer=!0;let m;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");m=n.getContextAttributes().alpha}else m=a;const _=new Uint32Array(4),x=new Int32Array(4);let p=null,u=null;const b=[],A=[];this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.toneMapping=fn,this.toneMappingExposure=1,this.transmissionResolutionScale=1;const E=this;let C=!1;this._outputColorSpace=Lt;let R=0,w=0,U=null,S=-1,M=null;const P=new st,O=new st;let H=null;const q=new Fe(0);let W=0,X=t.width,Z=t.height,G=1,se=null,le=null;const Ee=new st(0,0,X,Z),Oe=new st(0,0,X,Z);let Ke=!1;const Je=new js;let We=!1,Y=!1;const j=new it,de=new N,Ce=new st,Se={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let He=!1;function mt(){return U===null?G:1}let T=n;function Qe(v,L){return t.getContext(v,L)}try{const v={alpha:!0,depth:r,stencil:s,antialias:o,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:d,failIfMajorPerformanceCaveat:h};if("setAttribute"in t&&t.setAttribute("data-engine",`three.js r${Gs}`),t.addEventListener("webglcontextlost",ie,!1),t.addEventListener("webglcontextrestored",he,!1),t.addEventListener("webglcontextcreationerror",J,!1),T===null){const L="webgl2";if(T=Qe(L,v),T===null)throw Qe(L)?new Error("Error creating WebGL context with your selected attributes."):new Error("Error creating WebGL context.")}}catch(v){throw console.error("THREE.WebGLRenderer: "+v.message),v}let De,we,me,et,ge,Ue,ht,at,y,g,F,k,K,V,Me,ne,_e,ve,ee,ce,be,xe,ae,Le;function D(){De=new vd(T),De.init(),xe=new tp(T,De),we=new hd(T,De,e,xe),me=new Qf(T,De),we.reversedDepthBuffer&&f&&me.buffers.depth.setReversed(!0),et=new Sd(T),ge=new Hf,Ue=new ep(T,De,me,ge,we,xe,et),ht=new fd(E),at=new _d(E),y=new wl(T),ae=new ld(T,y),g=new xd(T,y,et,ae),F=new yd(T,g,y,et),ee=new Ed(T,we,Ue),ne=new dd(ge),k=new zf(E,ht,at,De,we,ae,ne),K=new op(E,ge),V=new Vf,Me=new $f(De),ve=new cd(E,ht,at,me,F,m,l),_e=new jf(E,F,we),Le=new cp(T,et,we,me),ce=new ud(T,De,et),be=new Md(T,De,et),et.programs=k.programs,E.capabilities=we,E.extensions=De,E.properties=ge,E.renderLists=V,E.shadowMap=_e,E.state=me,E.info=et}D();const te=new sp(E,T);this.xr=te,this.getContext=function(){return T},this.getContextAttributes=function(){return T.getContextAttributes()},this.forceContextLoss=function(){const v=De.get("WEBGL_lose_context");v&&v.loseContext()},this.forceContextRestore=function(){const v=De.get("WEBGL_lose_context");v&&v.restoreContext()},this.getPixelRatio=function(){return G},this.setPixelRatio=function(v){v!==void 0&&(G=v,this.setSize(X,Z,!1))},this.getSize=function(v){return v.set(X,Z)},this.setSize=function(v,L,B=!0){if(te.isPresenting){console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting.");return}X=v,Z=L,t.width=Math.floor(v*G),t.height=Math.floor(L*G),B===!0&&(t.style.width=v+"px",t.style.height=L+"px"),this.setViewport(0,0,v,L)},this.getDrawingBufferSize=function(v){return v.set(X*G,Z*G).floor()},this.setDrawingBufferSize=function(v,L,B){X=v,Z=L,G=B,t.width=Math.floor(v*B),t.height=Math.floor(L*B),this.setViewport(0,0,v,L)},this.getCurrentViewport=function(v){return v.copy(P)},this.getViewport=function(v){return v.copy(Ee)},this.setViewport=function(v,L,B,z){v.isVector4?Ee.set(v.x,v.y,v.z,v.w):Ee.set(v,L,B,z),me.viewport(P.copy(Ee).multiplyScalar(G).round())},this.getScissor=function(v){return v.copy(Oe)},this.setScissor=function(v,L,B,z){v.isVector4?Oe.set(v.x,v.y,v.z,v.w):Oe.set(v,L,B,z),me.scissor(O.copy(Oe).multiplyScalar(G).round())},this.getScissorTest=function(){return Ke},this.setScissorTest=function(v){me.setScissorTest(Ke=v)},this.setOpaqueSort=function(v){se=v},this.setTransparentSort=function(v){le=v},this.getClearColor=function(v){return v.copy(ve.getClearColor())},this.setClearColor=function(){ve.setClearColor(...arguments)},this.getClearAlpha=function(){return ve.getClearAlpha()},this.setClearAlpha=function(){ve.setClearAlpha(...arguments)},this.clear=function(v=!0,L=!0,B=!0){let z=0;if(v){let I=!1;if(U!==null){const Q=U.texture.format;I=Q===Ys||Q===qs||Q===Xs}if(I){const Q=U.texture.type,oe=Q===Yt||Q===Pn||Q===pi||Q===mi||Q===ks||Q===Ws,fe=ve.getClearColor(),ue=ve.getClearAlpha(),Ae=fe.r,Re=fe.g,ye=fe.b;oe?(_[0]=Ae,_[1]=Re,_[2]=ye,_[3]=ue,T.clearBufferuiv(T.COLOR,0,_)):(x[0]=Ae,x[1]=Re,x[2]=ye,x[3]=ue,T.clearBufferiv(T.COLOR,0,x))}else z|=T.COLOR_BUFFER_BIT}L&&(z|=T.DEPTH_BUFFER_BIT),B&&(z|=T.STENCIL_BUFFER_BIT,this.state.buffers.stencil.setMask(4294967295)),T.clear(z)},this.clearColor=function(){this.clear(!0,!1,!1)},this.clearDepth=function(){this.clear(!1,!0,!1)},this.clearStencil=function(){this.clear(!1,!1,!0)},this.dispose=function(){t.removeEventListener("webglcontextlost",ie,!1),t.removeEventListener("webglcontextrestored",he,!1),t.removeEventListener("webglcontextcreationerror",J,!1),ve.dispose(),V.dispose(),Me.dispose(),ge.dispose(),ht.dispose(),at.dispose(),F.dispose(),ae.dispose(),Le.dispose(),k.dispose(),te.dispose(),te.removeEventListener("sessionstart",Gt),te.removeEventListener("sessionend",na),gn.stop()};function ie(v){v.preventDefault(),console.log("THREE.WebGLRenderer: Context Lost."),C=!0}function he(){console.log("THREE.WebGLRenderer: Context Restored."),C=!1;const v=et.autoReset,L=_e.enabled,B=_e.autoUpdate,z=_e.needsUpdate,I=_e.type;D(),et.autoReset=v,_e.enabled=L,_e.autoUpdate=B,_e.needsUpdate=z,_e.type=I}function J(v){console.error("THREE.WebGLRenderer: A WebGL context could not be created. Reason: ",v.statusMessage)}function $(v){const L=v.target;L.removeEventListener("dispose",$),pe(L)}function pe(v){Pe(v),ge.remove(v)}function Pe(v){const L=ge.get(v).programs;L!==void 0&&(L.forEach(function(B){k.releaseProgram(B)}),v.isShaderMaterial&&k.releaseShaderCache(v))}this.renderBufferDirect=function(v,L,B,z,I,Q){L===null&&(L=Se);const oe=I.isMesh&&I.matrixWorld.determinant()<0,fe=Wo(v,L,B,z,I);me.setMaterial(z,oe);let ue=B.index,Ae=1;if(z.wireframe===!0){if(ue=g.getWireframeAttribute(B),ue===void 0)return;Ae=2}const Re=B.drawRange,ye=B.attributes.position;let Be=Re.start*Ae,qe=(Re.start+Re.count)*Ae;Q!==null&&(Be=Math.max(Be,Q.start*Ae),qe=Math.min(qe,(Q.start+Q.count)*Ae)),ue!==null?(Be=Math.max(Be,0),qe=Math.min(qe,ue.count)):ye!=null&&(Be=Math.max(Be,0),qe=Math.min(qe,ye.count));const rt=qe-Be;if(rt<0||rt===1/0)return;ae.setup(I,z,fe,B,ue);let je,$e=ce;if(ue!==null&&(je=y.get(ue),$e=be,$e.setIndex(je)),I.isMesh)z.wireframe===!0?(me.setLineWidth(z.wireframeLinewidth*mt()),$e.setMode(T.LINES)):$e.setMode(T.TRIANGLES);else if(I.isLine){let Te=z.linewidth;Te===void 0&&(Te=1),me.setLineWidth(Te*mt()),I.isLineSegments?$e.setMode(T.LINES):I.isLineLoop?$e.setMode(T.LINE_LOOP):$e.setMode(T.LINE_STRIP)}else I.isPoints?$e.setMode(T.POINTS):I.isSprite&&$e.setMode(T.TRIANGLES);if(I.isBatchedMesh)if(I._multiDrawInstances!==null)vi("THREE.WebGLRenderer: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection."),$e.renderMultiDrawInstances(I._multiDrawStarts,I._multiDrawCounts,I._multiDrawCount,I._multiDrawInstances);else if(De.get("WEBGL_multi_draw"))$e.renderMultiDraw(I._multiDrawStarts,I._multiDrawCounts,I._multiDrawCount);else{const Te=I._multiDrawStarts,tt=I._multiDrawCounts,Ve=I._multiDrawCount,At=ue?y.get(ue).bytesPerElement:1,Ln=ge.get(z).currentProgram.getUniforms();for(let bt=0;bt{function Q(){if(z.forEach(function(oe){ge.get(oe).currentProgram.isReady()&&z.delete(oe)}),z.size===0){I(v);return}setTimeout(Q,10)}De.get("KHR_parallel_shader_compile")!==null?Q():setTimeout(Q,10)})};let Xe=null;function Kt(v){Xe&&Xe(v)}function Gt(){gn.stop()}function na(){gn.start()}const gn=new zo;gn.setAnimationLoop(Kt),typeof self<"u"&&gn.setContext(self),this.setAnimationLoop=function(v){Xe=v,te.setAnimationLoop(v),v===null?gn.stop():gn.start()},te.addEventListener("sessionstart",Gt),te.addEventListener("sessionend",na),this.render=function(v,L){if(L!==void 0&&L.isCamera!==!0){console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(C===!0)return;if(v.matrixWorldAutoUpdate===!0&&v.updateMatrixWorld(),L.parent===null&&L.matrixWorldAutoUpdate===!0&&L.updateMatrixWorld(),te.enabled===!0&&te.isPresenting===!0&&(te.cameraAutoUpdate===!0&&te.updateCamera(L),L=te.getCamera()),v.isScene===!0&&v.onBeforeRender(E,v,L,U),u=Me.get(v,A.length),u.init(L),A.push(u),j.multiplyMatrices(L.projectionMatrix,L.matrixWorldInverse),Je.setFromProjectionMatrix(j,Xt,L.reversedDepth),Y=this.localClippingEnabled,We=ne.init(this.clippingPlanes,Y),p=V.get(v,b.length),p.init(),b.push(p),te.enabled===!0&&te.isPresenting===!0){const Q=E.xr.getDepthSensingMesh();Q!==null&&mr(Q,L,-1/0,E.sortObjects)}mr(v,L,0,E.sortObjects),p.finish(),E.sortObjects===!0&&p.sort(se,le),He=te.enabled===!1||te.isPresenting===!1||te.hasDepthSensing()===!1,He&&ve.addToRenderList(p,v),this.info.render.frame++,We===!0&&ne.beginShadows();const B=u.state.shadowsArray;_e.render(B,v,L),We===!0&&ne.endShadows(),this.info.autoReset===!0&&this.info.reset();const z=p.opaque,I=p.transmissive;if(u.setupLights(),L.isArrayCamera){const Q=L.cameras;if(I.length>0)for(let oe=0,fe=Q.length;oe0&&ra(z,I,v,L),He&&ve.render(v),ia(p,v,L);U!==null&&w===0&&(Ue.updateMultisampleRenderTarget(U),Ue.updateRenderTargetMipmap(U)),v.isScene===!0&&v.onAfterRender(E,v,L),ae.resetDefaultState(),S=-1,M=null,A.pop(),A.length>0?(u=A[A.length-1],We===!0&&ne.setGlobalState(E.clippingPlanes,u.state.camera)):u=null,b.pop(),b.length>0?p=b[b.length-1]:p=null};function mr(v,L,B,z){if(v.visible===!1)return;if(v.layers.test(L.layers)){if(v.isGroup)B=v.renderOrder;else if(v.isLOD)v.autoUpdate===!0&&v.update(L);else if(v.isLight)u.pushLight(v),v.castShadow&&u.pushShadow(v);else if(v.isSprite){if(!v.frustumCulled||Je.intersectsSprite(v)){z&&Ce.setFromMatrixPosition(v.matrixWorld).applyMatrix4(j);const oe=F.update(v),fe=v.material;fe.visible&&p.push(v,oe,fe,B,Ce.z,null)}}else if((v.isMesh||v.isLine||v.isPoints)&&(!v.frustumCulled||Je.intersectsObject(v))){const oe=F.update(v),fe=v.material;if(z&&(v.boundingSphere!==void 0?(v.boundingSphere===null&&v.computeBoundingSphere(),Ce.copy(v.boundingSphere.center)):(oe.boundingSphere===null&&oe.computeBoundingSphere(),Ce.copy(oe.boundingSphere.center)),Ce.applyMatrix4(v.matrixWorld).applyMatrix4(j)),Array.isArray(fe)){const ue=oe.groups;for(let Ae=0,Re=ue.length;Ae0&&Ai(I,L,B),Q.length>0&&Ai(Q,L,B),oe.length>0&&Ai(oe,L,B),me.buffers.depth.setTest(!0),me.buffers.depth.setMask(!0),me.buffers.color.setMask(!0),me.setPolygonOffset(!1)}function ra(v,L,B,z){if((B.isScene===!0?B.overrideMaterial:null)!==null)return;u.state.transmissionRenderTarget[z.id]===void 0&&(u.state.transmissionRenderTarget[z.id]=new Dn(1,1,{generateMipmaps:!0,type:De.has("EXT_color_buffer_half_float")||De.has("EXT_color_buffer_float")?xi:Yt,minFilter:Cn,samples:4,stencilBuffer:s,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:ke.workingColorSpace}));const Q=u.state.transmissionRenderTarget[z.id],oe=z.viewport||P;Q.setSize(oe.z*E.transmissionResolutionScale,oe.w*E.transmissionResolutionScale);const fe=E.getRenderTarget(),ue=E.getActiveCubeFace(),Ae=E.getActiveMipmapLevel();E.setRenderTarget(Q),E.getClearColor(q),W=E.getClearAlpha(),W<1&&E.setClearColor(16777215,.5),E.clear(),He&&ve.render(B);const Re=E.toneMapping;E.toneMapping=fn;const ye=z.viewport;if(z.viewport!==void 0&&(z.viewport=void 0),u.setupLightsView(z),We===!0&&ne.setGlobalState(E.clippingPlanes,z),Ai(v,B,z),Ue.updateMultisampleRenderTarget(Q),Ue.updateRenderTargetMipmap(Q),De.has("WEBGL_multisampled_render_to_texture")===!1){let Be=!1;for(let qe=0,rt=L.length;qe0),ye=!!B.morphAttributes.position,Be=!!B.morphAttributes.normal,qe=!!B.morphAttributes.color;let rt=fn;z.toneMapped&&(U===null||U.isXRRenderTarget===!0)&&(rt=E.toneMapping);const je=B.morphAttributes.position||B.morphAttributes.normal||B.morphAttributes.color,$e=je!==void 0?je.length:0,Te=ge.get(z),tt=u.state.lights;if(We===!0&&(Y===!0||v!==M)){const vt=v===M&&z.id===S;ne.setState(z,v,vt)}let Ve=!1;z.version===Te.__version?(Te.needsLights&&Te.lightsStateVersion!==tt.state.version||Te.outputColorSpace!==fe||I.isBatchedMesh&&Te.batching===!1||!I.isBatchedMesh&&Te.batching===!0||I.isBatchedMesh&&Te.batchingColor===!0&&I.colorTexture===null||I.isBatchedMesh&&Te.batchingColor===!1&&I.colorTexture!==null||I.isInstancedMesh&&Te.instancing===!1||!I.isInstancedMesh&&Te.instancing===!0||I.isSkinnedMesh&&Te.skinning===!1||!I.isSkinnedMesh&&Te.skinning===!0||I.isInstancedMesh&&Te.instancingColor===!0&&I.instanceColor===null||I.isInstancedMesh&&Te.instancingColor===!1&&I.instanceColor!==null||I.isInstancedMesh&&Te.instancingMorph===!0&&I.morphTexture===null||I.isInstancedMesh&&Te.instancingMorph===!1&&I.morphTexture!==null||Te.envMap!==ue||z.fog===!0&&Te.fog!==Q||Te.numClippingPlanes!==void 0&&(Te.numClippingPlanes!==ne.numPlanes||Te.numIntersection!==ne.numIntersection)||Te.vertexAlphas!==Ae||Te.vertexTangents!==Re||Te.morphTargets!==ye||Te.morphNormals!==Be||Te.morphColors!==qe||Te.toneMapping!==rt||Te.morphTargetsCount!==$e)&&(Ve=!0):(Ve=!0,Te.__version=z.version);let At=Te.currentProgram;Ve===!0&&(At=bi(z,L,I));let Ln=!1,bt=!1,ri=!1;const nt=At.getUniforms(),Ct=Te.uniforms;if(me.useProgram(At.program)&&(Ln=!0,bt=!0,ri=!0),z.id!==S&&(S=z.id,bt=!0),Ln||M!==v){me.buffers.depth.getReversed()&&v.reversedDepth!==!0&&(v._reversedDepth=!0,v.updateProjectionMatrix()),nt.setValue(T,"projectionMatrix",v.projectionMatrix),nt.setValue(T,"viewMatrix",v.matrixWorldInverse);const Mt=nt.map.cameraPosition;Mt!==void 0&&Mt.setValue(T,de.setFromMatrixPosition(v.matrixWorld)),we.logarithmicDepthBuffer&&nt.setValue(T,"logDepthBufFC",2/(Math.log(v.far+1)/Math.LN2)),(z.isMeshPhongMaterial||z.isMeshToonMaterial||z.isMeshLambertMaterial||z.isMeshBasicMaterial||z.isMeshStandardMaterial||z.isShaderMaterial)&&nt.setValue(T,"isOrthographic",v.isOrthographicCamera===!0),M!==v&&(M=v,bt=!0,ri=!0)}if(I.isSkinnedMesh){nt.setOptional(T,I,"bindMatrix"),nt.setOptional(T,I,"bindMatrixInverse");const vt=I.skeleton;vt&&(vt.boneTexture===null&&vt.computeBoneTexture(),nt.setValue(T,"boneTexture",vt.boneTexture,Ue))}I.isBatchedMesh&&(nt.setOptional(T,I,"batchingTexture"),nt.setValue(T,"batchingTexture",I._matricesTexture,Ue),nt.setOptional(T,I,"batchingIdTexture"),nt.setValue(T,"batchingIdTexture",I._indirectTexture,Ue),nt.setOptional(T,I,"batchingColorTexture"),I._colorsTexture!==null&&nt.setValue(T,"batchingColorTexture",I._colorsTexture,Ue));const Pt=B.morphAttributes;if((Pt.position!==void 0||Pt.normal!==void 0||Pt.color!==void 0)&&ee.update(I,B,At),(bt||Te.receiveShadow!==I.receiveShadow)&&(Te.receiveShadow=I.receiveShadow,nt.setValue(T,"receiveShadow",I.receiveShadow)),z.isMeshGouraudMaterial&&z.envMap!==null&&(Ct.envMap.value=ue,Ct.flipEnvMap.value=ue.isCubeTexture&&ue.isRenderTargetTexture===!1?-1:1),z.isMeshStandardMaterial&&z.envMap===null&&L.environment!==null&&(Ct.envMapIntensity.value=L.environmentIntensity),bt&&(nt.setValue(T,"toneMappingExposure",E.toneMappingExposure),Te.needsLights&&Xo(Ct,ri),Q&&z.fog===!0&&K.refreshFogUniforms(Ct,Q),K.refreshMaterialUniforms(Ct,z,G,Z,u.state.transmissionRenderTarget[v.id]),rr.upload(T,aa(Te),Ct,Ue)),z.isShaderMaterial&&z.uniformsNeedUpdate===!0&&(rr.upload(T,aa(Te),Ct,Ue),z.uniformsNeedUpdate=!1),z.isSpriteMaterial&&nt.setValue(T,"center",I.center),nt.setValue(T,"modelViewMatrix",I.modelViewMatrix),nt.setValue(T,"normalMatrix",I.normalMatrix),nt.setValue(T,"modelMatrix",I.matrixWorld),z.isShaderMaterial||z.isRawShaderMaterial){const vt=z.uniformsGroups;for(let Mt=0,gr=vt.length;Mt0&&Ue.useMultisampledRTT(v)===!1?I=ge.get(v).__webglMultisampledFramebuffer:Array.isArray(Re)?I=Re[B]:I=Re,P.copy(v.viewport),O.copy(v.scissor),H=v.scissorTest}else P.copy(Ee).multiplyScalar(G).floor(),O.copy(Oe).multiplyScalar(G).floor(),H=Ke;if(B!==0&&(I=Yo),me.bindFramebuffer(T.FRAMEBUFFER,I)&&z&&me.drawBuffers(v,I),me.viewport(P),me.scissor(O),me.setScissorTest(H),Q){const ue=ge.get(v.texture);T.framebufferTexture2D(T.FRAMEBUFFER,T.COLOR_ATTACHMENT0,T.TEXTURE_CUBE_MAP_POSITIVE_X+L,ue.__webglTexture,B)}else if(oe){const ue=L;for(let Ae=0;Ae=0&&L<=v.width-z&&B>=0&&B<=v.height-I&&(v.textures.length>1&&T.readBuffer(T.COLOR_ATTACHMENT0+fe),T.readPixels(L,B,z,I,xe.convert(Re),xe.convert(ye),Q))}finally{const Ae=U!==null?ge.get(U).__webglFramebuffer:null;me.bindFramebuffer(T.FRAMEBUFFER,Ae)}}},this.readRenderTargetPixelsAsync=async function(v,L,B,z,I,Q,oe,fe=0){if(!(v&&v.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let ue=ge.get(v).__webglFramebuffer;if(v.isWebGLCubeRenderTarget&&oe!==void 0&&(ue=ue[oe]),ue)if(L>=0&&L<=v.width-z&&B>=0&&B<=v.height-I){me.bindFramebuffer(T.FRAMEBUFFER,ue);const Ae=v.textures[fe],Re=Ae.format,ye=Ae.type;if(!we.textureFormatReadable(Re))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!we.textureTypeReadable(ye))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");const Be=T.createBuffer();T.bindBuffer(T.PIXEL_PACK_BUFFER,Be),T.bufferData(T.PIXEL_PACK_BUFFER,Q.byteLength,T.STREAM_READ),v.textures.length>1&&T.readBuffer(T.COLOR_ATTACHMENT0+fe),T.readPixels(L,B,z,I,xe.convert(Re),xe.convert(ye),0);const qe=U!==null?ge.get(U).__webglFramebuffer:null;me.bindFramebuffer(T.FRAMEBUFFER,qe);const rt=T.fenceSync(T.SYNC_GPU_COMMANDS_COMPLETE,0);return T.flush(),await zc(T,rt,4),T.bindBuffer(T.PIXEL_PACK_BUFFER,Be),T.getBufferSubData(T.PIXEL_PACK_BUFFER,0,Q),T.deleteBuffer(Be),T.deleteSync(rt),Q}else throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")},this.copyFramebufferToTexture=function(v,L=null,B=0){const z=Math.pow(2,-B),I=Math.floor(v.image.width*z),Q=Math.floor(v.image.height*z),oe=L!==null?L.x:0,fe=L!==null?L.y:0;Ue.setTexture2D(v,0),T.copyTexSubImage2D(T.TEXTURE_2D,B,0,0,oe,fe,I,Q),me.unbindTexture()};const $o=T.createFramebuffer(),Ko=T.createFramebuffer();this.copyTextureToTexture=function(v,L,B=null,z=null,I=0,Q=null){Q===null&&(I!==0?(vi("WebGLRenderer: copyTextureToTexture function signature has changed to support src and dst mipmap levels."),Q=I,I=0):Q=0);let oe,fe,ue,Ae,Re,ye,Be,qe,rt;const je=v.isCompressedTexture?v.mipmaps[Q]:v.image;if(B!==null)oe=B.max.x-B.min.x,fe=B.max.y-B.min.y,ue=B.isBox3?B.max.z-B.min.z:1,Ae=B.min.x,Re=B.min.y,ye=B.isBox3?B.min.z:0;else{const Pt=Math.pow(2,-I);oe=Math.floor(je.width*Pt),fe=Math.floor(je.height*Pt),v.isDataArrayTexture?ue=je.depth:v.isData3DTexture?ue=Math.floor(je.depth*Pt):ue=1,Ae=0,Re=0,ye=0}z!==null?(Be=z.x,qe=z.y,rt=z.z):(Be=0,qe=0,rt=0);const $e=xe.convert(L.format),Te=xe.convert(L.type);let tt;L.isData3DTexture?(Ue.setTexture3D(L,0),tt=T.TEXTURE_3D):L.isDataArrayTexture||L.isCompressedArrayTexture?(Ue.setTexture2DArray(L,0),tt=T.TEXTURE_2D_ARRAY):(Ue.setTexture2D(L,0),tt=T.TEXTURE_2D),T.pixelStorei(T.UNPACK_FLIP_Y_WEBGL,L.flipY),T.pixelStorei(T.UNPACK_PREMULTIPLY_ALPHA_WEBGL,L.premultiplyAlpha),T.pixelStorei(T.UNPACK_ALIGNMENT,L.unpackAlignment);const Ve=T.getParameter(T.UNPACK_ROW_LENGTH),At=T.getParameter(T.UNPACK_IMAGE_HEIGHT),Ln=T.getParameter(T.UNPACK_SKIP_PIXELS),bt=T.getParameter(T.UNPACK_SKIP_ROWS),ri=T.getParameter(T.UNPACK_SKIP_IMAGES);T.pixelStorei(T.UNPACK_ROW_LENGTH,je.width),T.pixelStorei(T.UNPACK_IMAGE_HEIGHT,je.height),T.pixelStorei(T.UNPACK_SKIP_PIXELS,Ae),T.pixelStorei(T.UNPACK_SKIP_ROWS,Re),T.pixelStorei(T.UNPACK_SKIP_IMAGES,ye);const nt=v.isDataArrayTexture||v.isData3DTexture,Ct=L.isDataArrayTexture||L.isData3DTexture;if(v.isDepthTexture){const Pt=ge.get(v),vt=ge.get(L),Mt=ge.get(Pt.__renderTarget),gr=ge.get(vt.__renderTarget);me.bindFramebuffer(T.READ_FRAMEBUFFER,Mt.__webglFramebuffer),me.bindFramebuffer(T.DRAW_FRAMEBUFFER,gr.__webglFramebuffer);for(let _n=0;_n(i[i.None=0]="None",i[i.Left=1]="Left",i[i.Right=2]="Right",i[i.Across=3]="Across",i))(fi||{}),pt=(i=>(i[i.Clubs=0]="Clubs",i[i.Diamonds=1]="Diamonds",i[i.Hearts=2]="Hearts",i[i.Spades=3]="Spades",i))(pt||{});class ho{mesh;card;cardGeometry;cardMaterial;isHovered=!1;isSelected=!1;constructor(e,t){this.card=e,this.mesh=new hi,this.mesh.position.copy(t),this.cardGeometry=new Ti(1.2,1.7),this.cardMaterial=new Bs({color:this.getCardColor(),side:kt});const n=new Et(this.cardGeometry,this.cardMaterial);this.mesh.add(n);const r=new gl(this.cardGeometry),s=new No({color:0,linewidth:2}),a=new ml(r,s);this.mesh.add(a),this.addCardDetails(),this.mesh.userData={card:this}}getCardColor(){switch(this.card.suit){case pt.Hearts:return 16739179;case pt.Diamonds:return 16751001;case pt.Clubs:return 3355443;case pt.Spades:return 1710618;default:return 16777215}}addCardDetails(){const e=new hr(.2,16),t=new cr({color:this.card.suit===pt.Hearts||this.card.suit===pt.Diamonds?16711680:0}),n=new Et(e,t);n.position.set(-.4,.6,.01),this.mesh.add(n);const r=new hr(.3,this.getSuitSegments()),s=new cr({color:this.card.suit===pt.Hearts||this.card.suit===pt.Diamonds?16711680:0}),a=new Et(r,s);a.position.set(0,0,.01),this.mesh.add(a)}getSuitSegments(){switch(this.card.suit){case pt.Hearts:return 3;case pt.Diamonds:return 4;case pt.Clubs:return 5;case pt.Spades:return 6;default:return 16}}getRankString(){return["","","2","3","4","5","6","7","8","9","10","J","Q","K","A"][this.card.rank]||"?"}getSuitString(){switch(this.card.suit){case pt.Hearts:return"♥";case pt.Diamonds:return"♦";case pt.Clubs:return"♣";case pt.Spades:return"♠";default:return"?"}}setHovered(e){this.isHovered!==e&&(this.isHovered=e,e&&!this.isSelected?(this.mesh.position.y+=.3,this.cardMaterial.emissive=new Fe(4473924)):this.isSelected||(this.mesh.position.y-=.3,this.cardMaterial.emissive=new Fe(0)))}setSelected(e){this.isSelected=e,e?(this.mesh.position.y=.5,this.cardMaterial.emissive=new Fe(8947848)):(this.mesh.position.y=0,this.cardMaterial.emissive=new Fe(0))}animateToPosition(e,t=500){return new Promise(n=>{const r=this.mesh.position.clone(),s=Date.now(),a=()=>{const o=Date.now()-s,l=Math.min(o/t,1),c=l<.5?2*l*l:1-Math.pow(-2*l+2,2)/2;this.mesh.position.lerpVectors(r,e,c),l<1?requestAnimationFrame(a):n()};a()})}dispose(){this.cardGeometry.dispose(),this.cardMaterial.dispose()}}class up{scene;camera;renderer;raycaster;mouse;playerCards=[];currentTrickCards=[];hoveredCard=null;selectedCards=[];onCardClick;constructor(e){this.scene=new ul,this.scene.background=new Fe(1722154),this.camera=new It(75,window.innerWidth/window.innerHeight,.1,1e3),this.camera.position.set(0,10,12),this.camera.lookAt(0,0,0),this.renderer=new lp({antialias:!0}),this.renderer.setSize(window.innerWidth,window.innerHeight),this.renderer.shadowMap.enabled=!0,e.appendChild(this.renderer.domElement),this.raycaster=new Al,this.mouse=new Ge,this.setupLights(),this.createTable(),window.addEventListener("resize",this.onWindowResize.bind(this)),this.renderer.domElement.addEventListener("mousemove",this.onMouseMove.bind(this)),this.renderer.domElement.addEventListener("click",this.onClick.bind(this)),this.animate()}setupLights(){const e=new yl(16777215,.6);this.scene.add(e);const t=new El(16777215,.8);t.position.set(5,10,5),t.castShadow=!0,this.scene.add(t);const n=new xl(16777215,4473924,.4);this.scene.add(n)}createTable(){const e=new Js(8,8,.2,32),t=new Bs({color:678442,roughness:.8,metalness:.1}),n=new Et(e,t);n.position.y=-.5,n.receiveShadow=!0,this.scene.add(n);const r=new Qs(8,.15,16,32),s=new Bs({color:9127187}),a=new Et(r,s);a.rotation.x=Math.PI/2,a.position.y=-.4,this.scene.add(a)}addPlayerCards(e){this.clearPlayerCards();const t=e.length,n=1.5,r=-(t-1)*n/2;e.forEach((s,a)=>{const o=new N(r+a*n,0,5),l=new ho(s,o);this.playerCards.push(l),this.scene.add(l.mesh)})}addTrickCard(e,t){const r=[new N(0,0,2),new N(-2,0,0),new N(0,0,-2),new N(2,0,0)][t%4],s=new ho(e,r);this.currentTrickCards.push(s),this.scene.add(s.mesh)}clearTrick(){this.currentTrickCards.forEach(e=>{this.scene.remove(e.mesh),e.dispose()}),this.currentTrickCards=[]}clearPlayerCards(){this.playerCards.forEach(e=>{this.scene.remove(e.mesh),e.dispose()}),this.playerCards=[],this.selectedCards=[]}removePlayerCard(e){const t=this.playerCards.findIndex(n=>n.card.rank===e.rank&&n.card.suit===e.suit);if(t!==-1){const n=this.playerCards[t];this.scene.remove(n.mesh),n.dispose(),this.playerCards.splice(t,1),this.rearrangePlayerCards()}}rearrangePlayerCards(){const e=this.playerCards.length,t=1.5,n=-(e-1)*t/2;this.playerCards.forEach((r,s)=>{const a=new N(n+s*t,r.mesh.position.y,5);r.animateToPosition(a,300)})}getSelectedCards(){return this.selectedCards}clearSelection(){this.selectedCards.forEach(e=>e.setSelected(!1)),this.selectedCards=[]}onMouseMove(e){this.mouse.x=e.clientX/window.innerWidth*2-1,this.mouse.y=-(e.clientY/window.innerHeight)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);const t=this.playerCards.map(r=>r.mesh),n=this.raycaster.intersectObjects(t,!0);if(n.length>0){const s=n[0].object.parent?.userData.card;s&&s!==this.hoveredCard&&(this.hoveredCard&&this.hoveredCard.setHovered(!1),this.hoveredCard=s,this.hoveredCard.setHovered(!0))}else this.hoveredCard&&(this.hoveredCard.setHovered(!1),this.hoveredCard=null)}onClick(e){this.mouse.x=e.clientX/window.innerWidth*2-1,this.mouse.y=-(e.clientY/window.innerHeight)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);const t=this.playerCards.map(r=>r.mesh),n=this.raycaster.intersectObjects(t,!0);if(n.length>0){const s=n[0].object.parent?.userData.card;s&&(this.handleCardSelection(s),this.onCardClick&&this.onCardClick(s))}}handleCardSelection(e){const t=this.selectedCards.indexOf(e);t!==-1?(this.selectedCards.splice(t,1),e.setSelected(!1)):this.selectedCards.length<3&&(this.selectedCards.push(e),e.setSelected(!0))}onWindowResize(){this.camera.aspect=window.innerWidth/window.innerHeight,this.camera.updateProjectionMatrix(),this.renderer.setSize(window.innerWidth,window.innerHeight)}animate(){requestAnimationFrame(this.animate.bind(this)),this.renderer.render(this.scene,this.camera)}dispose(){window.removeEventListener("resize",this.onWindowResize.bind(this)),this.renderer.domElement.removeEventListener("mousemove",this.onMouseMove.bind(this)),this.renderer.domElement.removeEventListener("click",this.onClick.bind(this)),this.renderer.dispose()}}class hp{connectionPanel;gameInfo;messageDisplay;statusElement;roundNumberEl;playerScoreEl;totalScoreEl;passDirectionEl;turnStatusEl;connectionStatusEl;constructor(){this.connectionPanel=document.getElementById("connection-panel"),this.gameInfo=document.getElementById("game-info"),this.messageDisplay=document.getElementById("message-display"),this.statusElement=document.getElementById("status"),this.roundNumberEl=document.getElementById("round-number"),this.playerScoreEl=document.getElementById("player-score"),this.totalScoreEl=document.getElementById("total-score"),this.passDirectionEl=document.getElementById("pass-direction"),this.turnStatusEl=document.getElementById("turn-status"),this.connectionStatusEl=document.getElementById("connection-status")}showConnectionPanel(){this.connectionPanel.classList.remove("hidden"),this.gameInfo.classList.add("hidden")}hideConnectionPanel(){this.connectionPanel.classList.add("hidden"),this.gameInfo.classList.remove("hidden")}setConnectionStatus(e){this.connectionStatusEl.textContent=e}updateGameInfo(e){e.roundNumber!==void 0&&(this.roundNumberEl.textContent=e.roundNumber.toString()),e.playerScore!==void 0&&(this.playerScoreEl.textContent=e.playerScore.toString()),e.totalScore!==void 0&&(this.totalScoreEl.textContent=e.totalScore.toString()),e.passDirection!==void 0&&(this.passDirectionEl.textContent=`Pass: ${e.passDirection}`),e.isMyTurn!==void 0&&(this.turnStatusEl.textContent=e.isMyTurn?"Your turn!":"Waiting...",this.turnStatusEl.style.color=e.isMyTurn?"#4caf50":"#666")}setStatus(e){this.statusElement.textContent=e}showMessage(e,t=3e3){this.messageDisplay.textContent=e,this.messageDisplay.classList.add("show"),setTimeout(()=>{this.messageDisplay.classList.remove("show")},t)}getConnectionInputs(){return{playerName:document.getElementById("player-name").value,gameId:document.getElementById("game-id").value}}setConnectButtonEnabled(e){const t=document.getElementById("connect-btn");t.disabled=!e}}class dp{constructor(e,t){this.actionSocket=e,this.notificationSocket=t,this.gameStartedHandlers=[],this.passingPhaseStartedHandlers=[],this.allPlayersPassedHandlers=[],this.playerPassedCardsHandlers=[],this.itsYourTurnHandlers=[],this.itsPlayersTurnHandlers=[],this.playerPlayedCardHandlers=[],this.trickCompletedHandlers=[],this.roundEndedHandlers=[],this.gameEndedHandlers=[],this.heartsWereBrokenHandlers=[],this.setupNotificationHandlers()}setupNotificationHandlers(){this.notificationSocket.onmessage=e=>{const t=JSON.parse(e.data);this.handleNotification(t)}}handleNotification(e){switch(e.type){case"GameStarted":this.gameStartedHandlers.forEach(t=>t(e.data));break;case"PassingPhaseStarted":this.passingPhaseStartedHandlers.forEach(t=>t(e.data));break;case"AllPlayersPassed":this.allPlayersPassedHandlers.forEach(t=>t(e.data));break;case"PlayerPassedCards":this.playerPassedCardsHandlers.forEach(t=>t(e.data));break;case"ItsYourTurn":this.itsYourTurnHandlers.forEach(t=>t(e.data));break;case"ItsPlayersTurn":this.itsPlayersTurnHandlers.forEach(t=>t(e.data));break;case"PlayerPlayedCard":this.playerPlayedCardHandlers.forEach(t=>t(e.data));break;case"TrickCompleted":this.trickCompletedHandlers.forEach(t=>t(e.data));break;case"RoundEnded":this.roundEndedHandlers.forEach(t=>t(e.data));break;case"GameEnded":this.gameEndedHandlers.forEach(t=>t(e.data));break;case"HeartsWereBroken":this.heartsWereBrokenHandlers.forEach(t=>t(e.data));break}}onGameStarted(e){this.gameStartedHandlers.push(e)}offGameStarted(e){const t=this.gameStartedHandlers.indexOf(e);t>-1&&this.gameStartedHandlers.splice(t,1)}onPassingPhaseStarted(e){this.passingPhaseStartedHandlers.push(e)}offPassingPhaseStarted(e){const t=this.passingPhaseStartedHandlers.indexOf(e);t>-1&&this.passingPhaseStartedHandlers.splice(t,1)}onAllPlayersPassed(e){this.allPlayersPassedHandlers.push(e)}offAllPlayersPassed(e){const t=this.allPlayersPassedHandlers.indexOf(e);t>-1&&this.allPlayersPassedHandlers.splice(t,1)}onPlayerPassedCards(e){this.playerPassedCardsHandlers.push(e)}offPlayerPassedCards(e){const t=this.playerPassedCardsHandlers.indexOf(e);t>-1&&this.playerPassedCardsHandlers.splice(t,1)}onItsYourTurn(e){this.itsYourTurnHandlers.push(e)}offItsYourTurn(e){const t=this.itsYourTurnHandlers.indexOf(e);t>-1&&this.itsYourTurnHandlers.splice(t,1)}onItsPlayersTurn(e){this.itsPlayersTurnHandlers.push(e)}offItsPlayersTurn(e){const t=this.itsPlayersTurnHandlers.indexOf(e);t>-1&&this.itsPlayersTurnHandlers.splice(t,1)}onPlayerPlayedCard(e){this.playerPlayedCardHandlers.push(e)}offPlayerPlayedCard(e){const t=this.playerPlayedCardHandlers.indexOf(e);t>-1&&this.playerPlayedCardHandlers.splice(t,1)}onTrickCompleted(e){this.trickCompletedHandlers.push(e)}offTrickCompleted(e){const t=this.trickCompletedHandlers.indexOf(e);t>-1&&this.trickCompletedHandlers.splice(t,1)}onRoundEnded(e){this.roundEndedHandlers.push(e)}offRoundEnded(e){const t=this.roundEndedHandlers.indexOf(e);t>-1&&this.roundEndedHandlers.splice(t,1)}onGameEnded(e){this.gameEndedHandlers.push(e)}offGameEnded(e){const t=this.gameEndedHandlers.indexOf(e);t>-1&&this.gameEndedHandlers.splice(t,1)}onHeartsWereBroken(e){this.heartsWereBrokenHandlers.push(e)}offHeartsWereBroken(e){const t=this.heartsWereBrokenHandlers.indexOf(e);t>-1&&this.heartsWereBrokenHandlers.splice(t,1)}async passCards(e){return new Promise((t,n)=>{const r={type:"PassCards",data:{request:e}},s=a=>{const o=JSON.parse(a.data);o.error?n(new Error(o.error)):t(o.data),this.actionSocket.removeEventListener("message",s)};this.actionSocket.addEventListener("message",s),this.actionSocket.send(JSON.stringify(r))})}async playCard(e){return new Promise((t,n)=>{const r={type:"PlayCard",data:{request:e}},s=a=>{const o=JSON.parse(a.data);o.error?n(new Error(o.error)):t(o.data),this.actionSocket.removeEventListener("message",s)};this.actionSocket.addEventListener("message",s),this.actionSocket.send(JSON.stringify(r))})}}class fp{client;scene;ui;playerId="";passingPhase=!1;myTurn=!1;constructor(e,t){this.scene=e,this.ui=t,this.scene.onCardClick=this.handleCardClick.bind(this)}async connect(e,t,n,r){this.playerId=t;try{console.log("Starting connection process..."),this.ui.setConnectionStatus("Authenticating..."),this.ui.setConnectButtonEnabled(!1);const s=e.replace("ws://","http://").replace("wss://","https://");console.log("Authenticating with:",s+"/login");const a=await fetch(`${s}/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:n,password:"default-password"}),credentials:"include"});if(console.log("Login response status:",a.status),!a.ok){const _=await a.text();throw console.error("Login failed:",_),new Error(`Authentication failed: ${a.status} ${a.statusText} -${_}`)}const o=await a.json();console.log("Authenticated successfully:",o);const l=o.accessToken;this.ui.setConnectionStatus("Authenticated. Connecting to game..."),console.log("Attempting to connect to game:",r);const c=`${e}/hearts/join/${encodeURIComponent(r)}`;console.log("Connecting action socket to:",c);const d=new WebSocket(c);await this.waitForSocketOpen(d),console.log("Action socket connected"),this.ui.setConnectionStatus("Action socket connected. Waiting for connection ID..."),console.log("Waiting for connection ID...");const h=await this.getConnectionId(d);console.log("Received connection ID:",h),this.ui.setConnectionStatus("Establishing notification socket...");const f=`${e}/hearts/join/${h}/finish`;console.log("Connecting notification socket to:",f);const m=new WebSocket(f);await this.waitForSocketOpen(m),console.log("Notification socket connected"),this.ui.setConnectionStatus("Connected!"),this.client=new dp(d,m),this.setupEventHandlers(),this.ui.hideConnectionPanel(),this.ui.setStatus("Connected to game"),this.ui.showMessage("Connected to Hearts game!")}catch(s){console.error("Connection error:",s);const a=s instanceof Error?s.message:String(s);throw this.ui.setConnectionStatus(`Connection failed: ${a}`),this.ui.showMessage(`Connection failed: ${a}`,1e4),this.ui.setConnectButtonEnabled(!0),s}}getConnectionId(e){return new Promise((t,n)=>{const r=setTimeout(()=>{n(new Error("Timeout waiting for connection ID (10 seconds). The game may not exist or you may not have permission to join."))},1e4),s=a=>{console.log("Received message while waiting for connection ID:",a.data),clearTimeout(r);try{const o=JSON.parse(a.data);console.log("Parsed data:",o),o.connectionId?(e.removeEventListener("message",s),t(o.connectionId)):(console.error("Message does not contain connectionId:",o),n(new Error("No connectionId in response. Received: "+JSON.stringify(o))))}catch(o){console.error("Failed to parse message:",o,"Raw data:",a.data),n(new Error("Failed to parse connection ID response: "+a.data))}};e.addEventListener("message",s)})}waitForSocketOpen(e){return new Promise((t,n)=>{const r=setTimeout(()=>{n(new Error("Connection timeout - server not responding"))},1e4);e.onopen=()=>{clearTimeout(r),t()},e.onerror=s=>{clearTimeout(r),console.error("WebSocket error:",s),console.error("Socket URL:",e.url),console.error("Socket readyState:",e.readyState),n(new Error(`WebSocket connection failed. Make sure: +}`;class Kf{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t){if(this.texture===null){const n=new bo(e.texture);(e.depthNear!==t.depthNear||e.depthFar!==t.depthFar)&&(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=n}}getMesh(e){if(this.texture!==null&&this.mesh===null){const t=e.cameras[0].viewport,n=new gn({vertexShader:Yf,fragmentShader:$f,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new wt(new ai(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class Zf extends si{constructor(e,t){super();const n=this;let r=null,s=1,a=null,o="local-floor",c=1,l=null,h=null,d=null,f=null,m=null,_=null;const x=typeof XRWebGLBinding<"u",p=new Kf,u={},b=t.getContextAttributes();let A=null,E=null;const D=[],R=[],w=new Ge;let U=null;const S=new It;S.viewport=new rt;const M=new It;M.viewport=new rt;const C=[S,M],O=new mc;let z=null,q=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(Y){let j=D[Y];return j===void 0&&(j=new Ir,D[Y]=j),j.getTargetRaySpace()},this.getControllerGrip=function(Y){let j=D[Y];return j===void 0&&(j=new Ir,D[Y]=j),j.getGripSpace()},this.getHand=function(Y){let j=D[Y];return j===void 0&&(j=new Ir,D[Y]=j),j.getHandSpace()};function W(Y){const j=R.indexOf(Y.inputSource);if(j===-1)return;const de=D[j];de!==void 0&&(de.update(Y.inputSource,Y.frame,l||a),de.dispatchEvent({type:Y.type,data:Y.inputSource}))}function X(){r.removeEventListener("select",W),r.removeEventListener("selectstart",W),r.removeEventListener("selectend",W),r.removeEventListener("squeeze",W),r.removeEventListener("squeezestart",W),r.removeEventListener("squeezeend",W),r.removeEventListener("end",X),r.removeEventListener("inputsourceschange",Z);for(let Y=0;Y=0&&(R[Ce]=null,D[Ce].disconnect(de))}for(let j=0;j=R.length){R.push(de),Ce=ze;break}else if(R[ze]===null){R[ze]=de,Ce=ze;break}if(Ce===-1)break}const Se=D[Ce];Se&&Se.connect(de)}}const G=new F,se=new F;function ce(Y,j,de){G.setFromMatrixPosition(j.matrixWorld),se.setFromMatrixPosition(de.matrixWorld);const Ce=G.distanceTo(se),Se=j.projectionMatrix.elements,ze=de.projectionMatrix.elements,ft=Se[14]/(Se[10]-1),T=Se[14]/(Se[10]+1),Qe=(Se[9]+1)/Se[5],De=(Se[9]-1)/Se[5],we=(Se[8]-1)/Se[0],me=(ze[8]+1)/ze[0],et=ft*we,ge=ft*me,Ue=Ce/(-we+me),ut=Ue*-we;if(j.matrixWorld.decompose(Y.position,Y.quaternion,Y.scale),Y.translateX(ut),Y.translateZ(Ue),Y.matrixWorld.compose(Y.position,Y.quaternion,Y.scale),Y.matrixWorldInverse.copy(Y.matrixWorld).invert(),Se[10]===-1)Y.projectionMatrix.copy(j.projectionMatrix),Y.projectionMatrixInverse.copy(j.projectionMatrixInverse);else{const at=ft+Ue,y=T+Ue,g=et-ut,N=ge+(Ce-ut),V=Qe*T/y*at,K=De*T/y*at;Y.projectionMatrix.makePerspective(g,N,V,K,at,y),Y.projectionMatrixInverse.copy(Y.projectionMatrix).invert()}}function Ee(Y,j){j===null?Y.matrixWorld.copy(Y.matrix):Y.matrixWorld.multiplyMatrices(j.matrixWorld,Y.matrix),Y.matrixWorldInverse.copy(Y.matrixWorld).invert()}this.updateCamera=function(Y){if(r===null)return;let j=Y.near,de=Y.far;p.texture!==null&&(p.depthNear>0&&(j=p.depthNear),p.depthFar>0&&(de=p.depthFar)),O.near=M.near=S.near=j,O.far=M.far=S.far=de,(z!==O.near||q!==O.far)&&(r.updateRenderState({depthNear:O.near,depthFar:O.far}),z=O.near,q=O.far),O.layers.mask=Y.layers.mask|6,S.layers.mask=O.layers.mask&3,M.layers.mask=O.layers.mask&5;const Ce=Y.parent,Se=O.cameras;Ee(O,Ce);for(let ze=0;ze0&&(p.alphaTest.value=u.alphaTest);const b=e.get(u),A=b.envMap,E=b.envMapRotation;A&&(p.envMap.value=A,Tn.copy(E),Tn.x*=-1,Tn.y*=-1,Tn.z*=-1,A.isCubeTexture&&A.isRenderTargetTexture===!1&&(Tn.y*=-1,Tn.z*=-1),p.envMapRotation.value.setFromMatrix4(jf.makeRotationFromEuler(Tn)),p.flipEnvMap.value=A.isCubeTexture&&A.isRenderTargetTexture===!1?-1:1,p.reflectivity.value=u.reflectivity,p.ior.value=u.ior,p.refractionRatio.value=u.refractionRatio),u.lightMap&&(p.lightMap.value=u.lightMap,p.lightMapIntensity.value=u.lightMapIntensity,t(u.lightMap,p.lightMapTransform)),u.aoMap&&(p.aoMap.value=u.aoMap,p.aoMapIntensity.value=u.aoMapIntensity,t(u.aoMap,p.aoMapTransform))}function a(p,u){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,u.map&&(p.map.value=u.map,t(u.map,p.mapTransform))}function o(p,u){p.dashSize.value=u.dashSize,p.totalSize.value=u.dashSize+u.gapSize,p.scale.value=u.scale}function c(p,u,b,A){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,p.size.value=u.size*b,p.scale.value=A*.5,u.map&&(p.map.value=u.map,t(u.map,p.uvTransform)),u.alphaMap&&(p.alphaMap.value=u.alphaMap,t(u.alphaMap,p.alphaMapTransform)),u.alphaTest>0&&(p.alphaTest.value=u.alphaTest)}function l(p,u){p.diffuse.value.copy(u.color),p.opacity.value=u.opacity,p.rotation.value=u.rotation,u.map&&(p.map.value=u.map,t(u.map,p.mapTransform)),u.alphaMap&&(p.alphaMap.value=u.alphaMap,t(u.alphaMap,p.alphaMapTransform)),u.alphaTest>0&&(p.alphaTest.value=u.alphaTest)}function h(p,u){p.specular.value.copy(u.specular),p.shininess.value=Math.max(u.shininess,1e-4)}function d(p,u){u.gradientMap&&(p.gradientMap.value=u.gradientMap)}function f(p,u){p.metalness.value=u.metalness,u.metalnessMap&&(p.metalnessMap.value=u.metalnessMap,t(u.metalnessMap,p.metalnessMapTransform)),p.roughness.value=u.roughness,u.roughnessMap&&(p.roughnessMap.value=u.roughnessMap,t(u.roughnessMap,p.roughnessMapTransform)),u.envMap&&(p.envMapIntensity.value=u.envMapIntensity)}function m(p,u,b){p.ior.value=u.ior,u.sheen>0&&(p.sheenColor.value.copy(u.sheenColor).multiplyScalar(u.sheen),p.sheenRoughness.value=u.sheenRoughness,u.sheenColorMap&&(p.sheenColorMap.value=u.sheenColorMap,t(u.sheenColorMap,p.sheenColorMapTransform)),u.sheenRoughnessMap&&(p.sheenRoughnessMap.value=u.sheenRoughnessMap,t(u.sheenRoughnessMap,p.sheenRoughnessMapTransform))),u.clearcoat>0&&(p.clearcoat.value=u.clearcoat,p.clearcoatRoughness.value=u.clearcoatRoughness,u.clearcoatMap&&(p.clearcoatMap.value=u.clearcoatMap,t(u.clearcoatMap,p.clearcoatMapTransform)),u.clearcoatRoughnessMap&&(p.clearcoatRoughnessMap.value=u.clearcoatRoughnessMap,t(u.clearcoatRoughnessMap,p.clearcoatRoughnessMapTransform)),u.clearcoatNormalMap&&(p.clearcoatNormalMap.value=u.clearcoatNormalMap,t(u.clearcoatNormalMap,p.clearcoatNormalMapTransform),p.clearcoatNormalScale.value.copy(u.clearcoatNormalScale),u.side===Et&&p.clearcoatNormalScale.value.negate())),u.dispersion>0&&(p.dispersion.value=u.dispersion),u.iridescence>0&&(p.iridescence.value=u.iridescence,p.iridescenceIOR.value=u.iridescenceIOR,p.iridescenceThicknessMinimum.value=u.iridescenceThicknessRange[0],p.iridescenceThicknessMaximum.value=u.iridescenceThicknessRange[1],u.iridescenceMap&&(p.iridescenceMap.value=u.iridescenceMap,t(u.iridescenceMap,p.iridescenceMapTransform)),u.iridescenceThicknessMap&&(p.iridescenceThicknessMap.value=u.iridescenceThicknessMap,t(u.iridescenceThicknessMap,p.iridescenceThicknessMapTransform))),u.transmission>0&&(p.transmission.value=u.transmission,p.transmissionSamplerMap.value=b.texture,p.transmissionSamplerSize.value.set(b.width,b.height),u.transmissionMap&&(p.transmissionMap.value=u.transmissionMap,t(u.transmissionMap,p.transmissionMapTransform)),p.thickness.value=u.thickness,u.thicknessMap&&(p.thicknessMap.value=u.thicknessMap,t(u.thicknessMap,p.thicknessMapTransform)),p.attenuationDistance.value=u.attenuationDistance,p.attenuationColor.value.copy(u.attenuationColor)),u.anisotropy>0&&(p.anisotropyVector.value.set(u.anisotropy*Math.cos(u.anisotropyRotation),u.anisotropy*Math.sin(u.anisotropyRotation)),u.anisotropyMap&&(p.anisotropyMap.value=u.anisotropyMap,t(u.anisotropyMap,p.anisotropyMapTransform))),p.specularIntensity.value=u.specularIntensity,p.specularColor.value.copy(u.specularColor),u.specularColorMap&&(p.specularColorMap.value=u.specularColorMap,t(u.specularColorMap,p.specularColorMapTransform)),u.specularIntensityMap&&(p.specularIntensityMap.value=u.specularIntensityMap,t(u.specularIntensityMap,p.specularIntensityMapTransform))}function _(p,u){u.matcap&&(p.matcap.value=u.matcap)}function x(p,u){const b=e.get(u).light;p.referencePosition.value.setFromMatrixPosition(b.matrixWorld),p.nearDistance.value=b.shadow.camera.near,p.farDistance.value=b.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:r}}function Qf(i,e,t,n){let r={},s={},a=[];const o=i.getParameter(i.MAX_UNIFORM_BUFFER_BINDINGS);function c(b,A){const E=A.program;n.uniformBlockBinding(b,E)}function l(b,A){let E=r[b.id];E===void 0&&(_(b),E=h(b),r[b.id]=E,b.addEventListener("dispose",p));const D=A.program;n.updateUBOMapping(b,D);const R=e.render.frame;s[b.id]!==R&&(f(b),s[b.id]=R)}function h(b){const A=d();b.__bindingPointIndex=A;const E=i.createBuffer(),D=b.__size,R=b.usage;return i.bindBuffer(i.UNIFORM_BUFFER,E),i.bufferData(i.UNIFORM_BUFFER,D,R),i.bindBuffer(i.UNIFORM_BUFFER,null),i.bindBufferBase(i.UNIFORM_BUFFER,A,E),E}function d(){for(let b=0;b0&&(E+=D-R),b.__size=E,b.__cache={},this}function x(b){const A={boundary:0,storage:0};return typeof b=="number"||typeof b=="boolean"?(A.boundary=4,A.storage=4):b.isVector2?(A.boundary=8,A.storage=8):b.isVector3||b.isColor?(A.boundary=16,A.storage=12):b.isVector4?(A.boundary=16,A.storage=16):b.isMatrix3?(A.boundary=48,A.storage=48):b.isMatrix4?(A.boundary=64,A.storage=64):b.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",b),A}function p(b){const A=b.target;A.removeEventListener("dispose",p);const E=a.indexOf(A.__bindingPointIndex);a.splice(E,1),i.deleteBuffer(r[A.id]),delete r[A.id],delete s[A.id]}function u(){for(const b in r)i.deleteBuffer(r[b]);a=[],r={},s={}}return{bind:c,update:l,dispose:u}}class ep{constructor(e={}){const{canvas:t=Cl(),context:n=null,depth:r=!0,stencil:s=!1,alpha:a=!1,antialias:o=!1,premultipliedAlpha:c=!0,preserveDrawingBuffer:l=!1,powerPreference:h="default",failIfMajorPerformanceCaveat:d=!1,reversedDepthBuffer:f=!1}=e;this.isWebGLRenderer=!0;let m;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");m=n.getContextAttributes().alpha}else m=a;const _=new Uint32Array(4),x=new Int32Array(4);let p=null,u=null;const b=[],A=[];this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.toneMapping=pn,this.toneMappingExposure=1,this.transmissionResolutionScale=1;const E=this;let D=!1;this._outputColorSpace=Lt;let R=0,w=0,U=null,S=-1,M=null;const C=new rt,O=new rt;let z=null;const q=new Oe(0);let W=0,X=t.width,Z=t.height,G=1,se=null,ce=null;const Ee=new rt(0,0,X,Z),Fe=new rt(0,0,X,Z);let Ke=!1;const Je=new ks;let We=!1,Y=!1;const j=new st,de=new F,Ce=new rt,Se={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let ze=!1;function ft(){return U===null?G:1}let T=n;function Qe(v,L){return t.getContext(v,L)}try{const v={alpha:!0,depth:r,stencil:s,antialias:o,premultipliedAlpha:c,preserveDrawingBuffer:l,powerPreference:h,failIfMajorPerformanceCaveat:d};if("setAttribute"in t&&t.setAttribute("data-engine",`three.js r${Ls}`),t.addEventListener("webglcontextlost",ie,!1),t.addEventListener("webglcontextrestored",he,!1),t.addEventListener("webglcontextcreationerror",J,!1),T===null){const L="webgl2";if(T=Qe(L,v),T===null)throw Qe(L)?new Error("Error creating WebGL context with your selected attributes."):new Error("Error creating WebGL context.")}}catch(v){throw console.error("THREE.WebGLRenderer: "+v.message),v}let De,we,me,et,ge,Ue,ut,at,y,g,N,V,K,k,Me,ne,_e,ve,ee,le,be,xe,ae,Le;function P(){De=new cd(T),De.init(),xe=new qf(T,De),we=new nd(T,De,e,xe),me=new Wf(T,De),we.reversedDepthBuffer&&f&&me.buffers.depth.setReversed(!0),et=new dd(T),ge=new Df,Ue=new Xf(T,De,me,ge,we,xe,et),ut=new rd(E),at=new ld(E),y=new vc(T),ae=new ed(T,y),g=new ud(T,y,et,ae),N=new pd(T,g,y,et),ee=new fd(T,we,Ue),ne=new id(ge),V=new Pf(E,ut,at,De,we,ae,ne),K=new Jf(E,ge),k=new If,Me=new Hf(De),ve=new Qh(E,ut,at,me,N,m,c),_e=new kf(E,N,we),Le=new Qf(T,et,we,me),le=new td(T,De,et),be=new hd(T,De,et),et.programs=V.programs,E.capabilities=we,E.extensions=De,E.properties=ge,E.renderLists=k,E.shadowMap=_e,E.state=me,E.info=et}P();const te=new Zf(E,T);this.xr=te,this.getContext=function(){return T},this.getContextAttributes=function(){return T.getContextAttributes()},this.forceContextLoss=function(){const v=De.get("WEBGL_lose_context");v&&v.loseContext()},this.forceContextRestore=function(){const v=De.get("WEBGL_lose_context");v&&v.restoreContext()},this.getPixelRatio=function(){return G},this.setPixelRatio=function(v){v!==void 0&&(G=v,this.setSize(X,Z,!1))},this.getSize=function(v){return v.set(X,Z)},this.setSize=function(v,L,B=!0){if(te.isPresenting){console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting.");return}X=v,Z=L,t.width=Math.floor(v*G),t.height=Math.floor(L*G),B===!0&&(t.style.width=v+"px",t.style.height=L+"px"),this.setViewport(0,0,v,L)},this.getDrawingBufferSize=function(v){return v.set(X*G,Z*G).floor()},this.setDrawingBufferSize=function(v,L,B){X=v,Z=L,G=B,t.width=Math.floor(v*B),t.height=Math.floor(L*B),this.setViewport(0,0,v,L)},this.getCurrentViewport=function(v){return v.copy(C)},this.getViewport=function(v){return v.copy(Ee)},this.setViewport=function(v,L,B,H){v.isVector4?Ee.set(v.x,v.y,v.z,v.w):Ee.set(v,L,B,H),me.viewport(C.copy(Ee).multiplyScalar(G).round())},this.getScissor=function(v){return v.copy(Fe)},this.setScissor=function(v,L,B,H){v.isVector4?Fe.set(v.x,v.y,v.z,v.w):Fe.set(v,L,B,H),me.scissor(O.copy(Fe).multiplyScalar(G).round())},this.getScissorTest=function(){return Ke},this.setScissorTest=function(v){me.setScissorTest(Ke=v)},this.setOpaqueSort=function(v){se=v},this.setTransparentSort=function(v){ce=v},this.getClearColor=function(v){return v.copy(ve.getClearColor())},this.setClearColor=function(){ve.setClearColor(...arguments)},this.getClearAlpha=function(){return ve.getClearAlpha()},this.setClearAlpha=function(){ve.setClearAlpha(...arguments)},this.clear=function(v=!0,L=!0,B=!0){let H=0;if(v){let I=!1;if(U!==null){const Q=U.texture.format;I=Q===Bs||Q===Os||Q===Fs}if(I){const Q=U.texture.type,oe=Q===qt||Q===Ln||Q===_i||Q===vi||Q===Us||Q===Ns,fe=ve.getClearColor(),ue=ve.getClearAlpha(),Ae=fe.r,Re=fe.g,ye=fe.b;oe?(_[0]=Ae,_[1]=Re,_[2]=ye,_[3]=ue,T.clearBufferuiv(T.COLOR,0,_)):(x[0]=Ae,x[1]=Re,x[2]=ye,x[3]=ue,T.clearBufferiv(T.COLOR,0,x))}else H|=T.COLOR_BUFFER_BIT}L&&(H|=T.DEPTH_BUFFER_BIT),B&&(H|=T.STENCIL_BUFFER_BIT,this.state.buffers.stencil.setMask(4294967295)),T.clear(H)},this.clearColor=function(){this.clear(!0,!1,!1)},this.clearDepth=function(){this.clear(!1,!0,!1)},this.clearStencil=function(){this.clear(!1,!1,!0)},this.dispose=function(){t.removeEventListener("webglcontextlost",ie,!1),t.removeEventListener("webglcontextrestored",he,!1),t.removeEventListener("webglcontextcreationerror",J,!1),ve.dispose(),k.dispose(),Me.dispose(),ge.dispose(),ut.dispose(),at.dispose(),N.dispose(),ae.dispose(),Le.dispose(),V.dispose(),te.dispose(),te.removeEventListener("sessionstart",kt),te.removeEventListener("sessionend",$s),_n.stop()};function ie(v){v.preventDefault(),console.log("THREE.WebGLRenderer: Context Lost."),D=!0}function he(){console.log("THREE.WebGLRenderer: Context Restored."),D=!1;const v=et.autoReset,L=_e.enabled,B=_e.autoUpdate,H=_e.needsUpdate,I=_e.type;P(),et.autoReset=v,_e.enabled=L,_e.autoUpdate=B,_e.needsUpdate=H,_e.type=I}function J(v){console.error("THREE.WebGLRenderer: A WebGL context could not be created. Reason: ",v.statusMessage)}function $(v){const L=v.target;L.removeEventListener("dispose",$),pe(L)}function pe(v){Pe(v),ge.remove(v)}function Pe(v){const L=ge.get(v).programs;L!==void 0&&(L.forEach(function(B){V.releaseProgram(B)}),v.isShaderMaterial&&V.releaseShaderCache(v))}this.renderBufferDirect=function(v,L,B,H,I,Q){L===null&&(L=Se);const oe=I.isMesh&&I.matrixWorld.determinant()<0,fe=No(v,L,B,H,I);me.setMaterial(H,oe);let ue=B.index,Ae=1;if(H.wireframe===!0){if(ue=g.getWireframeAttribute(B),ue===void 0)return;Ae=2}const Re=B.drawRange,ye=B.attributes.position;let Be=Re.start*Ae,qe=(Re.start+Re.count)*Ae;Q!==null&&(Be=Math.max(Be,Q.start*Ae),qe=Math.min(qe,(Q.start+Q.count)*Ae)),ue!==null?(Be=Math.max(Be,0),qe=Math.min(qe,ue.count)):ye!=null&&(Be=Math.max(Be,0),qe=Math.min(qe,ye.count));const it=qe-Be;if(it<0||it===1/0)return;ae.setup(I,H,fe,B,ue);let je,$e=le;if(ue!==null&&(je=y.get(ue),$e=be,$e.setIndex(je)),I.isMesh)H.wireframe===!0?(me.setLineWidth(H.wireframeLinewidth*ft()),$e.setMode(T.LINES)):$e.setMode(T.TRIANGLES);else if(I.isLine){let Te=H.linewidth;Te===void 0&&(Te=1),me.setLineWidth(Te*ft()),I.isLineSegments?$e.setMode(T.LINES):I.isLineLoop?$e.setMode(T.LINE_LOOP):$e.setMode(T.LINE_STRIP)}else I.isPoints?$e.setMode(T.POINTS):I.isSprite&&$e.setMode(T.TRIANGLES);if(I.isBatchedMesh)if(I._multiDrawInstances!==null)Ei("THREE.WebGLRenderer: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection."),$e.renderMultiDrawInstances(I._multiDrawStarts,I._multiDrawCounts,I._multiDrawCount,I._multiDrawInstances);else if(De.get("WEBGL_multi_draw"))$e.renderMultiDraw(I._multiDrawStarts,I._multiDrawCounts,I._multiDrawCount);else{const Te=I._multiDrawStarts,tt=I._multiDrawCounts,ke=I._multiDrawCount,yt=ue?y.get(ue).bytesPerElement:1,Un=ge.get(H).currentProgram.getUniforms();for(let Tt=0;Tt{function Q(){if(H.forEach(function(oe){ge.get(oe).currentProgram.isReady()&&H.delete(oe)}),H.size===0){I(v);return}setTimeout(Q,10)}De.get("KHR_parallel_shader_compile")!==null?Q():setTimeout(Q,10)})};let Xe=null;function $t(v){Xe&&Xe(v)}function kt(){_n.stop()}function $s(){_n.start()}const _n=new Co;_n.setAnimationLoop($t),typeof self<"u"&&_n.setContext(self),this.setAnimationLoop=function(v){Xe=v,te.setAnimationLoop(v),v===null?_n.stop():_n.start()},te.addEventListener("sessionstart",kt),te.addEventListener("sessionend",$s),this.render=function(v,L){if(L!==void 0&&L.isCamera!==!0){console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(D===!0)return;if(v.matrixWorldAutoUpdate===!0&&v.updateMatrixWorld(),L.parent===null&&L.matrixWorldAutoUpdate===!0&&L.updateMatrixWorld(),te.enabled===!0&&te.isPresenting===!0&&(te.cameraAutoUpdate===!0&&te.updateCamera(L),L=te.getCamera()),v.isScene===!0&&v.onBeforeRender(E,v,L,U),u=Me.get(v,A.length),u.init(L),A.push(u),j.multiplyMatrices(L.projectionMatrix,L.matrixWorldInverse),Je.setFromProjectionMatrix(j,Wt,L.reversedDepth),Y=this.localClippingEnabled,We=ne.init(this.clippingPlanes,Y),p=k.get(v,b.length),p.init(),b.push(p),te.enabled===!0&&te.isPresenting===!0){const Q=E.xr.getDepthSensingMesh();Q!==null&&lr(Q,L,-1/0,E.sortObjects)}lr(v,L,0,E.sortObjects),p.finish(),E.sortObjects===!0&&p.sort(se,ce),ze=te.enabled===!1||te.isPresenting===!1||te.hasDepthSensing()===!1,ze&&ve.addToRenderList(p,v),this.info.render.frame++,We===!0&&ne.beginShadows();const B=u.state.shadowsArray;_e.render(B,v,L),We===!0&&ne.endShadows(),this.info.autoReset===!0&&this.info.reset();const H=p.opaque,I=p.transmissive;if(u.setupLights(),L.isArrayCamera){const Q=L.cameras;if(I.length>0)for(let oe=0,fe=Q.length;oe0&&Zs(H,I,v,L),ze&&ve.render(v),Ks(p,v,L);U!==null&&w===0&&(Ue.updateMultisampleRenderTarget(U),Ue.updateRenderTargetMipmap(U)),v.isScene===!0&&v.onAfterRender(E,v,L),ae.resetDefaultState(),S=-1,M=null,A.pop(),A.length>0?(u=A[A.length-1],We===!0&&ne.setGlobalState(E.clippingPlanes,u.state.camera)):u=null,b.pop(),b.length>0?p=b[b.length-1]:p=null};function lr(v,L,B,H){if(v.visible===!1)return;if(v.layers.test(L.layers)){if(v.isGroup)B=v.renderOrder;else if(v.isLOD)v.autoUpdate===!0&&v.update(L);else if(v.isLight)u.pushLight(v),v.castShadow&&u.pushShadow(v);else if(v.isSprite){if(!v.frustumCulled||Je.intersectsSprite(v)){H&&Ce.setFromMatrixPosition(v.matrixWorld).applyMatrix4(j);const oe=N.update(v),fe=v.material;fe.visible&&p.push(v,oe,fe,B,Ce.z,null)}}else if((v.isMesh||v.isLine||v.isPoints)&&(!v.frustumCulled||Je.intersectsObject(v))){const oe=N.update(v),fe=v.material;if(H&&(v.boundingSphere!==void 0?(v.boundingSphere===null&&v.computeBoundingSphere(),Ce.copy(v.boundingSphere.center)):(oe.boundingSphere===null&&oe.computeBoundingSphere(),Ce.copy(oe.boundingSphere.center)),Ce.applyMatrix4(v.matrixWorld).applyMatrix4(j)),Array.isArray(fe)){const ue=oe.groups;for(let Ae=0,Re=ue.length;Ae0&&Ci(I,L,B),Q.length>0&&Ci(Q,L,B),oe.length>0&&Ci(oe,L,B),me.buffers.depth.setTest(!0),me.buffers.depth.setMask(!0),me.buffers.color.setMask(!0),me.setPolygonOffset(!1)}function Zs(v,L,B,H){if((B.isScene===!0?B.overrideMaterial:null)!==null)return;u.state.transmissionRenderTarget[H.id]===void 0&&(u.state.transmissionRenderTarget[H.id]=new In(1,1,{generateMipmaps:!0,type:De.has("EXT_color_buffer_half_float")||De.has("EXT_color_buffer_float")?yi:qt,minFilter:Dn,samples:4,stencilBuffer:s,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:Ve.workingColorSpace}));const Q=u.state.transmissionRenderTarget[H.id],oe=H.viewport||C;Q.setSize(oe.z*E.transmissionResolutionScale,oe.w*E.transmissionResolutionScale);const fe=E.getRenderTarget(),ue=E.getActiveCubeFace(),Ae=E.getActiveMipmapLevel();E.setRenderTarget(Q),E.getClearColor(q),W=E.getClearAlpha(),W<1&&E.setClearColor(16777215,.5),E.clear(),ze&&ve.render(B);const Re=E.toneMapping;E.toneMapping=pn;const ye=H.viewport;if(H.viewport!==void 0&&(H.viewport=void 0),u.setupLightsView(H),We===!0&&ne.setGlobalState(E.clippingPlanes,H),Ci(v,B,H),Ue.updateMultisampleRenderTarget(Q),Ue.updateRenderTargetMipmap(Q),De.has("WEBGL_multisampled_render_to_texture")===!1){let Be=!1;for(let qe=0,it=L.length;qe0),ye=!!B.morphAttributes.position,Be=!!B.morphAttributes.normal,qe=!!B.morphAttributes.color;let it=pn;H.toneMapped&&(U===null||U.isXRRenderTarget===!0)&&(it=E.toneMapping);const je=B.morphAttributes.position||B.morphAttributes.normal||B.morphAttributes.color,$e=je!==void 0?je.length:0,Te=ge.get(H),tt=u.state.lights;if(We===!0&&(Y===!0||v!==M)){const gt=v===M&&H.id===S;ne.setState(H,v,gt)}let ke=!1;H.version===Te.__version?(Te.needsLights&&Te.lightsStateVersion!==tt.state.version||Te.outputColorSpace!==fe||I.isBatchedMesh&&Te.batching===!1||!I.isBatchedMesh&&Te.batching===!0||I.isBatchedMesh&&Te.batchingColor===!0&&I.colorTexture===null||I.isBatchedMesh&&Te.batchingColor===!1&&I.colorTexture!==null||I.isInstancedMesh&&Te.instancing===!1||!I.isInstancedMesh&&Te.instancing===!0||I.isSkinnedMesh&&Te.skinning===!1||!I.isSkinnedMesh&&Te.skinning===!0||I.isInstancedMesh&&Te.instancingColor===!0&&I.instanceColor===null||I.isInstancedMesh&&Te.instancingColor===!1&&I.instanceColor!==null||I.isInstancedMesh&&Te.instancingMorph===!0&&I.morphTexture===null||I.isInstancedMesh&&Te.instancingMorph===!1&&I.morphTexture!==null||Te.envMap!==ue||H.fog===!0&&Te.fog!==Q||Te.numClippingPlanes!==void 0&&(Te.numClippingPlanes!==ne.numPlanes||Te.numIntersection!==ne.numIntersection)||Te.vertexAlphas!==Ae||Te.vertexTangents!==Re||Te.morphTargets!==ye||Te.morphNormals!==Be||Te.morphColors!==qe||Te.toneMapping!==it||Te.morphTargetsCount!==$e)&&(ke=!0):(ke=!0,Te.__version=H.version);let yt=Te.currentProgram;ke===!0&&(yt=Pi(H,L,I));let Un=!1,Tt=!1,li=!1;const nt=yt.getUniforms(),Ct=Te.uniforms;if(me.useProgram(yt.program)&&(Un=!0,Tt=!0,li=!0),H.id!==S&&(S=H.id,Tt=!0),Un||M!==v){me.buffers.depth.getReversed()&&v.reversedDepth!==!0&&(v._reversedDepth=!0,v.updateProjectionMatrix()),nt.setValue(T,"projectionMatrix",v.projectionMatrix),nt.setValue(T,"viewMatrix",v.matrixWorldInverse);const Mt=nt.map.cameraPosition;Mt!==void 0&&Mt.setValue(T,de.setFromMatrixPosition(v.matrixWorld)),we.logarithmicDepthBuffer&&nt.setValue(T,"logDepthBufFC",2/(Math.log(v.far+1)/Math.LN2)),(H.isMeshPhongMaterial||H.isMeshToonMaterial||H.isMeshLambertMaterial||H.isMeshBasicMaterial||H.isMeshStandardMaterial||H.isShaderMaterial)&&nt.setValue(T,"isOrthographic",v.isOrthographicCamera===!0),M!==v&&(M=v,Tt=!0,li=!0)}if(I.isSkinnedMesh){nt.setOptional(T,I,"bindMatrix"),nt.setOptional(T,I,"bindMatrixInverse");const gt=I.skeleton;gt&&(gt.boneTexture===null&>.computeBoneTexture(),nt.setValue(T,"boneTexture",gt.boneTexture,Ue))}I.isBatchedMesh&&(nt.setOptional(T,I,"batchingTexture"),nt.setValue(T,"batchingTexture",I._matricesTexture,Ue),nt.setOptional(T,I,"batchingIdTexture"),nt.setValue(T,"batchingIdTexture",I._indirectTexture,Ue),nt.setOptional(T,I,"batchingColorTexture"),I._colorsTexture!==null&&nt.setValue(T,"batchingColorTexture",I._colorsTexture,Ue));const Pt=B.morphAttributes;if((Pt.position!==void 0||Pt.normal!==void 0||Pt.color!==void 0)&&ee.update(I,B,yt),(Tt||Te.receiveShadow!==I.receiveShadow)&&(Te.receiveShadow=I.receiveShadow,nt.setValue(T,"receiveShadow",I.receiveShadow)),H.isMeshGouraudMaterial&&H.envMap!==null&&(Ct.envMap.value=ue,Ct.flipEnvMap.value=ue.isCubeTexture&&ue.isRenderTargetTexture===!1?-1:1),H.isMeshStandardMaterial&&H.envMap===null&&L.environment!==null&&(Ct.envMapIntensity.value=L.environmentIntensity),Tt&&(nt.setValue(T,"toneMappingExposure",E.toneMappingExposure),Te.needsLights&&Fo(Ct,li),Q&&H.fog===!0&&K.refreshFogUniforms(Ct,Q),K.refreshMaterialUniforms(Ct,H,G,Z,u.state.transmissionRenderTarget[v.id]),ir.upload(T,Js(Te),Ct,Ue)),H.isShaderMaterial&&H.uniformsNeedUpdate===!0&&(ir.upload(T,Js(Te),Ct,Ue),H.uniformsNeedUpdate=!1),H.isSpriteMaterial&&nt.setValue(T,"center",I.center),nt.setValue(T,"modelViewMatrix",I.modelViewMatrix),nt.setValue(T,"normalMatrix",I.normalMatrix),nt.setValue(T,"modelMatrix",I.matrixWorld),H.isShaderMaterial||H.isRawShaderMaterial){const gt=H.uniformsGroups;for(let Mt=0,cr=gt.length;Mt0&&Ue.useMultisampledRTT(v)===!1?I=ge.get(v).__webglMultisampledFramebuffer:Array.isArray(Re)?I=Re[B]:I=Re,C.copy(v.viewport),O.copy(v.scissor),z=v.scissorTest}else C.copy(Ee).multiplyScalar(G).floor(),O.copy(Fe).multiplyScalar(G).floor(),z=Ke;if(B!==0&&(I=Bo),me.bindFramebuffer(T.FRAMEBUFFER,I)&&H&&me.drawBuffers(v,I),me.viewport(C),me.scissor(O),me.setScissorTest(z),Q){const ue=ge.get(v.texture);T.framebufferTexture2D(T.FRAMEBUFFER,T.COLOR_ATTACHMENT0,T.TEXTURE_CUBE_MAP_POSITIVE_X+L,ue.__webglTexture,B)}else if(oe){const ue=L;for(let Ae=0;Ae=0&&L<=v.width-H&&B>=0&&B<=v.height-I&&(v.textures.length>1&&T.readBuffer(T.COLOR_ATTACHMENT0+fe),T.readPixels(L,B,H,I,xe.convert(Re),xe.convert(ye),Q))}finally{const Ae=U!==null?ge.get(U).__webglFramebuffer:null;me.bindFramebuffer(T.FRAMEBUFFER,Ae)}}},this.readRenderTargetPixelsAsync=async function(v,L,B,H,I,Q,oe,fe=0){if(!(v&&v.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let ue=ge.get(v).__webglFramebuffer;if(v.isWebGLCubeRenderTarget&&oe!==void 0&&(ue=ue[oe]),ue)if(L>=0&&L<=v.width-H&&B>=0&&B<=v.height-I){me.bindFramebuffer(T.FRAMEBUFFER,ue);const Ae=v.textures[fe],Re=Ae.format,ye=Ae.type;if(!we.textureFormatReadable(Re))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!we.textureTypeReadable(ye))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");const Be=T.createBuffer();T.bindBuffer(T.PIXEL_PACK_BUFFER,Be),T.bufferData(T.PIXEL_PACK_BUFFER,Q.byteLength,T.STREAM_READ),v.textures.length>1&&T.readBuffer(T.COLOR_ATTACHMENT0+fe),T.readPixels(L,B,H,I,xe.convert(Re),xe.convert(ye),0);const qe=U!==null?ge.get(U).__webglFramebuffer:null;me.bindFramebuffer(T.FRAMEBUFFER,qe);const it=T.fenceSync(T.SYNC_GPU_COMMANDS_COMPLETE,0);return T.flush(),await Pl(T,it,4),T.bindBuffer(T.PIXEL_PACK_BUFFER,Be),T.getBufferSubData(T.PIXEL_PACK_BUFFER,0,Q),T.deleteBuffer(Be),T.deleteSync(it),Q}else throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")},this.copyFramebufferToTexture=function(v,L=null,B=0){const H=Math.pow(2,-B),I=Math.floor(v.image.width*H),Q=Math.floor(v.image.height*H),oe=L!==null?L.x:0,fe=L!==null?L.y:0;Ue.setTexture2D(v,0),T.copyTexSubImage2D(T.TEXTURE_2D,B,0,0,oe,fe,I,Q),me.unbindTexture()};const Ho=T.createFramebuffer(),zo=T.createFramebuffer();this.copyTextureToTexture=function(v,L,B=null,H=null,I=0,Q=null){Q===null&&(I!==0?(Ei("WebGLRenderer: copyTextureToTexture function signature has changed to support src and dst mipmap levels."),Q=I,I=0):Q=0);let oe,fe,ue,Ae,Re,ye,Be,qe,it;const je=v.isCompressedTexture?v.mipmaps[Q]:v.image;if(B!==null)oe=B.max.x-B.min.x,fe=B.max.y-B.min.y,ue=B.isBox3?B.max.z-B.min.z:1,Ae=B.min.x,Re=B.min.y,ye=B.isBox3?B.min.z:0;else{const Pt=Math.pow(2,-I);oe=Math.floor(je.width*Pt),fe=Math.floor(je.height*Pt),v.isDataArrayTexture?ue=je.depth:v.isData3DTexture?ue=Math.floor(je.depth*Pt):ue=1,Ae=0,Re=0,ye=0}H!==null?(Be=H.x,qe=H.y,it=H.z):(Be=0,qe=0,it=0);const $e=xe.convert(L.format),Te=xe.convert(L.type);let tt;L.isData3DTexture?(Ue.setTexture3D(L,0),tt=T.TEXTURE_3D):L.isDataArrayTexture||L.isCompressedArrayTexture?(Ue.setTexture2DArray(L,0),tt=T.TEXTURE_2D_ARRAY):(Ue.setTexture2D(L,0),tt=T.TEXTURE_2D),T.pixelStorei(T.UNPACK_FLIP_Y_WEBGL,L.flipY),T.pixelStorei(T.UNPACK_PREMULTIPLY_ALPHA_WEBGL,L.premultiplyAlpha),T.pixelStorei(T.UNPACK_ALIGNMENT,L.unpackAlignment);const ke=T.getParameter(T.UNPACK_ROW_LENGTH),yt=T.getParameter(T.UNPACK_IMAGE_HEIGHT),Un=T.getParameter(T.UNPACK_SKIP_PIXELS),Tt=T.getParameter(T.UNPACK_SKIP_ROWS),li=T.getParameter(T.UNPACK_SKIP_IMAGES);T.pixelStorei(T.UNPACK_ROW_LENGTH,je.width),T.pixelStorei(T.UNPACK_IMAGE_HEIGHT,je.height),T.pixelStorei(T.UNPACK_SKIP_PIXELS,Ae),T.pixelStorei(T.UNPACK_SKIP_ROWS,Re),T.pixelStorei(T.UNPACK_SKIP_IMAGES,ye);const nt=v.isDataArrayTexture||v.isData3DTexture,Ct=L.isDataArrayTexture||L.isData3DTexture;if(v.isDepthTexture){const Pt=ge.get(v),gt=ge.get(L),Mt=ge.get(Pt.__renderTarget),cr=ge.get(gt.__renderTarget);me.bindFramebuffer(T.READ_FRAMEBUFFER,Mt.__webglFramebuffer),me.bindFramebuffer(T.DRAW_FRAMEBUFFER,cr.__webglFramebuffer);for(let vn=0;vn(i[i.None=0]="None",i[i.Left=1]="Left",i[i.Right=2]="Right",i[i.Across=3]="Across",i))(mi||{}),gi=(i=>(i[i.Clubs=0]="Clubs",i[i.Diamonds=1]="Diamonds",i[i.Hearts=2]="Hearts",i[i.Spades=3]="Spades",i))(gi||{});class Uo{static atlas=null;static async load(){if(this.atlas)return this.atlas;const e=await fetch("/card_atlas.json");return this.atlas=await e.json(),this.atlas}static getCardKey(e,t){let n;if(typeof t=="string")n=t.toLowerCase();else switch(t){case gi.Clubs:n="clubs";break;case gi.Diamonds:n="diamonds";break;case gi.Hearts:n="hearts";break;case gi.Spades:n="spades";break;default:n="hearts";break}let r;switch(e){case 1:r="A";break;case 11:r="J";break;case 12:r="Q";break;case 13:r="K";break;default:r=e.toString();break}return`${n}_${r}`}static getCardFrame(e,t){if(!this.atlas)return console.error("Card atlas not loaded yet. Call CardAtlasLoader.load() first."),null;const n=this.getCardKey(e,t),r=this.atlas.frames[n];return r||console.error(`Card frame not found for key: ${n}, rank: ${e}, suit: ${t}`),r||null}static calculateUVs(e,t){const n=this.getCardFrame(e,t);if(!n||!this.atlas)return null;const r=this.atlas.size.w,s=this.atlas.size.h,a=n.x/r,o=(n.x+n.w)/r,c=1-(n.y+n.h)/s,l=1-n.y/s;return{uMin:a,uMax:o,vMin:c,vMax:l}}}class tn{mesh;card;cardGeometry;cardMaterial;isHovered=!1;isSelected=!1;static cardTexture=null;static textureLoader=new wo;constructor(e,t){this.card=e,this.mesh=new Zn,this.mesh.position.copy(t),this.cardGeometry=new ai(1.2,1.7),tn.cardTexture||(tn.cardTexture=tn.textureLoader.load("/cards.png"),tn.cardTexture.minFilter=Ut,tn.cardTexture.magFilter=Ut);const n=this.calculateUVs(),r=this.cardGeometry.attributes.uv,s=r.array;s[0]=n.uMin,s[1]=n.vMax,s[2]=n.uMax,s[3]=n.vMax,s[4]=n.uMin,s[5]=n.vMin,s[6]=n.uMax,s[7]=n.vMin,r.needsUpdate=!0,this.cardMaterial=new nr({map:tn.cardTexture,side:Bt,transparent:!1});const a=new wt(this.cardGeometry,this.cardMaterial);this.mesh.add(a),this.mesh.userData={card:this}}calculateUVs(){const e=Uo.calculateUVs(this.card.rank,this.card.suit);return e||(console.warn(`Could not find UV coordinates for card: rank=${this.card.rank}, suit=${this.card.suit}`),{uMin:0,uMax:1,vMin:0,vMax:1})}setHovered(e){this.isHovered!==e&&(this.isHovered=e,e&&!this.isSelected?(this.mesh.position.y+=.2,this.cardMaterial.emissive=new Oe(4473924)):this.isSelected||(this.mesh.position.y-=.2,this.cardMaterial.emissive=new Oe(0)))}setSelected(e){this.isSelected=e,e?(this.mesh.position.y=.4,this.cardMaterial.emissive=new Oe(8947848)):(this.mesh.position.y=.1,this.cardMaterial.emissive=new Oe(0))}animateToPosition(e,t=500){return new Promise(n=>{const r=this.mesh.position.clone(),s=Date.now(),a=()=>{const o=Date.now()-s,c=Math.min(o/t,1),l=c<.5?2*c*c:1-Math.pow(-2*c+2,2)/2;this.mesh.position.lerpVectors(r,e,l),c<1?requestAnimationFrame(a):n()};a()})}dispose(){this.cardGeometry.dispose(),this.cardMaterial.dispose()}}class vt{scene;camera;renderer;raycaster;mouse;playerCards=[];currentTrickCards=[];hoveredCard=null;selectedCards=[];opponentCards={};static bgTexture=null;static textureLoader=new wo;isAtlasLoaded=!1;onCardClick;constructor(e){this.scene=new tc,this.scene.background=new Oe(1722154),this.camera=new It(60,window.innerWidth/window.innerHeight,.1,1e3),this.camera.position.set(0,8,10),this.camera.lookAt(0,0,-2),this.renderer=new ep({antialias:!0}),this.renderer.setSize(window.innerWidth,window.innerHeight),this.renderer.shadowMap.enabled=!0,e.appendChild(this.renderer.domElement),this.raycaster=new gc,this.mouse=new Ge,this.setupLights(),this.createTable(),this.loadCardAtlas(),window.addEventListener("resize",this.onWindowResize.bind(this)),this.renderer.domElement.addEventListener("mousemove",this.onMouseMove.bind(this)),this.renderer.domElement.addEventListener("click",this.onClick.bind(this)),this.animate()}async loadCardAtlas(){try{await Uo.load(),this.isAtlasLoaded=!0,console.log("Card atlas loaded successfully")}catch(e){console.error("Failed to load card atlas:",e)}}setupLights(){const e=new pc(16777215,.6);this.scene.add(e);const t=new fc(16777215,.8);t.position.set(5,10,5),t.castShadow=!0,this.scene.add(t);const n=new uc(16777215,4473924,.4);this.scene.add(n)}createTable(){vt.bgTexture||(vt.bgTexture=vt.textureLoader.load("/bg.png"),vt.bgTexture.wrapS=Cn,vt.bgTexture.wrapT=Cn,vt.bgTexture.repeat.set(2,2));const e=new Vs(8,8,.2,32),t=new nr({map:vt.bgTexture,roughness:.8,metalness:.1}),n=new wt(e,t);n.position.y=-.5,n.receiveShadow=!0,this.scene.add(n);const r=new Ws(8,.15,16,32),s=new nr({color:9127187}),a=new wt(r,s);a.rotation.x=Math.PI/2,a.position.y=-.4,this.scene.add(a)}addPlayerCards(e){this.clearPlayerCards();const t=[...e].sort((o,c)=>{const l=f=>{if(typeof f=="string")switch(f){case"Clubs":return 0;case"Diamonds":return 1;case"Hearts":return 2;case"Spades":return 3;default:return 0}return f},h=l(o.suit),d=l(c.suit);return h!==d?h-d:o.rank-c.rank}),n=t.length,r=1.3,s=5,a=.1;t.forEach((o,c)=>{const h=-(n-1)*r/2+c*r,d=new F(h,a,s),f=new tn(o,d);f.mesh.rotation.x=-Math.PI/2,f.mesh.rotation.z=0,f.mesh.renderOrder=c,this.playerCards.push(f),this.scene.add(f.mesh)})}updateOpponentCards(e,t,n){this.opponentCards[e]&&(this.scene.remove(this.opponentCards[e]),this.opponentCards[e].clear());const r=new Zn;this.opponentCards[e]=r;const a=[{x:-7,z:0,baseRotation:Math.PI/2},{x:0,z:-7,baseRotation:Math.PI},{x:7,z:0,baseRotation:-Math.PI/2}][n%3];vt.bgTexture||(vt.bgTexture=vt.textureLoader.load("/bg.png"),vt.bgTexture.wrapS=Cn,vt.bgTexture.wrapT=Cn);const o=t,c=Math.PI/4,l=5;for(let h=0;h1?-c/2+h/(o-1)*c:0,x=l*Math.sin(_),p=-l*Math.cos(_)+l;a.x!==0?(m.position.set(a.x+p*.3,.5,x),m.rotation.y=a.baseRotation+_):(m.position.set(x,.5,a.z-p*.3),m.rotation.y=a.baseRotation+_),m.rotation.x=-Math.PI/15,m.renderOrder=h,r.add(m)}this.scene.add(r)}addTrickCard(e,t){const r=[new F(0,0,2),new F(-2,0,0),new F(0,0,-2),new F(2,0,0)][t%4],s=new tn(e,r);this.currentTrickCards.push(s),this.scene.add(s.mesh)}clearTrick(){this.currentTrickCards.forEach(e=>{this.scene.remove(e.mesh),e.dispose()}),this.currentTrickCards=[]}clearPlayerCards(){this.playerCards.forEach(e=>{this.scene.remove(e.mesh),e.dispose()}),this.playerCards=[],this.selectedCards=[]}clearOpponentCards(){Object.keys(this.opponentCards).forEach(e=>{this.scene.remove(this.opponentCards[e]),this.opponentCards[e].clear()}),this.opponentCards={}}removePlayerCard(e){const t=this.playerCards.findIndex(n=>n.card.rank===e.rank&&n.card.suit===e.suit);if(t!==-1){const n=this.playerCards[t];this.scene.remove(n.mesh),n.dispose(),this.playerCards.splice(t,1),this.rearrangePlayerCards()}}rearrangePlayerCards(){const e=this.playerCards.length,t=1.3,n=5;this.playerCards.forEach((r,s)=>{const o=-(e-1)*t/2+s*t,c=new F(o,r.mesh.position.y,n);r.animateToPosition(c,300),setTimeout(()=>{r.mesh.rotation.x=-Math.PI/2,r.mesh.rotation.z=0,r.mesh.renderOrder=s},150)})}getSelectedCards(){return this.selectedCards}clearSelection(){this.selectedCards.forEach(e=>e.setSelected(!1)),this.selectedCards=[]}onMouseMove(e){this.mouse.x=e.clientX/window.innerWidth*2-1,this.mouse.y=-(e.clientY/window.innerHeight)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);const t=this.playerCards.map(r=>r.mesh),n=this.raycaster.intersectObjects(t,!0);if(n.length>0){const s=n[0].object.parent?.userData.card;s&&s!==this.hoveredCard&&(this.hoveredCard&&this.hoveredCard.setHovered(!1),this.hoveredCard=s,this.hoveredCard.setHovered(!0))}else this.hoveredCard&&(this.hoveredCard.setHovered(!1),this.hoveredCard=null)}onClick(e){this.mouse.x=e.clientX/window.innerWidth*2-1,this.mouse.y=-(e.clientY/window.innerHeight)*2+1,this.raycaster.setFromCamera(this.mouse,this.camera);const t=this.playerCards.map(r=>r.mesh),n=this.raycaster.intersectObjects(t,!0);if(n.length>0){const s=n[0].object.parent?.userData.card;s&&(this.handleCardSelection(s),this.onCardClick&&this.onCardClick(s))}}handleCardSelection(e){const t=this.selectedCards.indexOf(e);t!==-1?(this.selectedCards.splice(t,1),e.setSelected(!1)):this.selectedCards.length<3&&(this.selectedCards.push(e),e.setSelected(!0))}onWindowResize(){this.camera.aspect=window.innerWidth/window.innerHeight,this.camera.updateProjectionMatrix(),this.renderer.setSize(window.innerWidth,window.innerHeight)}animate(){requestAnimationFrame(this.animate.bind(this)),this.renderer.render(this.scene,this.camera)}dispose(){window.removeEventListener("resize",this.onWindowResize.bind(this)),this.renderer.domElement.removeEventListener("mousemove",this.onMouseMove.bind(this)),this.renderer.domElement.removeEventListener("click",this.onClick.bind(this)),this.renderer.dispose()}}class tp{connectionPanel;gameInfo;messageDisplay;statusElement;roundNumberEl;playerScoreEl;totalScoreEl;passDirectionEl;turnStatusEl;connectionStatusEl;constructor(){this.connectionPanel=document.getElementById("connection-panel"),this.gameInfo=document.getElementById("game-info"),this.messageDisplay=document.getElementById("message-display"),this.statusElement=document.getElementById("status"),this.roundNumberEl=document.getElementById("round-number"),this.playerScoreEl=document.getElementById("player-score"),this.totalScoreEl=document.getElementById("total-score"),this.passDirectionEl=document.getElementById("pass-direction"),this.turnStatusEl=document.getElementById("turn-status"),this.connectionStatusEl=document.getElementById("connection-status")}showConnectionPanel(){this.connectionPanel.classList.remove("hidden"),this.gameInfo.classList.add("hidden")}hideConnectionPanel(){this.connectionPanel.classList.add("hidden"),this.gameInfo.classList.remove("hidden")}setConnectionStatus(e){this.connectionStatusEl.textContent=e}updateGameInfo(e){e.roundNumber!==void 0&&(this.roundNumberEl.textContent=e.roundNumber.toString()),e.playerScore!==void 0&&(this.playerScoreEl.textContent=e.playerScore.toString()),e.totalScore!==void 0&&(this.totalScoreEl.textContent=e.totalScore.toString()),e.passDirection!==void 0&&(this.passDirectionEl.textContent=`Pass: ${e.passDirection}`),e.isMyTurn!==void 0&&(this.turnStatusEl.textContent=e.isMyTurn?"Your turn!":"Waiting...",this.turnStatusEl.style.color=e.isMyTurn?"#4caf50":"#666")}setStatus(e){this.statusElement.textContent=e}showMessage(e,t=3e3){this.messageDisplay.textContent=e,this.messageDisplay.classList.add("show"),setTimeout(()=>{this.messageDisplay.classList.remove("show")},t)}getConnectionInputs(){return{playerName:document.getElementById("player-name").value,gameId:document.getElementById("game-id").value}}setConnectButtonEnabled(e){const t=document.getElementById("connect-btn");t.disabled=!e}}class np{constructor(e,t){this.actionSocket=e,this.notificationSocket=t,this.gameStartedHandlers=[],this.passingPhaseStartedHandlers=[],this.allPlayersPassedHandlers=[],this.playerPassedCardsHandlers=[],this.itsYourTurnHandlers=[],this.itsPlayersTurnHandlers=[],this.playerPlayedCardHandlers=[],this.trickCompletedHandlers=[],this.roundEndedHandlers=[],this.gameEndedHandlers=[],this.heartsWereBrokenHandlers=[],this.setupNotificationHandlers()}setupNotificationHandlers(){this.notificationSocket.onmessage=e=>{const t=JSON.parse(e.data);this.handleNotification(t)}}handleNotification(e){switch(e.type){case"Hearts.GameStartedNotification":this.gameStartedHandlers.forEach(t=>t(e));break;case"Hearts.PassingPhaseStartedNotification":this.passingPhaseStartedHandlers.forEach(t=>t(e));break;case"Hearts.AllPlayersPassedNotification":this.allPlayersPassedHandlers.forEach(t=>t(e));break;case"Hearts.PlayerPassedCardsNotification":this.playerPassedCardsHandlers.forEach(t=>t(e));break;case"Hearts.ItsYourTurnNotification":this.itsYourTurnHandlers.forEach(t=>t(e));break;case"Hearts.ItsPlayersTurnNotification":this.itsPlayersTurnHandlers.forEach(t=>t(e));break;case"Hearts.PlayerPlayedCardNotification":this.playerPlayedCardHandlers.forEach(t=>t(e));break;case"Hearts.TrickCompletedNotification":this.trickCompletedHandlers.forEach(t=>t(e));break;case"Hearts.RoundEndedNotification":this.roundEndedHandlers.forEach(t=>t(e));break;case"Hearts.GameEndedNotification":this.gameEndedHandlers.forEach(t=>t(e));break;case"Hearts.HeartsAreBrokenNotification":this.heartsWereBrokenHandlers.forEach(t=>t(e));break}}onGameStarted(e){this.gameStartedHandlers.push(e)}offGameStarted(e){const t=this.gameStartedHandlers.indexOf(e);t>-1&&this.gameStartedHandlers.splice(t,1)}onPassingPhaseStarted(e){this.passingPhaseStartedHandlers.push(e)}offPassingPhaseStarted(e){const t=this.passingPhaseStartedHandlers.indexOf(e);t>-1&&this.passingPhaseStartedHandlers.splice(t,1)}onAllPlayersPassed(e){this.allPlayersPassedHandlers.push(e)}offAllPlayersPassed(e){const t=this.allPlayersPassedHandlers.indexOf(e);t>-1&&this.allPlayersPassedHandlers.splice(t,1)}onPlayerPassedCards(e){this.playerPassedCardsHandlers.push(e)}offPlayerPassedCards(e){const t=this.playerPassedCardsHandlers.indexOf(e);t>-1&&this.playerPassedCardsHandlers.splice(t,1)}onItsYourTurn(e){this.itsYourTurnHandlers.push(e)}offItsYourTurn(e){const t=this.itsYourTurnHandlers.indexOf(e);t>-1&&this.itsYourTurnHandlers.splice(t,1)}onItsPlayersTurn(e){this.itsPlayersTurnHandlers.push(e)}offItsPlayersTurn(e){const t=this.itsPlayersTurnHandlers.indexOf(e);t>-1&&this.itsPlayersTurnHandlers.splice(t,1)}onPlayerPlayedCard(e){this.playerPlayedCardHandlers.push(e)}offPlayerPlayedCard(e){const t=this.playerPlayedCardHandlers.indexOf(e);t>-1&&this.playerPlayedCardHandlers.splice(t,1)}onTrickCompleted(e){this.trickCompletedHandlers.push(e)}offTrickCompleted(e){const t=this.trickCompletedHandlers.indexOf(e);t>-1&&this.trickCompletedHandlers.splice(t,1)}onRoundEnded(e){this.roundEndedHandlers.push(e)}offRoundEnded(e){const t=this.roundEndedHandlers.indexOf(e);t>-1&&this.roundEndedHandlers.splice(t,1)}onGameEnded(e){this.gameEndedHandlers.push(e)}offGameEnded(e){const t=this.gameEndedHandlers.indexOf(e);t>-1&&this.gameEndedHandlers.splice(t,1)}onHeartsWereBroken(e){this.heartsWereBrokenHandlers.push(e)}offHeartsWereBroken(e){const t=this.heartsWereBrokenHandlers.indexOf(e);t>-1&&this.heartsWereBrokenHandlers.splice(t,1)}async passCards(e){return new Promise((t,n)=>{const r={...e,type:"Hearts.PassCardsRequest"},s=a=>{const o=JSON.parse(a.data);o.hasError?n(new Error(o.error||"Unknown error")):t(o),this.actionSocket.removeEventListener("message",s)};this.actionSocket.addEventListener("message",s),this.actionSocket.send(JSON.stringify(r))})}async playCard(e){return new Promise((t,n)=>{const r={...e,type:"Hearts.PlayCardRequest"},s=a=>{const o=JSON.parse(a.data);o.hasError?n(new Error(o.error||"Unknown error")):t(o),this.actionSocket.removeEventListener("message",s)};this.actionSocket.addEventListener("message",s),this.actionSocket.send(JSON.stringify(r))})}}class ip{client;scene;ui;playerId="";passingPhase=!1;myTurn=!1;constructor(e,t){this.scene=e,this.ui=t,this.scene.onCardClick=this.handleCardClick.bind(this)}async createGame(e,t){try{console.log("Creating new game...");const n=e.replace("ws://","http://").replace("wss://","https://");console.log("Authenticating with:",n+"/login");const r=await fetch(`${n}/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:t,password:"default-password"}),credentials:"include"});if(console.log("Login response status:",r.status),!r.ok){const o=await r.text();throw console.error("Login failed:",o),new Error(`Authentication failed: ${r.status} ${r.statusText}`)}await r.json(),console.log("Authenticated successfully"),console.log("Creating Hearts game...");const s=await fetch(`${n}/hearts/create`,{method:"POST",credentials:"include"});if(!s.ok){const o=await s.text();throw new Error(`Failed to create game: ${s.status} ${s.statusText} +${o}`)}const a=await s.json();return console.log("Game created:",a),a.id}catch(n){throw console.error("Error creating game:",n),n}}async connect(e,t,n,r){try{console.log("Starting connection process..."),this.ui.setConnectionStatus("Authenticating..."),this.ui.setConnectButtonEnabled(!1);const s=e.replace("ws://","http://").replace("wss://","https://");console.log("Authenticating with:",s+"/login");const a=await fetch(`${s}/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:n,password:"default-password"}),credentials:"include"});if(console.log("Login response status:",a.status),!a.ok){const _=await a.text();throw console.error("Login failed:",_),new Error(`Authentication failed: ${a.status} ${a.statusText} +${_}`)}const o=await a.json();console.log("Authenticated successfully:",o);const c=o.accessToken;this.playerId=o.id,console.log("Using player ID from auth:",this.playerId),this.ui.setConnectionStatus("Authenticated. Connecting to game..."),console.log("Attempting to connect to game:",r);const l=`${e}/hearts/join/${encodeURIComponent(r)}`;console.log("Connecting action socket to:",l);const h=new WebSocket(l);await this.waitForSocketOpen(h),console.log("Action socket connected"),this.ui.setConnectionStatus("Action socket connected. Waiting for connection ID..."),console.log("Waiting for connection ID...");const d=await this.getConnectionId(h);console.log("Received connection ID:",d),this.ui.setConnectionStatus("Establishing notification socket...");const f=`${e}/hearts/join/${d}/finish`;console.log("Connecting notification socket to:",f);const m=new WebSocket(f);await this.waitForSocketOpen(m),console.log("Notification socket connected"),this.ui.setConnectionStatus("Connected!"),console.log("Setting up notification socket logging..."),m.addEventListener("message",_=>{console.log("📨 RAW notification received:",_.data)}),console.log("Creating Hearts client..."),this.client=new np(h,m),console.log("Hearts client created"),console.log("Setting up event handlers..."),this.setupEventHandlers(),console.log("Event handlers set up"),console.log("Hiding connection panel and showing game UI..."),this.ui.hideConnectionPanel(),this.ui.setStatus("Connected to game. Waiting for game to start..."),this.ui.showMessage("Connected to Hearts game!"),console.log("Connection complete. Waiting for game events...")}catch(s){console.error("Connection error:",s);const a=s instanceof Error?s.message:String(s);throw this.ui.setConnectionStatus(`Connection failed: ${a}`),this.ui.showMessage(`Connection failed: ${a}`,1e4),this.ui.setConnectButtonEnabled(!0),s}}getConnectionId(e){return new Promise((t,n)=>{const r=setTimeout(()=>{n(new Error("Timeout waiting for connection ID (10 seconds). The game may not exist or you may not have permission to join."))},1e4),s=a=>{console.log("Received message while waiting for connection ID:",a.data),clearTimeout(r);try{const o=JSON.parse(a.data);if(console.log("Parsed data:",o),o.ConnectionId||o.connectionId){const c=o.ConnectionId||o.connectionId;e.removeEventListener("message",s),console.log("Extracted connection ID:",c),t(c)}else if(o.ErrorMessage||o.errorMessage){const c=o.ErrorMessage||o.errorMessage;console.error("Server error:",c),n(new Error("Server error: "+c))}else console.error("Message does not contain ConnectionId:",o),n(new Error("No ConnectionId in response. Received: "+JSON.stringify(o)))}catch(o){console.error("Failed to parse message:",o,"Raw data:",a.data),n(new Error("Failed to parse connection ID response: "+a.data))}};e.addEventListener("message",s)})}waitForSocketOpen(e){return new Promise((t,n)=>{const r=setTimeout(()=>{n(new Error("Connection timeout - server not responding"))},1e4);e.onopen=()=>{clearTimeout(r),t()},e.onerror=s=>{clearTimeout(r),console.error("WebSocket error:",s),console.error("Socket URL:",e.url),console.error("Socket readyState:",e.readyState),n(new Error(`WebSocket connection failed. Make sure: 1. Server is running on localhost:13992 2. Game ID exists on server -3. Check server logs for errors`))},e.onclose=s=>{s.wasClean||(clearTimeout(r),n(new Error(`Connection closed unexpectedly (code: ${s.code}, reason: ${s.reason||"none"})`)))}})}setupEventHandlers(){this.client&&(this.client.onGameStarted(e=>{console.log("Game started:",e),this.ui.showMessage("Game started!"),this.ui.setStatus("Game in progress"),e.playerViewOfGame&&this.updateGameState(e.playerViewOfGame)}),this.client.onPassingPhaseStarted(e=>{console.log("Passing phase started:",e),this.passingPhase=!0;const t=this.getPassDirectionString(e.passDirection);this.ui.showMessage(`Pass 3 cards ${t}`),this.ui.setStatus(`Select 3 cards to pass ${t}`),this.ui.updateGameInfo({passDirection:t})}),this.client.onAllPlayersPassed(e=>{console.log("All players passed:",e),this.passingPhase=!1,this.scene.clearSelection(),e.receivedCards&&e.receivedCards.length>0&&this.ui.showMessage(`Received ${e.receivedCards.length} cards`),this.ui.setStatus("Cards passed. Waiting for round to start...")}),this.client.onPlayerPassedCards(e=>{console.log("Player passed cards:",e)}),this.client.onItsYourTurn(e=>{console.log("Your turn:",e),this.myTurn=!0,this.ui.showMessage("Your turn!"),this.ui.setStatus("Your turn - select a card to play"),this.ui.updateGameInfo({isMyTurn:!0}),e.playerViewOfGame&&this.updateGameState(e.playerViewOfGame)}),this.client.onItsPlayersTurn(e=>{console.log("It's another player's turn:",e),this.myTurn=!1,this.ui.updateGameInfo({isMyTurn:!1}),this.ui.setStatus("Waiting for other players...")}),this.client.onPlayerPlayedCard(e=>{console.log("Player played card:",e),this.scene.addTrickCard(e.card,0)}),this.client.onTrickCompleted(e=>{console.log("Trick completed:",e),this.ui.showMessage(`${e.winnerName||"Player"} won the trick! (+${e.points} points)`),setTimeout(()=>{this.scene.clearTrick()},2e3)}),this.client.onRoundEnded(e=>{console.log("Round ended:",e);let t="Round ended!";e.moonShooterName&&(t=`${e.moonShooterName} shot the moon!`),this.ui.showMessage(t,5e3),this.ui.setStatus("Round ended. Waiting for next round..."),e.scores&&console.log("Scores:",e.scores)}),this.client.onGameEnded(e=>{console.log("Game ended:",e),this.ui.showMessage(`Game Over! Winner: ${e.winnerName||"Unknown"}`,1e4),this.ui.setStatus("Game ended")}),this.client.onHeartsWereBroken(()=>{console.log("Hearts were broken"),this.ui.showMessage("Hearts have been broken!")}))}updateGameState(e){console.log("Updating game state:",e),this.ui.updateGameInfo({roundNumber:e.roundNumber,playerScore:e.roundScore,totalScore:e.totalScore,isMyTurn:e.isMyTurn}),e.cards&&this.scene.addPlayerCards(e.cards),e.currentTrick&&(this.scene.clearTrick(),e.currentTrick.forEach((t,n)=>{this.scene.addTrickCard(t.card,n)}))}getPassDirectionString(e){switch(e){case fi.Left:return"Left";case fi.Right:return"Right";case fi.Across:return"Across";case fi.None:return"None";default:return"Unknown"}}async handleCardClick(e){if(this.passingPhase){const t=this.scene.getSelectedCards();t.length===3&&(this.ui.setStatus("Passing cards..."),await this.passCards(t.map(n=>n.card)))}else this.myTurn&&(this.ui.setStatus("Playing card..."),await this.playCard(e.card))}async passCards(e){if(this.client)try{const t=await this.client.passCards({playerId:this.playerId,cards:e});console.log("Pass cards response:",t),t.hasError?(this.ui.showMessage(`Error: ${t.error}`),this.scene.clearSelection()):(this.ui.showMessage("Cards passed!"),this.ui.setStatus("Waiting for other players to pass..."),e.forEach(n=>this.scene.removePlayerCard(n)),this.scene.clearSelection())}catch(t){console.error("Error passing cards:",t),this.ui.showMessage("Failed to pass cards"),this.scene.clearSelection()}}async playCard(e){if(this.client)try{const t=await this.client.playCard({playerId:this.playerId,card:e});console.log("Play card response:",t),t.hasError?this.ui.showMessage(`Error: ${t.error}`):(this.myTurn=!1,this.scene.removePlayerCard(e),this.scene.addTrickCard(e,0),this.ui.setStatus("Waiting for other players..."),this.updateGameState(t))}catch(t){console.error("Error playing card:",t),this.ui.showMessage("Failed to play card")}}}function pp(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,i=>{const e=Math.random()*16|0;return(i==="x"?e:e&3|8).toString(16)})}function fo(){console.log("Initializing Hearts Web Client...");const i=document.getElementById("canvas-container");if(!i){console.error("Canvas container not found!");return}const e=new up(i);console.log("3D scene initialized");const t=new hp;console.log("UI initialized");const n=new fp(e,t);console.log("Game controller initialized");const r=document.getElementById("connect-btn");r&&r.addEventListener("click",async()=>{const s=t.getConnectionInputs(),a=s.playerName.trim(),o=s.gameId.trim();if(!a||!o){t.setConnectionStatus("Please fill in all fields");return}const l=pp(),c="ws://localhost:13992";console.log("Connection details:"),console.log("- Server URL:",c),console.log("- Player ID:",l),console.log("- Player Name:",a),console.log("- Game ID:",o);try{await n.connect(c,l,a,o)}catch(d){console.error("Failed to connect:",d)}}),console.log("Hearts Web Client ready!")}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",fo):fo(); +3. Check server logs for errors`))},e.onclose=s=>{s.wasClean||(clearTimeout(r),n(new Error(`Connection closed unexpectedly (code: ${s.code}, reason: ${s.reason||"none"})`)))}})}setupEventHandlers(){if(!this.client){console.error("Cannot setup event handlers: client is null");return}console.log("Registering GameStarted handler..."),this.client.onGameStarted(e=>{console.log("🎮 Game started event received!",e),this.ui.showMessage("Game started!"),this.ui.setStatus("Game in progress"),e.playerViewOfGame&&this.updateGameState(e.playerViewOfGame)}),console.log("Registering PassingPhaseStarted handler..."),this.client.onPassingPhaseStarted(e=>{console.log("🎴 Passing phase started event received!",e),this.passingPhase=!0;const t=this.getPassDirectionString(e.passDirection);this.ui.showMessage(`Pass 3 cards ${t}`),this.ui.setStatus(`Select 3 cards to pass ${t}`),this.ui.updateGameInfo({passDirection:t})}),this.client.onAllPlayersPassed(e=>{console.log("All players passed:",e),this.passingPhase=!1,this.scene.clearSelection(),e.receivedCards&&e.receivedCards.length>0&&this.ui.showMessage(`Received ${e.receivedCards.length} cards`),this.ui.setStatus("Cards passed. Waiting for round to start...")}),this.client.onPlayerPassedCards(e=>{console.log("Player passed cards:",e)}),console.log("Registering ItsYourTurn handler..."),this.client.onItsYourTurn(e=>{console.log("✋ Your turn event received!",e),this.myTurn=!0,this.ui.showMessage("Your turn!"),this.ui.setStatus("Your turn - select a card to play"),this.ui.updateGameInfo({isMyTurn:!0}),e.playerViewOfGame&&this.updateGameState(e.playerViewOfGame)}),this.client.onItsPlayersTurn(e=>{console.log("It's another player's turn:",e),console.log("My player ID:",this.playerId),console.log("Turn player ID:",e.playerId),e.playerId!==this.playerId?(this.myTurn=!1,this.ui.updateGameInfo({isMyTurn:!1}),this.ui.setStatus("Waiting for other players...")):console.log("Received ItsPlayersTurn for my own ID - this might be a server notification about me playing")}),this.client.onPlayerPlayedCard(e=>{console.log("Player played card:",e),this.scene.addTrickCard(e.card,1)}),this.client.onTrickCompleted(e=>{console.log("Trick completed:",e),this.ui.showMessage(`${e.winnerName||"Player"} won the trick! (+${e.points} points)`),setTimeout(()=>{this.scene.clearTrick()},2e3)}),this.client.onRoundEnded(e=>{console.log("Round ended:",e);let t="Round ended!";e.moonShooterName&&(t=`${e.moonShooterName} shot the moon!`),this.ui.showMessage(t,5e3),this.ui.setStatus("Round ended. Waiting for next round..."),e.scores&&console.log("Scores:",e.scores)}),this.client.onGameEnded(e=>{console.log("Game ended:",e),this.ui.showMessage(`Game Over! Winner: ${e.winnerName||"Unknown"}`,1e4),this.ui.setStatus("Game ended")}),this.client.onHeartsWereBroken(()=>{console.log("Hearts were broken"),this.ui.showMessage("Hearts have been broken!")})}updateGameState(e){console.log("Updating game state:",e),this.ui.updateGameInfo({roundNumber:e.roundNumber,playerScore:e.roundScore,totalScore:e.totalScore,isMyTurn:e.isMyTurn}),e.cards&&this.scene.addPlayerCards(e.cards),e.otherPlayers&&e.otherPlayers.forEach((t,n)=>{this.scene.updateOpponentCards(t.playerId,t.numberOfCards,n)}),e.currentTrick&&(this.scene.clearTrick(),e.currentTrick.forEach((t,n)=>{this.scene.addTrickCard(t.card,n)}))}getPassDirectionString(e){switch(e){case mi.Left:return"Left";case mi.Right:return"Right";case mi.Across:return"Across";case mi.None:return"None";default:return"Unknown"}}async handleCardClick(e){if(console.log("Card clicked:",e.card),console.log("Passing phase:",this.passingPhase),console.log("My turn:",this.myTurn),this.passingPhase){const t=this.scene.getSelectedCards();t.length===3&&(this.ui.setStatus("Passing cards..."),await this.passCards(t.map(n=>n.card)))}else this.myTurn?(this.ui.setStatus("Playing card..."),await this.playCard(e.card)):console.log("Not my turn or not in correct phase")}async passCards(e){if(this.client)try{const t=await this.client.passCards({playerId:this.playerId,cards:e});console.log("Pass cards response:",t),t.hasError?(this.ui.showMessage(`Error: ${t.error}`),this.scene.clearSelection()):(this.ui.showMessage("Cards passed!"),this.ui.setStatus("Waiting for other players to pass..."),e.forEach(n=>this.scene.removePlayerCard(n)),this.scene.clearSelection())}catch(t){console.error("Error passing cards:",t),this.ui.showMessage("Failed to pass cards"),this.scene.clearSelection()}}async playCard(e){if(this.client)try{console.log("Playing card:",e),console.log("Player ID:",this.playerId),console.log("My turn:",this.myTurn);const t=await this.client.playCard({playerId:this.playerId,card:e});console.log("Play card response:",t),t.hasError?this.ui.showMessage(`Error: ${t.error}`):(this.myTurn=!1,this.scene.removePlayerCard(e),this.scene.addTrickCard(e,0),this.ui.setStatus("Waiting for other players..."),this.updateGameState(t))}catch(t){console.error("Error playing card:",t),this.ui.showMessage("Failed to play card")}}}function Qa(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,i=>{const e=Math.random()*16|0;return(i==="x"?e:e&3|8).toString(16)})}function eo(){console.log("Initializing Hearts Web Client...");const i=document.getElementById("canvas-container");if(!i){console.error("Canvas container not found!");return}const e=new vt(i);console.log("3D scene initialized");const t=new tp;console.log("UI initialized");const n=new ip(e,t);console.log("Game controller initialized");const r=document.getElementById("create-game-btn"),s=document.getElementById("join-game-btn"),a=document.getElementById("join-section"),o=document.getElementById("created-game-section"),c=document.getElementById("connect-btn"),l=document.getElementById("created-game-id"),h=document.getElementById("copy-game-id-btn"),d=document.getElementById("connect-to-created-btn");let f="";s?.addEventListener("click",()=>{a&&(a.style.display="block"),o&&(o.style.display="none")}),r?.addEventListener("click",async()=>{const _=document.getElementById("player-name").value.trim();if(!_){t.setConnectionStatus("Please enter your name");return}try{t.setConnectionStatus("Creating game..."),r&&(r.disabled=!0);const p=await n.createGame("ws://localhost:13992",_);f=p,l&&(l.value=p),a&&(a.style.display="none"),o&&(o.style.display="block"),t.setConnectionStatus("Game created successfully!"),console.log("Game created with ID:",p)}catch(x){console.error("Failed to create game:",x),t.setConnectionStatus("Failed to create game: "+(x instanceof Error?x.message:String(x)))}finally{r&&(r.disabled=!1)}}),h?.addEventListener("click",()=>{l&&(l.select(),navigator.clipboard.writeText(l.value).then(()=>{const m=h.textContent;h.textContent="Copied!",setTimeout(()=>{h.textContent=m},2e3)}))}),d?.addEventListener("click",async()=>{const _=document.getElementById("player-name").value.trim();if(!_){t.setConnectionStatus("Please enter your name");return}const x=Qa(),p="ws://localhost:13992";console.log("Connection details:"),console.log("- Server URL:",p),console.log("- Player ID:",x),console.log("- Player Name:",_),console.log("- Game ID:",f);try{await n.connect(p,x,_,f)}catch(u){console.error("Failed to connect:",u)}}),c?.addEventListener("click",async()=>{const m=t.getConnectionInputs(),_=m.playerName.trim(),x=m.gameId.trim();if(!_||!x){t.setConnectionStatus("Please fill in all fields");return}const p=Qa(),u="ws://localhost:13992";console.log("Connection details:"),console.log("- Server URL:",u),console.log("- Player ID:",p),console.log("- Player Name:",_),console.log("- Game ID:",x);try{await n.connect(u,p,_,x)}catch(b){console.error("Failed to connect:",b)}}),console.log("Hearts Web Client ready!")}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",eo):eo(); diff --git a/web-clients/hearts/dist/bg.png b/web-clients/hearts/dist/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..eedd1ae3bce62a2e6dee5da560fff1efa401056d GIT binary patch literal 367189 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

e?V&HmPWjX0|DkDMvRp5a51 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 H1(4ec8J|R5f+2PIu=%>}U^lPZy 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≀J2BTI>(9oC+8M0_j5DO+EFim4B08s~=#8QcLk^wTZnvkctIxW zUOY8YVp3-Y@0hu9k+g>$(n>kM+4E?-Yz^wBb<+0klxM%s^jbzj4teOz;zUXkaY)#z zbplZx`9eU~n1!)kZ8%ID+bB z=XJf2NJMOr-%~CbGjXTmVa5leEv{InH#mlDE$Y-{=j8d!9Nw=}sssMEx78j>Dn@lt zkqp~oMsMM|qoflYiljbtu`WYWaAL{R3rI*Z}eFtFSwxXHyTY!ZY`Bvy&|D0q* zu{JWW*NXOyB`gP0epK3~Sb~%@-k^~rQz@USVXr&ze|jx%ZM*e3PiAUsKgM3|ZPKWl zvWrTieJhVon!L%e>UkjL&FnR`>^gc1fzJfdoR|$QGr$Ul2EqNF7ua+xWP1ZR%U@t#=1C6FU zyMn%k;T$u|PNq@0>;qT5IGk9W4*1L?&%NA|4UKYk%uxcs{}7RXeW2T~eOKOWG|m5i zKK9|Hq}5~3b8(J4Jq>f$vYAd8CWS|ND$>p=%jDL+t=JUH!u$`67r6T-JTTY2{BjFR z!C_dt<(r1J=K~ttaI188lS+sUYw~O55t`r-3m*AYPRIMZdqX* z&U#Y3fPiK?%#sj&yp*wIT{b7L!{wwEAB{(lT;q1CZ(UwgnlpRCEbaWv@c!e)dazMK zzp2gCL&?}~jO6t&)OxBAll9&X1zo+afuSDej&eF~CHA7+9B}fq9HiWJ zmdY8AkAcnFQ}`dI1^7vW01T#(T@k7CM7zAD9nF~t`sVclPewZJ^|Cm-6ziUS*#z{; z+F-^ePv$#MKM(BK5|w+5#@Fpe4PkG~JQS!l1X9A1b;RCwKTgOHtt%Y+W0En+}W)oK^tt=%m7KCk%< za-j}|^gJQ-v-TR~kL_LIUi?7ANaqYTG3-i^K4vn97Mj?k=fL;G1Yj>8M<$$k+(N3$ zGL#o*`DI}*muZcJls6gnK>0hBUXh`@IRmP_A@J>-*_wX#1^}FP{B9-7>+j;71?-`t zY%O{FiZ{bjO+VM<5s`b~PUk@f+*uzcY|{Pz%BS;UUUuc3U$Wd; zx|#>D2BFrf04XewitsF2v&A~YBlEvbYa&F6cIGu054zdOY2l^mGn8^8{2>*ItAzjC zuq1JWXl4~`CQ~I9fcwxBV3pG+9C6;<3R7s9V`F^}%?xJ_P19PHMwt^}qz^iY2(Rm^ ztHM4uBPm1w!7V0*WdVOU^kXWOiRk5>zO|N^seC_6ZeFKn(K-~eYn-3v>dGi9)~aO3 z5i%2wEz zM})zuQnEcABzo5LMF;jC>?Pr5y(MfA(o@Ll7J+c)dRd_HTs53~-@*6$`Ieh!u~UZ* z*c;{dNe4^W5Q(t0m<7`d8b(H>g`Wd^N#0kWC3dl(q>LKOa)ew&;|Mo-;~Di@ zO*DNH|9`Fx>_qm(EvseM^{DvB`*L*b4Q`X~mpM&)5qZsT$~_60TO-upxIGWC0+63G z>_!ocfh>FD_g0JX+n}!#Qxi2BO)P_3epYBxvJtd0pQMT$!?lNtWJ^NUg5*nlK+r5U z02`rqCoLPDoOpybi7#H)&hFPCl-H^IISUhZFgG!XO69tTP^f-Lx+h#Qq+}stOh@TBA5}{gPR!`$=?_&+lVbuLJx3Fx<8jBV$4WpOq>1@cXd5**a^}EcpWphwf7 zSBBAX>*A7keQ+r-(%|GEG4s^_WBFa^4CY6NN|7NOO((WYo@WJC`m5(za^Ixo>Q2S; ze0w{ZJH?ku8|3qLaHI0)`&)1b`u%meY(Ngu!3O`T&23qm(dRUE@9!4|0@Fcb?rN*I zNXTzHZ_u&#zK{pT(o3c;_IIM}=Lzgh;Og=UlxuiuMtEJ%q=OAIdr!_Y=QP9q ztCl*RPJ4|v2cJI?~&NMHDvs2_3j{>J8a-{ciRE$yDU~`x)44(J_r$CHA_U z!wxz2R=T3eeT>3hP3+AY=j;a;;APkoHWu$lHmfh>bY8Gghk=mU#*V#x4)u~tuKRN9 zvFRbziEP~SJo&v#M4g+f<7;mQbX~3d1_*#^;k@lq$?9h!(yd97arnu83*Pvqf!qER zR+61VFTh0U1EpMYpH;8&l>LTag>I>Uz47!{*h^JO>|OFan%KJn7rk>jvG>WkX&eXG z>@5vMe1Csuhxxh*d*L@U+3ncN`Vlul3vt2V_g>NlPqNBaG*9vVS&uA(jd7WB?5(5X z>icZH4Qm{GSNRS2n}1Z=kOT=`q80nVPxxl}; z4l|}o3`5f$)-~Djc2L!`GFc)^#VD^@SKx`jm?PkcD?R{w@#X|`%BB%gz-y{8;wfcd z;=i0kOEbid)1EDI&K-V9sF#`8w+p?pXOV^rWg6LQ2vr%0qDW~?QGH(kVDy~9J@Vig zl&r$ZSoEvR0d8IrZYs|o692l*ubW8M42Dj=3MnKSV5i3*Ym~=Kg@-ve(_DTmBKU=c(e`Okd4v1L!GJ2(|{n3oVrwfiK*4V z3Ul#!R{L+QeS7nk6gjrLu^{E#hL@Ms)7mr(HJQus2~usvLB&p63zvL9pX5ed*Y{R&DH5 z;3#W_Rab0k>6;Zh!N!#ow>{oReOKdtOc_%~}Ct7)$J7)F) zMH$#z`L!HK1~xwA{S^g{sy+!3hl#_PZ zV(eADQgv!6o={Xs%(I%s#Hh9MmYJ-_JE;?nNFBw3HtwKq@<{Je`$Cxd@h(d8)v<>w zXj>oQ4KyubUo+X%dTZa8)*R4n%9L$4JuQnaVM;w@nyD;P$w;>G#ZmPJNvzLlYsDuR zJ3GfLKjcA5@2ZLsxn%3e>9=d|m~J+wGnsWDS3$N;6klz8pacZFdg>Glz_^5P%gA@{ zmDeapIo{I@CNSox@AwwG8HU0rIXRZ;qC=5&=QU8oon~zOZ;rw>*(T#K=v_XCEv>=&p-1@wo#?ztJQ349tkq05h_Hn%P!}G zAJq>wcTn`nG+4LO7R9&khYJbkFEfxf64+(I|E?9YiMGp`5|0FY3n11sqCyT40Jr{3 z>5j@CQ1>u8n)uC%2syVc7UD1*H*^i{-)Cw3`Gk5)A{6>Kk!mcyYj`#c%c;s8DGPUC z#Mg?!JW_eaS9CbOzrRO*CYF&OgbFd+1N{&Y=?+65#cv!+?3Ek{2KEAT-AXLM`l?)~ z*w&xIiCLKkUzn-Q5f~bvJIxFLdoQiEqsYn2sx_u@!_X=__GWd9RN4P_N_N>5Ib$!4 zk+=3b=R6TzMRR#g?P=hV3)jdCGCji*+4gh07kxsZufh}^bQVI*OTAr3|yu^mV zVjdo3_aR7aO^+W&_eD47?>1y>sr>E;wIaf^JD{{l8a81=ry3HMu-LKwgpVcr)JAE0 zIoYmJr$>9{yOzcHRIO`T4Lth(C1c@@*6a%}k7x{^yN{+o4^uvF&<~0W* zCqj;*>Q$#}gXrxm8f2w*S39Le`pWZsbQiE`AU`)s>rkI$_oS1fA~dUe$t4uuwwKNH zx1YmM#b8NxJUdbCuZdNdIrHnx^pDr*nEscDeMu^cmM~1Rs)}gDVW8S(ArT^QSLjRz znS2<1ZQ&PNgVb{~A7%Xd`s(k8>B`^8kK`d8HPJR`fzf;u9|;GvR$Vgl zv5~%WMcRvqit_JHTXLTSIm9fLfb!=YE{ue)zTRP{;`AK!xw74t%hmn$4}pVP^6UTg zS3N<<{`t>;P%U;RphQiZL17-y@{__B6Z!u0CtL2mu`WgB zx>=U4DhCwAD12@V6CtFwpfBfSggG;+{o${N@Jg#z_ z*sf{t*39Jj{uYx6i3{E*pM-3M@T_OF9nDU7_@?u^Hf>UxQ5KIDsKy!`W?8oU=e`4e zzZl`f27Z9MzlXi$tmROy@EX&TM7CP+AQ=@}`n5^C55`~CmaVvp(B}#e!n;O?REXMb z5+MiLCic3|;9=;!ZW;2;*voVU+3dI{_NvRSW3S0S{_&Tbv3IvIF8FY~s}td}OLigN ze*gKCbT#b73}Lyhc!z4(3B zt{QxVH8HuaOYZwGNx6!`+_s8f&;&H0UbC(xl~ti-OaAq*KZLz#siXFmuUgHU_4oX! zts{+N?;o-IF2C2T#`m~aCYZG+>?NgizZZi}5xtPu>(`&}z}`NgJotRLti>V_ZJi5+ z3&pP{VTT#>hP^pB+x5hEwnZ!1U`y|~CuZ4{-w*UduC{?Q`b=tY8JN-Q^yW3-Ed(&I zGS>B945sW8G~(p_x0&y_Y`@u$*RPk&k6=8e0?x)fy%%ZH&c=7GTw|Ib_42v@v_s=T zxE!?gieN=^Lvz!*5hsI`ncF)@7qT!C&vFvY#MiBak*)lR*yvm`vfy^vqBSb90%WZ= zDpz8!V)n#3852jYC5fWup^oj0Ow1x+1Cks}ScAWqsVT!S+wUZ{n*3_4BIrBG!Mk*% z8?~@GmWGpLO%DMA1qPi;4iB1pRb)%jBCf7?#%B zXQ5%F0&)> zl5*AOm~8e!*pZlmrZB8$of23mH` zT4$WTe8panKwU7y{W$pLNDm|c^?-aOd= z*h|qAR=I81yU9s53S9+?)_QujCw;|lw&gZo)lFns*k^J+YB8R(E$6r4*H}cBakl|f z=EZ9(5_=m-R5N3-E)i{Ynmpk4)WT{zX(-)&>Xc@iPCIvMllSY;G40j;H(+P7!JQ z#hUsz?J2Hl`&%yjE2K6bO+?^ZP5W!|cII)P9TjnXJpJDMK^2-omLUYhlM?n`qZ6Cu z7uZYXHA+*Tp7K%dJELwKd%Mr0DTjkP%hCn9;$M-E5!u{N(I;{j-J+G1YMvvw8fHrC zAo{iZD3bork2jN*rlyFPGI#n72JwutR(LJ!1&+Ycu3wEo2U(p-yL_T}fZ%L_lkg9} zp`6KoJX1`M)udUJUmB5xHIIX z(J0e!g1}#TKs1u`+UymZfs?96c{)1w{!HgeG2hQ+7A@PurjKOV+BMd zlo@L{-r9CvY_Z59;SAI)*D%2&LIV$b*8!usnj^QpxdW_CV)G!cCwEFyg0zcEZ=>#D zsFY4sO_tcY%i!3On>Lh5USnrRB9zzlWrl(8)*9YohrZ>Teu;^!N9_9Av}>-{smu@8 z7@ONYs1h|2B{rIm#BUXgO$2T8&)+6>TS)v(f02iZNjb9kp zZKV2z5tQN;dq;{k0((=6 z%<`Z6@UX=(`vkH=uJbPtPkqL0T`M-(5nrq~jwm6umFyYfJ_o&v2YpvOjpQ$}t-|e3 zj1pjdEmUyUl07u%_mtPOhFN0g8}=549KJTMYhiCsn|5|PIf8igqm_}gkz7v0UNqwe z*%g`YONHJ$gh5Y%b%Yejqa!qI{zG|bz+OxFLnqqIHy>lVT^BLHSKXY3z2A7JFG9UoMCRTe&F{U^z9E(JA*<};(@H&=mgi2N;me-P)GJ3M4I0_bt@Z1 z$>k_q?0YoKy7q_|47_k#H`B0*SJ!bKNYg{PCoSx{)xT-_pEKB+81u<%nb$sJ3MPNd zg~bF7my~Zd69l)B&Ug!ldGo(2L*bDS2Yqh|FZtc=X(6vjy&;*7ug(r&IYB0OE0WR~ zc9%_I101j5555t#5aqjzc^!&73OV(gUSm zlbp$hatC!XD_bH5G7OIN6{Xj@I-6(ywu~G|7`9!UVxy4O;Nw#mT`j-Hf0wkBzE4?- zJ7axkxg9t&%RW+d{#7}XV{Rs*p-aaBjWTW~tA1jA9d&k0fNT>dDew4RRb|O7IYV-+ z9Y6ihcB95n?Il9zK=yT8+b;Ocx=j9I7Mbq(!?cPMr%p)Pi=dV3((p;jZunA-Yg!!2 z7xKe66b{gDu{Y{wrbJuSzAm0oWnmZDM>OzWKZ)=U*Bkb#Wc(-l0w{0$Hli2MR-o9KRUhi!UdwDWV=+2jjpCkCVa4DHjYFTZc3w2dMvC-@bP zzcGFmu?Ie|u6elYHR%yxp<__yVMZxfx7Y{;Pgv(|iQ3)Ms-#|@WmkI>a}9=}yu`85 zWq0I}3>zh^RkQtc)q3lqDzO*rJz}pB-%m=^V+HkIl!I@Z-Ax}d&-8{M6% zrG%WA$a1^W<*M&>(XdzCp88BL5ZW$=4igQEo~*q-ZVeY`;D=JBgi9|Rr9e6xuBNI63 z3I6P1y(gE*+Mkj6;Z--m1>(^zQNJ3&x27*FJ8%SfMy=PS3v{uN!cL&bOI#olIgCjArY1JO?Kz0MM zf$1(wxDWxjmO+kCvQfp>^ z5MjyPr6E)z;ZTH8w3-D)dmwzO2EIxcH@Fd~Zl8@Xv+T&*Xe7)`3azotGkMJuWvAp) zoJUcR6!I%(qSq2%--cSSLQZ4$c4>tEBBV>@G}wb#WN*q{C%XLcs|sDj0Nu)Z)C_f> zQ97?1GP4XR?~b&|pYLxG@y@zl6c)T;uMY;)7-`;s8&X3OkX;fkmg6*k9iQs`s6({J zYl~1DYaUgk)Q*I`(%cXciQxs2_{_~>^FD0@!X?wK$b=;G z5aHn45qm|X!t+k{qt_r2B%uYmL=gT=E&3OC%h z0rpa7$UNi`;e2}4`RG?{=%k8`6^%%FyE>E>k1RHcYg}XORre#7P3-jzx&-&eIY`#|F&y#58_Ajc z`QzBD;I?g(cd(s=7j6Hy3@06Y{w7?J8LDv?_i~g1+!JV*aPl!BW z1gg*|+kwgU^dMX*Ec29as-8+P=@MR}<;I2pNKV}mfLb{h#s-h55mC~MgT+dRBT%U< zn24BM*F75KlI!-o5`5J%OrsnC>?}#Z%yIH4S3S@AxD=($7&d+;16ztFHfd2N=l0Ok z7Eo+biex=c*n(SYhq{^j#|uV+96+VwmZ+$%>eLORWsP_JQW^o`Fr!quTwF>(q$i5& z$sS4`GNt9#F05Bv)gCpwLQreLa8ar4(z8Z_HP@GjeEZhWQK!>h>?$+V@V>7; z@~Op}_27sCtzD$ex%Sts@*N$e8hoJQvJBeo)cD?dLZjIn`ioRQ2kAf`WB`6i5sxzo zwKa>(irLHSx?;ePO;bn4260Io;Rkhq75E_{+!0Nn%Ow!PFPcn%(P|iL>+t6axyKG$$oF*M{BI;q@uyo&aEf(<)R&_fxTbyL?;g& zjDBV$E?!2X(n)(qQhv9=+qh>rNbJ@9n>J|Er6L>B zuL|Q!D%}d$%$^)n;AKe)pJgrSyM32%=Kn3+dt&dK{MI12C!;`a z7@BDB2IMK41CKFD(9P>MXa~H!vU4@*vn}t=UuJN}UVPp7qwGsf9_(e~N{)x`AR;ve zOc97IzCEY02DaVV`JO5Lud|b|ld?U&q>uQw*}P)4W8|qkZhiT{a2TMsDh753U?F^h`aB7+t{KGiibfR0*3j zXHREkAyjD$rlI2BR3_-NG`ywXRYuKT_L6D#rjs+Sf#R&EEfsic`(V^3TZ`8z?~z-v zUc`Kh_O%Lu%-YvQD@GDGA^;ZM8S-n1$=8|C17BKa??d%?u+hxKcnk7jxp;JxAtuKe z%%#lCMYX#pH$-t1mungJCDO<92Sn9hDd&*CnxIkvKf6gB= zM4Xmb#mmMz?E@FbOAq(P57@BQ^Jb(@y~iO}Qkh>R?H4&k7*jh83E{$}>Ce9B}EOo-MccF%konk2i8rZuMdy7m}k-rYuyW*%b zrS=XK@Oz`$w94!#HNy@&_RdcZTp2U0rZFR_(9vn93VXv8J5N}4r`^->;t+Yk=AfEC z_{L7BAP5#<@>q!^{dVYE_XG9?3=JUv1d1x@3|W#NoSCFN93voh|! zoCKfw`t$uquIu*msVvIWqOIn~N^Dphayp+tJkPLJ)TJ4~h=3neC}4y;Mui%8C} z#B5p4?6iM+q&HcFO%8Z8)tHsz|VPV*DH^j_ChyhED?2&>eA@Z5y! z+t;c8^Pm4rf_YZcM@(UC%2>3BXf_1-jFD0!-yTr;ez9?2o%eTbgckgZwk>#4`V4aY zNvJ;P6hstGXw)-pA`-C0|6IMgG4aTOsK;6=f6RBCO?2E0y--N{j@@VMtx#7VfWSJp zl65=YLFOnr26=7HqY6TbuC`taVdfP<0gU$bd5f?YjJ4vkExGTGy>N;D_2-Y=_bp$4 zeMLyGxWg25`c9Oib4eYtcZtwyTiea}OnOk^|+5m*v1f>LkiYv7`r0wjp0!_sApLD#5KVkl<&#RKzfw zhCxuqK*Fnp8l}N!6~PjYI!?p&9BWHOa10u){x#{?d+m`1&+`!Wx^20n22nBFTK4D# zKMM%^0~NtWGQ7UNndVQfM6>ZmBEhj()fTm6U}j3|5r0&m!kCR7uBweU@6(QhoE|RU zW`ITH`}EDHx7f>X*mpoy zEW1%2kKl{cav+-3PG)CY4xUea%b(iHVwr8bTBl4+Lv*UCja%y?NqBS41GCw~#Yk-TLqCG-g4>ep}NLWEnc514huWAgj^UCzx!^w#A2GK9P! zBRhR2Z+dgIJBCha&;W-&KzMowZKjdSkIa99gajJWnPU0M=&mw8DiRw`@N5&pk3~$@ zW3;IO$()JUdPL-o8PiAFK#*9??ub&m9H?iRBNjLbeYM}~HF%W^ z^MS0E|5+&BiDH4xpIpyrxmxM1OqKu-mRP>tSL=8s3y1v3tm7s%v)BrUQn6abj2TAd z@0oWeEV4FXTk>!$IAp7L2qA~%L)zx7bC!!X=ki&6DNMXb{g%mk9=UwoMGih9d~1p1 z&ezS&*+HfQ>w&)$6DQ5bL3ER#yyRUx3mf-<=(}McXL8E`N+hdoz>BB7gmw75gyrzyu!^rvSylRA}NjEq8Et95KbYraw&LBp-|H#l@LiV~i zOaVEq4Ug8F;i#>(b6Wp``P>Op)eN8EH7K?*lGsjuVl#EQz9N8Biho5$QJ;X({33cL z2sB12V54=8Do6DR4Cb&H=OsckR(dhi9)6Z^6fHV2+Ws6@)ctrr5#{#e%jF@t<{a4! z%+}udI>h32b}M*-0yfkBq&=H2^D9ba=G9*#9GA26ACALLBU#^v;BX*d3$Z^d>C)4@ixTz za4TXW#Mf|DIv#kck$sfxc4mU%`*dN5psQ`<+1hb&rqhsSeu5ZS_{0WDpIWtc#a^jd z{LZ7y?xY=nt#Mw2y|=dN6`WBTCvFc6XpqdZOY85R2Yd5om_(yQ7^|nPvq-v)UV^ne z1X2aE7MA>F=cNWdlkRsnL3_E`4lUuh?!3BV?@UgV5B#i2F?D{q^A}--Z0Qc{J@w{XgwqY65I5_@4$9#J-%gxEzDYD<6CXXTo);8T!)v9h>^vobxxw-rCe zIZYcht3PsVG8nVDYk|kXa>jY@C+l;{F8|OWR2S^MhJFHlVR3!hsu1kB+WW9>8|x!I zkmRNpER#2SrcCEwh3bQizpmKZS;BlF)XIs4%cX!HI7V`@TcyQMnb`ZW6BkmRJN9xU zn_5CZc54+`;(PgR=wr*LKFjyIUTp_?`T66&(Gs|@FIQss%5}AUo2ZZ52xey?#yVsn>lOBRn*mBKs*y{P*@YJ+O@+p1+^5U3}C#C?4%|bhbJ}GQ-hX*Gc8~Z{ z$0IV5tq~>Z7r3KX97cvJIsXH=(`BAO})p~fZl~;O!STENA-ewCm*EBQs z_L(Y+Pyr&$x7et#2!^Q4!hSaJ*}!9iI_opm#&}5nF`$xsV&<}eVI%JR$UI4YQ8Th} zPq$IM_AI{1!G$m-YhAE6oQ|1k&ogfBcrR)9`lX;C)T(_#NoAf9x{+3Vd5pi`YHQE3 zzRP*>hP_eHjbDJv)h1a6Vr`)5amcO~PLN8Z?n7&&BX!A9G001}_r`FUHgWH>`!NGr z%TKj6jlu>~)`xV)X-vo53*B3>me>xd|MmF!zh@h1>YW#)s7+n6)UY)dUV>-k%W?(w zMq4BTPBm~o)CfiJ(06y&zFc5G+IVXHiki2Cx@=I^k}IVQy7^hh_QYPd5qm2> zAEfV7HlHy5@Er#B1|wIOJI@gj_YT zHy3gJ5%ywW?+1H7SWrBUz2cE8Y#S`Hh-hh;I{A6AyN=N@8{AMR{a(i27u(&i*JT&T zQ?+7)vS&Y4M%Is2;Oy%+P37W_?z`tIS4t*s}-N4*BeQmayhE}s4K|jkx&K8uLvE=s! zz4qxUr*&}yzks9avC)$dPwT8MVw~6vj?GO(;Osi{pT)TXmfv=>|7h*a&MP28HtqSQvTHqN)vL?>_?+x{ z-Z0pyLVOfW5d3fxudH9U71GqH@WGvQ5JfV~C-kcv7YZQ>8r;#^`^QG*DKvNTBi8)n zIwuqj3$-@u!?Xb@$6{OajSqJj7g#P`bD&aZ8zFB@M-dNqrF{YXY`pyq764< z5RB^>j)p*Dq1?zTT-d&wv%T3NroNsVfb7gOl{_}cum*zeCpX%9+mMfSyz7@cOB$FD zsP0-KB>vtpOri!YREXuz??eB06l%H?QpX$3)H5dg(1tIUr4`tK5S&nEWn^K;54 zb&ieyP`(CvDUJfjPO?i^(CkQCbMN1mowA<~%Xf2phFxX6<@MtS>q>_#JaG9exbLRw zw8uHcoOg$-D4z-uL9T_!&aCON>XZD8us$oZY|wrl$6m^Q)H89*cM~pAi4K}cz$b8k zNK;kFXA$;Z26&Qj2zSWqGe{ZfI#2rhP^#7~J|MF0R5dpv3+x2|^|iBagCHfFg?W_e zET)$ppN$%YMitJuEt?rBY8`hBlIcczj*1phbYR6XWj5_DUD3gXuc7yRl(4tl-ASjF zYp*`Zm$sQyewv6>*gNwgA3vj}BuY4Ot79)emsFSK`K_SDvDYG4%*Uu>nVd(t&kTVl z%jvcKo6)AU$$^yJw3jdPQzeDpTZ1(bWf%5PgLlXEA_EFEzgW(+Rf9_&haauoW=96& zrujGdG<5#OCN(fZ1D5pFN@a|fUK9#ZWh212yI<%>1`OSdg*DwOsC(a{YmY}6uam>&Z%3d8b zVQ$V)-_x46Fdc!d!^`|e`^2bob0}O^_F31n{>gIVz$c*otYGwJRwQ`|ur|Wtcl)KnUH$7d8K-17WIzb<%YGw7=@ zOGEDz$PMoX{ciY$^2h`!R)J57=JXRmF^CX@I&$EqG}^D>sM!>Skqy6-)rP+zjkrdQ zw33O0T-kYjAMJA>d4s4iNE!}CV1NjCa4YKmeMFtemiEJ+OHb1vLoWKXrt&x=QcRp$(M}RW8_}K10j&;%M%8c9ipiU(J=_nZzhJ z^Qw91sGE$ua_l@l(t*8M(3Iy!#31%onad?a5jA71JM{?7tW*D#<;0&!nZG2tK^F;n z(%!YJ)ms1?@LBD-0vWwzkI4VZ!MBOMmRFHWZ5ixpex=rn14^_86IgyPSMCHs)aZY^RD3sSLRjo;rBY!GA~F%jCz@2dZ9+ z&N|1h3f*FHmi9eLaZ<0Q`T~RB>H8rj~V$a*~nD?75J7e-Eh$ zD4rmGF)W=!`Qlu~AQ!x`3~a%9&34!>y<>clIvpCj{WX{rWN42A(%!c^2Y|)XG^!rAx4el z)H5yBE%r_Ggi;nNvn9HLOf%?{E^U3JyY@)g)?wQc^l4WAT244%(ZDSq0)Q;PgMh8k zu#6WuLn|E5tRHs(^xTPBwFXzDhcXgVy!&KB^pA(4Ev{e6QnV%MZrW6mg%o^pu(MGl z+o4A5wLtUDnpLfEXZoLBWt>YzdS|rbk++Rhsi#2+r$m6IC0ndBQ+5FyBjnoi7CsX> zI(Z1gK0hL(&U&Mo;+LBSsX%zMl*0%z!PGVlY^6rUMm6^Hq#Ow>bpIF})1tMaDp=Vh z`Lh){QvRm6!q}S~N}3D5nV4iBw^P--tOHUGtSKS~+I2;lwwFtW6LU*HRWwz~fB5de zGTSKX=zO(VH`Z6bauPEYxAUTfCsMkLO}+*7Hr=4tx}%*dw78r4@Er(VNJBFUz}NWO z4cFh(zs@?HkNch&mhO2TUvn&W)~nc#oJnNqAOWjGFgVa z4=~-aH;U{-FC03pp&BR47>!`RrGTErb9?gEoJ7#H2 zZlPmxr+Z**yYK0m*em-eK=@%Ddy#S<%6nQ}W&!c}P_ZvI@t5mm#`HqUz@s~I-YWJTz;1Qa#?vns8=1)#e(!*&{b8oLkGd480^5O&<|eK* zV7%o{#Eqou=f_3un>b9Md>l0r#83LX0ZGX-EQn?`1W3SL=7qzK8u9^)W!t~=E}KzK zX04)r<0 zQ&deE3xn8p4~e=gq->^mH-)|!#K0xzbI=hy2<+V+)}`23YMZXC56A9xR7kvvcMUtE z=n|?Gtw&(XAPMx#Tban_(w$Ly9t0@cdyqHnh=Pg zTB&Rni^`ZI)%@o*`&2)mP0Gk0tW_3AePT;-=TXyCbzNxTC~syN~dvZ_R+&Fm(YGOBb;JaI=A1fn~baD)nPZ{+HF~HA7rW>n%m$A zWgohAnCY8yK(82bXI;}~=71qFU$_P0_^H@va0Bwmw<)G~_^O**q#Nlrv{tPnW-G&I z3d~=U*jvSEu|nbNq9bUQ8Yoy58yliJFX=N-J0_*qCwKnJ z5!U{p;^;ohz~NEnmWI^SAe(IkZ3u~bTPY0`W$BygAX<2%j%GLF894x~S_F06zMSS9 zMEr6e3c$vhQ)YE9*wT2+3iYk*_v@u&D($aagyn9m&MDwjf*2ueGij7Z6DU2}uBDdA z1i$k(j1gl+7&C?VnMe@0GScWIf9&}(hV-g)*OE45pmizInehHw!Z=A>*NZz|Q74}h^F=MYZ1%`LM1=n*BaXG+XXirlmu_?_=>_&4cg z+rcu1H&QQhjdeW3n5A=}KM;KQ!=9PvRh{E;T@4tO zo%bd^9ZO?fAHg{3Pqk6(EU4WW5WQCwr?+?6ZRVq=7^h3+PvR}(S+B1@t5`UM0~K5C zn{4|wm$cqI-41S79_WbnVA`^0F8RmgM)3K>41su`So47NJiF9uAS8ct&7sLJqwoW$ z?F^|iErR26Hq3O!`$wK8u=iq!+0a7K9QIV3iM^w&1K_>@*cAFGK9>YmL$#$dUZj~m zlIP|y+_S#EIPAOugC5@z&}x+J@~XY;9_Hs%wha!I-bvZ8mW`r0YLca;eeODYtz6ck zqC_N@LvLMKmk582<4cnF45JPIt8HvW9D^leoXZ>!93^R!_rG1G`w<()Qd`Hu@G^rc zPw3y{`jg@Tbf2t~c7yrCmi|8F!A}vXK|umYZ|5s_Zq7vf{1d-{KJ4u}ZNU&(plDRa z!~_XY*up_udv*+DB}L`C2(_An>1Vlq#yBs0AUKmp#~Gz29Ep%l!}=xUwEGabGAiPhPSd zopnD&aoDByePnr2rlfJaYuVMlAyqfRSHxu7{oDN0*v2&ILI0mz)G_^kfPek3y6rwf zdmMsMN2Q<)WD?5kjYjqwgaH}lbSB2TZ{RHLJp+M|;^zEE+ODZ!L1s64n)%SoLYs7@ z@C1lWYwzbbyL;`l>Bx@wIwDE^oFl zX>La44j$QJ5+*TBacp9;%fUFDNy>GIPnh;eR1cUqa;bDpen)s-etD5A7C(uRS8_%; z{4|K39ng7AP-`${`Q;3w^C{YPX-Hp5a*hh;D7-e&1xS~D7{bi;N!h5H`y9TgKh8`>GZ7acu#d%Fs}+YH2PpJ?9|049U;>EYa3tVRzYqQ*?9Quy?!tE{6k> z*otfj5n%sJzOh_P`loTGpU#Vzm7T2=MWkOuVUgk?#1LdSvC>gWy+~@ykd3%y8kMD< z+vL1*;~*dhvjXd4BeGn~CE7cKt!)0~bmkro?@IKJ#-|Jb7dz0B4fVgCT*CV$eJDu?bi zsJ-~}k=Fsdjy10kMxfJwT*|m-Qg?)_^qn;y<&i%Jy~!H=P7f&EzX1H>o`kRWU3oPK zW=h7yFnhy2Spj*z^NwsbJbjzrF~T0i9As4)uA+NGJ-$A6P@Q3_`9;piFbGgl(f%6i zMoXC*$%wNpk?kYEWjzpoG{7@?32N8kgV3IK8F--^8#Qy9o4!fNSMjEHlhxvVON;(- zXW8ZA_OOZ?a2fd8dfeKfm8*8kl1b`%7Y;;Y9yob2`;AObr0oI8QgZ|}|0savyolz? zP;j}^)b3OCxzk8gWG8fGr&0AmZ8z_2C&)(H8xV=LAs6dh46%Qs9k#iFb-r%NL!7+_ zAT|_C2lO_1Q$Z|Lej2*iD>~}=q!e!IEUE7p{0P#h)Y+(T`ryl^Yv< z>k~(CRBceaI&6@hUx&fNj3G-AM_ zYZj2RFc@Mm{0S9WPanQScEZ_K5_xUCev~dmuhSt_Kh?m$$aZI^uy+6TQrF~Lzm4WO zLiyca30yULH9yFXw*ZP=8~S9uKmI%PPZE1;$JUYzZniROyhI|%4j(26)cW2-egtG! zp}B!I)B~3}Z!Laj<#iInWqX~JUS6(uES5{EH{I0n7d{yA0sC+7z#6$9z)*DffQ;&< zNP~^%QG8%$2xDfNv%~}Z1AB)b zFn6}?P4Dlz=}XMk*Kg*-ng2y@#aMN`A}TpwC7+& z-NF%XBWHq`am)>N1enJQgunnX+UZ*%3DW5?F^V;V9CkLXtl~TxhQLQ>!=1cbpZeCa zj5RP}%(#;>xkFsIio?;k@8WoS?vBK7R~tad{2W4;*xG_Azqm_Ez2MpkKN|Uj%VnUr zp9gEHZ)QY0%#0B*-D?bbjCM-=4EaQs1K;dRfEwH++2BD8GO_u0zvvVM5Zxwwx}n<7 z4Q|~!0?-`v(V$Usrc@|t+a!!<^te&T87sa}aGO>=09fc#ywV3eVw+CA=Q#(sE=&N@ z2`au#(L5XidUn{A`GDK$`kZLYpKkEeUXD84Y+Wbpy!7^|WABHK#5%B$T2CT$+fOjM5rNV~d9a3y?>}5Pq;)3;i=UGUL4rXhme^u}FT~CN^#hYmWjg zqK6^1;@$*P4$=7I>zgcdC64~gdVS)|kCQn<8W0UBOw=Au zc@EYyPlCUR!{u+R=!B=3?BQN(y}!yH+eSsn>Te)B)7*T3+q>`I9$)6bFk$Gc{NC{X zLbkWlpI)P5`cDA=iQ*`8c5?WZ=9WS(>E6EKbR|l+a;{ZmgOlJ3mk};6j9$f~H(8xC zAX+qRC_ce92mV?gCB!bttgf91e%30}XEVhASM{n{rq| zWu*g@#(U;z7&`#_vC0+3c)np!hGD&33QU|xx^ixV-rshZol>QFM=6?eGJ0x%M&%oO z7l5BUqw6f2ODt$RYf0a@q0Lcf4IohLXWOojF)IW&Bbf#e@inJ_@ju(MMx-}EE^$Su9}V0)+}$$Fm2mNiHN8UgJ*vo z3`EtPJ*I~7f*1sh*{<}HQj{%CboO;?Vx6iv+iQJtKrS}ENfDyDF|6J$)td1<9W%`} z=q(Tipbn|_Pu{LuyK=~QlYf@;Q-;5ml}_=CEDdKzWB0ab^J~6=VU4-taSAa@xC`3MTLp#TjsS5@SC69l-O8n3e7uo-JY zk4zR+|4x1T$f{XeHNCPNZaAnZV!?x2I)bbp^>P77%^-$vHn2D4Aljeh@37M^_pA(3 zkNV87@@uEApa_r0Lf&W7_n&_tubx`Ky=0 z#{OH;Z~5HbjptNEU6KHLgb`1hrSOo2mA{onLR(pGG!-?XNq)YCNyZ`2TrSaCf^*>~ zKau%r%sdD2S>I5h2!T-O11Rk5z^#fol34{s1*T$!k-Z5bIzK54i4$q2?J`j+{>!EG zXZl2ZQTePtwLuEg`c_zYD9&wGWOfpcV*y4UGK%=7vo2>vy@A;ZM?TgDo3}dvKvNDG zU>D1Etsujw!>LF|O&d*0&Pq0S^8&sB8R<$4(2#!Wk#u$eiE^bo<%jIKjm|!=SLC{8 zoz!Q*nXbvNFBi43L<1+RcD~dh>F%(km)^^=_4f)JU?c2xePe8`!3S~*|#AB05pvRy5#l=zS~M*;C; zKV$GZJtj=Ukmo*W^M{%d`@PJN!ItEI{zAvM zU3uRO$1zHFF$n%%n7GBR3@g_tD-BW!O=Zf@LF+jA`$1Cjw1@tMA+4iTxE!w1G_WqH z8DeYC=LAzUjj?ebBmq$~enqGYE+%5mR zs+V!=35QZ2c;SN|8UrDkBZk_TtB`SYfEgIA`b?2c>F;f)d(N=j>lt~Z4joB?S)rph z&hW7&k*)ag3~omt*w4mt`Q2e)n8aa}ff_7I98G7{Lxa}^Pz64%;UT@*_7R5MvFWfe z(s|aSGA_nu8r_ymPeY~j?3*EIqpYDQ)&>zu9izCv+LNeHJfq!l^EFl#r_hhl-BE#_3GJWgac?sH4Tf0W4awN?EU!8@R~HX z38btK*OAs6QhUb!1rvU%iMjrh@HY-zJ^@lj>f;e!eqd?gbT4AsOq{>lBD9%d=WoZP zslb#+vrY94uPintU|Z&OW&{O)oONj4s;~el~(u>16my7Rk z=f?5$4So;oeY=!cL>SnTXcr5<2+zPW_u3hKdEWGmFeyh&WYpCwn7#mP8D~>oPZ}F0 zl7nDsK-k-MvL#tcI_#TG_91tq9Zk_opLBCQd-!g=$b2M<4tiJl4TQZbHl`E%sQa;1 zhdH1bwa;+l_%=vxaw;U}@vQu7MxOUJzTp{Kn`xw*vfJ9E*W){W6#eh_RL0;@W%Y|Z zzrBv@e**Zwz9;!|j_I5sI*GsPdfJ5xNVfb5=$SXUU7*qn#Tx_3|I9SJb|XSr70C4$ z_T199&YBa`9H1;f5eFA58I-c#(?)*POo%Z)UT1^CXoXz zx^F?L#(KaM2isyXJ3=u@NFwS!{0HN1VdiJLn=>gz!A z8}Z<@1)E9tk91Nj9e7j<0;c-i*7asd7v7dQ?g&7 z7DqE{_TefF*FryQlcN({%K_mAacyHK0DVxa@kr3pyv1$&^_3GGLVPwd81RqpA>&}LqxGw?<9S_*h!z|;ASNjL?ZNhWmyX= zL;R;`g>PZ-5pr1_wAfKSZHj!L_#s;l0y3d?yI{y@28`^4|pGF;k~M}!vJT4Jkn_!GSDR~5Mt zVqm<|=tPf5ye$S9932=`6Paqu9W-qC)xcMTDGlC*M#s+nqQLWPd_IDMd-*z0A?weC6xt(?YIAluuK_D?&d=SvfZ+w<$CfAIT-j@Is9iuhLKujRg9U(PWt za68~qSs})Y+*;jY1NJrr-Kx#$sQiQBB-A1^m*2pJV1BAvh%1e>mpazW|H(i5 zM?rsy{roGOeBDZXcOq6v!ZE-^M5g9bow5Vt;aY}6p@UL&YJ5{_I33c#IB4svl#MGX z=_Hl&FYFcQwvOrEY8zvO;gee51+96ML!fuu`&>VU+tD7Jg8?c^^ge3*PZvA6mU ziX7~^ndIPGtn-eJfo|Ij$#)|?LXY0~1RPP(dp}t6X>Ha!#w%xt(#~ZRiU6zDO#{I5 zJUJ+O!^7I(WxR@`Gos;L4pesW^0F}<^SqUoVYm}}ljR3(Hy76yX?YJEVW%yLP;Rj(w%4=bHH38$nML)(9-c>%r<%x`v zCI&?R!`QnWd;9s1q+4l+hkd2-pSgm8Q^5k}oj=Uy&d)>0OFm7O zD()Z#FJfn2J1;xzIN3MJqI!Kw;B4bDlG(`La;d(AWc}ge=7tk}<2vh{n&`@4cUUFbOhBCAkLE?Y=+i{q)Zw}%AYpu`Nw$pzZzKQ!AOJ~3K~(vjOFZ$k z_&+kgT({@q*lYBwen_@kvZ4DITQ+HZBja)%9n;bqsRx*Bzcqr;FBd5WF`a3d`CL>P zs0Qx1u$!II6l%`bp2bdcYl(+cX;UBrGoGIJ@@QRQzB@qBBwA>AvF2CAH=gNnT$*+5 ze5?27NU!xl&6>rR_HBTHZmo_5K#qhTBcMc20Fcv$qk~QWtx9cYqiG_c9KBuYs&KRk z2%(JCCvsD);m~UGyUMw_sl8}vveD-~PYHU-B+^R;aazY{KRFZf^E|%WGeMF9G3XJL zlmvFyq5=T}do2HurEa2q1V4<2%Puy{k)~YFE{@2Cs^lzhKW{jI)upXD>Cl-Mh|GM#$ICIGzem>T+eZ>_2mBTpFo(s8TLCv=qR)N>`- zt!z?8<1?tK^Y&5G;?=@}cVLdr^l)r>cfv@K4gyeX6u5p@#uH(bqdP1%b4g`~jt3^F zrJpku+OR;9H{nYNY!j^*giOagX)9b+_$DfXa-?$263?2BBLt}4wYxV*4kWWk{0eg# zD%^Yk<`>sJvG=c(hj0Y#_XT@1!>YpyU5e6(Ty6($mw;Bwx9sN1!4AnRhScYKmM75f z)(3X|u+t|jY&F+Eu9(euLte?EJJwp8+;BEA^(DuiZFCr)oC$fJAB!Z3eH5rNjJ?U5 z5~>JdmLg`lnJW6H{Z;IL^nCFSkz$eKvmbeAOsf5~DYdC|nxv@M97*X~5VAi=>6NH{$J= z@Dr^u7=Is87)tn|*>I+B5j^a;sF4^x5y|wg=z0A|t zS1Q^ky}43*st$uK49|j|(2X1@(BgNrFKQx3$-do`kftec-~R{wS$9OTj**MzfS|oG zEb&%u{jFZ-Zs3S9%|2g9d%37%YJtBzf>?E7p{+t2jIu?LxdWtK&$B6yUZEWSBE?kl zN<$4SS1M098>cHfIbAS=G(I-M(gqMlxk~3Uk?~a}1LjJjrHI)GInzG@Z3+&XA#PZ6 zcs2}Js=jWh0{oj(u9u)35e*3>qO1`wcDr3}1yn|k}PNv5Jxx>X^2r*U)&OH|pIM7t}f zBdPU{l{-rv_uk>`Atbd!t?I7jnhnGPd_Ms3#ptP>LZ?g@{as#l{3pU-4|nc2|7)W(;jGOQBEcaTvHs!irJ|(*^C)`KI#gn0SWjv|LSLu#_VIPm5+`ruMOM^ ze9&!Cly@jRdi%Uy(jzuH_Wn5bMmZtA9^tSRwnzJ^HywMKAgRoNs$Kpwuo;fMD#seG z#I8}tH=LbjB7SVwx7eK(k9BZY=mH%r71$ftv!S_v!N++y2gz>q34kX@d4g#F5ocj% zdDhWl?B#mafU300Yv{8)5D&}ES=k(L@Oq{AnB3373II8KXl)GET8S|7xp6eg^)D6$k{&tKl+ou*Qz0g%AT+{dol5f+G=2L(dM|d ztCM=vD_pfhb_t_1VcCZY5s$LMKhnZp^!AIv{}?7Jzt>Snkh|~#eTZLy9B3;WjlAz3 zO?HcmUyxD7u(5;zF<7=Ymco`Z(dK@EQr3{W${-peuP5*|+rDf!(^{_2+*B~$r=;7L zDRNI0>OM`g0W2R}*rYbFH#@7&wiWo~C*UTFnD&y(oOqC)|LlZT2c7-i;w0O;w1o;h z59K2|gIvbNI^p1;OwYGXMC&?cOk?IGTQ$%mr`S1lY8KiS^ZJxUE^ZX*spkdADH;sO zWUI}9&~uP%-vBm$YJZkhk$lBQK**D*Q5Bj^xvUk9rp-|lz`||itVey5-C%m?3M>m- ze}KnAYV!NwfrpotQ(0maNfg@ZVn)J$PreS$@y2hOJkl)E6#%tpL6#j1Q-SdRE8yuzL8Dz221 z)jb}YTzy)dLdX70X+_{?qs6RKI8)t>H!kGOVEPqY=v!*C3=c|U*@?)7A#)UKD879Dn!4Q}pWt}|Z<*Sq>&O^I#j+qodTiA0h zJ5;MT0NI9vdNA|6etbqo(u*=ZK!(9xu#fdL-}{>A#f>v%*LY>w`e01v9xSuMm3Dl_DztnnZYSDi~z-#@hKFFM}L|a)C?2ZtE_I9GhXyj@_UhS z_0IMtd)zRI=_doCuwzPiQDT0w+xKi!%ce2*Qa&%(D}HG??9^eT%l00%K z9qp6=<&2V7({5Rkj=j^7XLa)mXIUDzM|mu}T@u(=YJ+d|9V9w@8~bPX<_fHeY!`e# z0-`_G6b|e)UTN_xu$RauGg|3jc|AL&ztTc#w(1M^YU3*T4aGz%ll_K$c|Y~duAd(Z z2d#Yt?7w#Ol9mjLNRPE{*o&M23w%x4p4bZ=e(%ebqT|>bM`i`~vaXOVn0Q<}`P=*L z`WEXk6H8rC((gSwRTDq|1bg9uK$72p=!`t}-Zu9+!@t8WLdrB{IZAM(t=Ze8&M^?~ zBsRY$cu3!*oCkQtAI1mG^u64cp?%kM-!t@qP5{tz90RGqhY8f2Og#MD!|x@zp!7`U zE&rY$4LrQmuYXJLZu=s%)IvHMCY$c&U8q^7;6lq}jtm=}OZaR=>fG}& ze$D%Epln9aOO zR5HR|;)%Usv`ywBH1Hz)U#^hjWxS8uRt`nVc)tJjU;pXtE07eJ8}=e;tU#|(1t@C$ zI$)h_z$xPVCJMeyaWYuE^T{G^y?e z`udF?ANi-!ZPsg@E|-aE7#EfyGB}yies2xzoq3q-cC-wPm0D88qzRyVW33OB)9Wma zH{?S!e)keo<^1mhXGNn#`WyiD@a@^58IV>| zRUNE0GxrB|s(e^ZCyvoN%)s8i{|gEamu7z>>)x@~Y?G#K;c#A=GN!in^9fqCFhF8s zP66y_IBk4y`UIpOaquDp#9;rx95GMYB;WupUo%eKmr zYNuQKCVfFm;c|5Fx02l^9&v}+bUVHynV^A==lQ|<2-f-^U3Q6=0^qj6V$e-BMtqb~ z_(wQegI|Z_&hMq_+AenZmXd}VXjvQW%8pYh z0#n>~t#t+wL$W(1EpRrSy-+NH+y@q#l2+JDXD;VF(Ptzci+#gUtxf<5EAydcE9u`E zD>igT2#O{M#a8aQ!<#-X^k*$&Oko4$5yuM}0m~{XY8TBK9WRCBHUxMJZuQx9S>X_$ zZOfyoA@Ug}rpQsrNVb;Lq2q4&d~Sv|dJYFP^45N|+E5t2C26HU{l10j@C$@d9Jy=p zrjF(5GbvVM3Jnpj$Ab4WHr~%lWjZ=+R48sd5#m38%?5f%xBwRJ#vLB6dCU$>Bw|{^ z*qLKn4IyRF9E^YTZ#Oam;(m^6gm_8|-}8`e6+|daKZDO5lE{xUjoQYaAZu@zUHjk` zhR8ED3STd&^o}-Q5dq|58|WyI14CLv zpsIfPeK>SssP|^!sKG|>e5%u2yBvxdhB8c=u{UaA*!wX(&HfGfk!pUtTzp|C)OOhrlz`OGYZe|DA6KyIlY`BeUl;Ct(LDFP?$g1{1+1#!ZH)e8Q zOGa8`Uj4zy0vu^LWxrMPeo_8?HXO;08OihQx@>;LGowVkmk>KomYznDit5pGXO=4? zHS!VVFzC9mY`_uDXA(t9BDVI1H+@JtONIFbieY6WJIBkQ2cXzy7y;fAd()tfb0OoI z;1q@-G?*o!1TRX`RGy8k0{MiKBzc4egO=6p)2d}hjjUWB(ttKcje$D$2DBq9u<;nh zQX4lUYqA^{c}Ff6}smJ%~BX4D;5ev3p8Ty;z*xCFOUu2Tg}c9-df4a~VHxqYIRLajV< z?3Lc>=-e2D2~1X1JWN@KyrXS9{PrW&PVDXTIiQq*hdm;yHqWyFppEBo>`i-b1?{bP z=CM>@EJrRKh=Hv5wheFsz{OVQvJhyKJw?e%)lazMF2910V{heAxLzB>p*3^r`2ynX za_gY4vLnj8zW5D9Nn4MY{<;)R)G@LMJ!^;93~K|4g{9)rsUg2t*hlL$^xMMxtuBlH z(asIW*k4hId`uoZ~hDY;4@Ibrd2lPWJ#oR9%LB_GEM%tElwFKpJimr zAA0o7C>k*%uP$;!xW8PNHKt{RTNp&H!!ux~Y9fT2LvXLfi;M1#^hklxmZ1##<9<|3 z6%TBEK#dSaqj4ZZhsdkK2KFM1NiWO7O`T9TI;|u>nkI}q=N+`(9nPq~LcOym&~jRU z@^k`o1-Xfg&ERaT&tKm82u&y+&epI^0Hon3B{!-Xo3+YC2r2&;%40LWW~+zLvn}w< zf1Zs`j`kI}*C$5cR_m zh7csdj#${fp4sGJq1Gssd_Ki4Of6Bzd6?dPNEbTF(TA5^1M^6R{6>Q~&y@--mM;I_YxIBC#AEl^mTDl|q(DHzmID@=S%2)-|v< z%E-;ar1()7i!^&BKrF}ovR#$`HtdaAixaI7n%tr(vJGfBM7mBk`{{Mr-bpq4u`FT( zfh)Z_)&`1B(rHtD6v?Zv6&@?Kkzm<)*NJ7vYy|cuEh2FU>qT!+xRYd+Ji6D?A;mjd zmDSBJ43w7IB&pTY+Rp}6QP_(Zh~W-eS1iNdT^m<5zrh7YW5?g{9lUa}QIeV+vz?QP z`r9&yN2sO!CCS@+5pfW!PQo zz-jI7FD|?B9qBO745s>?J*H7@_BGT7_vTU+Cn>1f&x7SV_trow*^R7}|L{?ylr7c9 z(dbyF{8o>Z+yuhbWKYyU;b&2rPNjl`jKwy2-hL15bSpC2T#^RONJdAY#Mt6lwZY^k zhz6o%(3W`WJh%lsnK~Hng!nPr_7rKUCK#msc3nbwXGP*}I1dA4lq*huJ1sSul25c6 zjI_jl@On0?B-2Urc9`AeRtqL8(g{FAF=X6?z{Ou`0Y7AqdMM>D$OCwrk^s}$)>a0P zohoMIs7-sU3P^961hKM4BP*&eD_eWtn1#ck>_ng(0O{GIw?;Lmx19){y=@jUU$IfF zf;NEV2Z`5cHS?bg%W-LTW^4dLb3m)ncmdIaJFN%5OA}IIQHG6`_iAuT$63>E^k+5c z8#ZX!R6;s6M}0BEgoN6fW%EAN>F?gq%LY4alg`rDQaQ&1u4~q(Fh`hYLE2GR7?p2G zXC=2#=O8BeM&>C78gl#i1~!&Tkn{ycY~5I&g~@5e@f+SA);SKghJonvdv@a^FQh{l za+WKInLjz)Zk4=gcJ%BN$WBjnd?=q%G92yZIVASxyDzevKMBi&C_(yE($d)zB_61k zXXoC{Hj3zhv+d^9ZCCx1U&V|JJlY`#4wYnR*u*rzcb(6EMqs2)-c+#vJtX>8tsd4~ zT$_cL^KL9();Xo9g^u!d7y8Sap%m$wh2GJVFlS<~>jr>~6ks{(E$i>4=qa2d!lPZ3 zpEFQa-EyY?jn|C=b}gl6IkA^b!dL#uApp zj=k55^< z;7`=HWACJz+8byalI9>|zT^+5?&4^ViM`*^ZnPC=Ki5vSk<%DR)m)|~irgy@vVkpm zj`wysdn-&Yzq-xxchpfTdIB&wj}74C*n0yZenu}uI`;arlTS)zYSud zoO?bZzWe-o@q33XWyIPs82bf#82Fc1&aH z@JlWM3`bF{JTW>qWH8pP27m>Gaol@OPxCY;n8{U8I0PLqx)!Hzs-0$`MoWi)bRap* zfRaE)VNQ_`#i3`t4jzT!U{c4kC|s!~W@~KZj%H>G;6h*{AFj`p62y*djcb7kLd&5- zB-*xnfDLV*jzNtqv2i4x<_J(JX#>S9N7^3+a$O)jMw}DXF=;3p?Y!3Ag>i8ka9yH& z54B?BKN6G@H^-BKu|E#*uS}+?Az6$A4+m3{*`Xof&-qdHYK z{gLV76%SdHc+8L0)99+=`FG6F+L8(lvZ^H6-74Mpv#$y_3R8Q!P4R~zr|JZWAZHT- zdn0XYx>pi(+?5S9oF`wY=~W~8HQTmZbi-aG4hYTs7ZBZP4Ec=^?i7m|!u1NOe}KKC zaua()ZelpKjh!`drAC-`K!A)EiVij_lU%Z+2fazP!*)?t@Iq5Kx&9F_TTKpVU~d+h z4tx0msVL1)sD_qYzxsl`IiRKuk2N=@2_1-~Sr`{p_SFWA_eZ*J(+`>Bfy7xXVXq>N zFtI^rX+qeuPP;=Hmb)?Jqmjc{S@Nju-Mwzy@hR-BbXVC0N~jxIEGL0hHe-sd(2t%S zt#P#?h*bys$$bbrY9uIfhCS$E9ZPv501`s|vw7+P$pY&^ZBAKhX@jmjZ**zPyC%9u zyS{RR=nj9B#hh$z`+If3^t?~K%?}fMuN}kDDFtHUb|X3>%lT^25ij-nX8J(wa-?@2 zH~FRZxMn|IGz0hrE52N3$275zEgAB6n2eJ+QobVuB?RjFh5e#gi1zvw0LTSN?`08R z$UvYwMdgZc{la+GeXG5L;YWN{2(*?YXb6R3V?qMi>T;Q>ZSPmkWuyRGCqfFmo!qbO zPL?$SH-zh)MvyP<&&No1N z8LqlJ!G*44hhwTA9+ znr=X^QlY`Hwy^=K-7WqbxiRAe9css6RoZ^F`ej}nPZ-q>+HsLx7t$0PuJ+-@iY3-b9G_Tt1|!MV|Xmw)yfJ@Oa+dgN3GiePzas~okazohXc-`>e)xj8*SIUR6w_%6# zL*x7G23MB1V*CepP+|?Fz3MVd=*h2rIZwSgiz7@`AVxRCKbb6V2sdZ#yxz5Yar{%* zn>OJrzSW!UWxiUHyERMT)Sa?>4YLiHPXjZZ<|UG+Hs=yDps-iqof)f@4YVql>R6g} zP(pxagVoi(#Q|yfAfl+n*)C*MUc0W?tLXAN={lo?c)&8}s%}Qli1+tO$9Wd^)}~be z;_szX8g;Gq&_m2_cO8$r{jeuQxQy>7`v#WX%Ns@3*O~V8S>LbGG5uGTP_70SfSz?L z?qNLw*Oc`>G>L)n45 zjj(W`s-T57h#3lNg@JUOPdK_tYm>O`nyqjF5o)cb{6q?WJo%WNP_jC##nDzY)7(N! z1D{l>9Lv{OeyApuUU`%*Pu>zC^j;ya5pw++c|>^1w^7NoH(f?EH!X(}0<871jv|CQ z*!TSBOLTM)9q)NSiQa;WO?403ZNKL_t*Dsi>zkc%_#$WRPJBvc^CEf{;yJ!dY4#(+N6=`XB4tnTU+OqyBcWSx_bsY($uH7r0 zz}R$|+Ta%vtC@^uI{ppp6?!gu7s=z{O^-&JYev02(^QM(rgOF-`dtQr>WEkNY%Aqj zha2{?YZi{E&Gt~1j=gR0893yj%}C|v7yqZdvHZ$Ua{W@Zd_M7=)Y-zVy38Xk>z6f+ zkw4k}ksz59{^* zc>S^^e%6MuzLJ{rdI_j4Z}i>1aa?5}kQg~p_|DCNz2zHbG*|K}1~2&{o*qCW2j2_Y zU52!VXKKk$N;ui(k+mwl^h`<47_!r&&2I+zRMu6V>5u)sVDI#MQKsW;q434NwcSzS zH&I19az>7q_wTMn4?`DnLs{ALtD^mSec4Cx4|4h~NzRY}Zw8Aq;vRLAQ65zmfvlA? zm4>gS)Een8#)OMY(a-e5IORf^KDwI_mAZSb>4erdJeprTpufN1hPolE(tAV4bp9O0 zZd*SyZT9js?nGDa=Gb$jy!lxN2amP72>n@7gvUr$6wvaRYBZ^lFP2uPN5-^i{w{MW zCs}`Vg_iMuFDXf8LP%nLq2Zz#{XuGlq;sb!J1+b^7w-czpuquudEJcU^&;GD-p@Cyqx45N)!r5|ZhO()r{F1x~@xp0t4!Z()9DDu9 zmvF^y5f1s`TbWsf!qcjswlCVR!GbY0c6?RoaHN~Z$INV-(??n6qc`l87?{<}{B`^! zq~nPA_>R3NVTHYbbuyPMtj{OUfZked8gf&jNS1@~BXGuxl5{ewu9nC)aj8vVHJd+< zw@U0b<6tu*FN1Q~ssnrNj-xH;3+G|l)Y#A`YYfcjwhVdQgXeiW8b1G%;+qy0s6@=c zz(mgDXy02~vwrgTCGYCxm)t4+ow_&j);<8y+y9FVxXGr_f1tAU_RV`;6Hi?>KcBy{ zQ@S@{ZE*PNH}nak)UA9l=tx{R_xcdeJGecd7ra)w-i4eJt~S4S;vrw;_eQ&F@dgrp zuhoAEXlLcpjWLpj!$I}OtKAc@MiWj73GaeOUm=PK1Jg3(b`o~E)yuE)rRkf)988=X zubS+}!#C{J{#}%(=Qkp#WgvfWy_{njAjHkj)N7d6w50PzE-gO*FuR!F9UjKZo)F`gNb7P{+jzO%$hGcAh@YiQnBsLtl z87>xtSa(X+UvPe>dM+g<+V+lhn~K%iCjyx#34%8BbWsMKkE8xB3*vN@&r}Qit9EW^ zkIVSmcQU*wl(b*{?FkLH?`}o&*Q$Vcn4CrNjALMEO>95&6ZxA5T-a}q4fuNJt17en zT+W<9*IP}?0NDVGcL?>`vYqtc^Sw0>vs8wOk&9o4;i&qUWAsi25z`Bf5Mei1x!Wcg z*pm6XvvF*Te#p=mKFf1`H36B-DJ)t7$>-9~VSrqf+k{vDCJO8J^SDkiW1G5dsY*BU5BTG>rTbzvr66rQi!)~H}YrHTdVwj{70`^ znKb6!HMkVPzkH{aNjThPOSJNTb%NvF3*P}~?05`DjxUZ&R3Arz-!FylLS12dlyk9F z4XfsHCX{F z^VinxJIB&$47b`ApfeQeRdz4sBp$%Odk|}PC;o*jq>T%E(6aT;dK{6eT@P3vg72q< zdkX0(&-%Pw{EZPKfNktF(w*xHyUk8s3>*gJ?)Q3S_P}1xtpA-q!KRkVzKuUcE{)T*T@&&)|p*$Q`3Z5D+#IRaK@Tk`f>c%K(R z>#nuQs*iko?;$oDI{EE`DdA(Nr)rKt>7cYH@1%W~Uo@|_mgjYx`PL!>>2L1Akli~z z|EYnGuU`HAvB6+136XN+Xphnb_-<@)^SJYV<}a zv@Usb8NAk`65(uB4cdNyikhJ!d2V&qz+T6F$(-6|j8jrl$6l`)$ohhznYaH}fHyj1 zzh75RPFQ{q$@>LgXJ(gYOrL_z7nRd*xD_+-ChZQLQ%X7ZPpM7s1W)2`+I{6c1C6LbIL`@eeP4! zT0!X(F}rvJ(7=D~JZwwda%603jN0sc&Fsip`qR^A|NT1VR*yJ+ozz`Si{2RW_8u1xmn1CE`Otnyd#xK_x9a+4>jVAa>yA4VTX)zqC+c(Y`oF*#((;K^_R*x z9RpITK>XOT2 zmOTKD>_)@W6b{DN3-{S!Wtt??s^|3v_p zlIB1K_WjmAf6{*19^FjOSJ~Y-vU?Q~8GlI@i+30LBxE#Zb$v+-^PXfx4&MHW+;aK9 zU0wIur&~)lc!>>X+csbuIj3s8FmT|t`Mn{({&!+z@Ixa_N#-Y0bsinu%YV4CR9F99 z-%UK>+!%YSyr7+*RJTHV`4d}MFEE}5?Rt6EXr1}Z%V|&3I|czSUmW>Gxra)X{MPM7 z7p}DaT6q7INNJY+J>SFAmX^{O zCsPmGC5RB4*pA%t;hcD6DmtHJ(=mg`?p$+4AsxRH#tj-B-BQ3z?Lhm-MvBv(aj&8==Aw^1J*n%@eFb`YU;CKLioWghLJ zlqiqOngza~wYbbGZK~lqX-9sr)hqp~G)TokrV1wZ0i($=BskZ_bErV(jI-(e(K> zvp+T{$hI+Y&^kT@wtkrPI{6>6qBXd>+$L2!z4P!+_?z!=TATBV)2k)*DSWwvodZ1m z;pklP{>IIwC!@|Q{NA+|_I?KTdK!|kwv%)yi1G>CO2@nuZBW-LVeIW2iUvJ&i|nY< zT7_Uo`VAyJximVsda(aCCt3o^^4s|YoXhBLc49ui+3}(`chPS8E9EP|WOwe;0GC~> zql`!-Ed~3;$TGkNtfLp^B1={rv6fGp7IQ-~YCr!^uf{`RV=l<$Bd!ZAoN2 zyZz3E&WA7cCp!lBJhcHg8|@nq>G%e}rZsAXisf`t+K2frgz{bq7TjB@MV?ai1k7bX zyP~`TZ>Q~h5Zn9J`4$hQzl*aX2VX6erHoNJMhRlQ<+o>@xxC8W`QpW|&Tp2S<@N7o zzVW+8D#?|u-xIj<-EdqS?E45H>*olGY=3Wew`*>uFop45(=^lHQ-3QvRpd_gQA&4$ zw6oz?-Bc>jtJj3)C5zy3h%B9Ly7$K3yO$x=&bbkbDzG^q)&~QWX#cky`;wP?M@bSg zS0ZKaT=nlpr5U>fh#7q$XHS;Y;%F}Vjbi5+%RkqJ;i@)#;B~vRQ5Y`@@=_LcHs-yN z)yw%!_FDS!T7a{tkyc*mzyDXmMgQ)9D4du!Q>q`r+J5}F`VI+6O%yT7`=4w*OxQ;#bMxIF%ff-wkbQk?R5Cab^x zUv$FXHuwD1c00*5G2Z?wGQRi@p=-gf8;1Tyz%L(0Xm9SSs)W6R#t4~h*gNV{m!ymp z#{5S74SP@eyZ5!TEv}e-xvUTHdu`!%+97z=aBN8vyNPx zKUYQDm?)bl5)Y^2T*(;aXzI6Z#plNpG$JSarV>CCbj zSh$L!9!e$Y6t@|wjz5Fa*(Mhv;dPwNgpn81c4k30zD6XB%4KPuj{3i5NB2C-5$BYa zlNm)bKTb}ZAm*knM=gu-b?(`qWH3hg+3aXgUe!3Aif^zIDQd^S{#9)xmgd%OMX|Jg z3w?7f`{gpHrnblDZe4D`lrKqW2%BQiWy3eHdVnSrG3(*KzppntC`8U2DG{T+&V{|w zAgH%R@G`*$R}M)?&2Gv_(Es_o=gA$L3$+p+iC6{FJ4wj>W{Yzz_C0)!2U(JtO}$B~FXWE9cU((+$r-q^dyE?)x(uFu!bY*NZO7Zd z^Tvj%kFg_OuJ-;;Kh-(ebBSphvy##1%_g?8E<8$HztMB)zR6^UM-6Pv{y^=xsh;_7 za@+N-u$LDag6!_)^NZ|8HB#pzU7XAOg1uG$7fA}9srCmzqb{&lu@9Q%_{DAYV*lcw zz}}_FBeP3%WJ%PEV36BG0c=>rm0_<^{`R+O#CjKWP6J+s?!;c#uVytBJfLxL7sh?i zMNSaq^=)_O8}{aH&eFvm3Dq%5%G7Z^!qYgDW*2-SPyB0w$SeoLZ%qG5GcC(+tP5{v zpQml?@;hzCixd@>w_U4wzlpm0Kf>PDDUC9M2Abi|YD76P;HR^o{1!ms4P#`hXHYg_ z@Qc2;Mx&-axT*Dxw(oA`{eE3{<+bv=fZ2;XWB5yL9jan%%e+#1wpCVvFxTRHjc%J0 zeWUSZJ6fYOHb&^LD0IQuV7)>nB12_@raHFZn^RJ#lkLaxrV1qJX$dYX6)UD>-3HGk zl(PWhTr>}`FozIJ3!i0^Bb2rjwT+Zdd3m+T?nEp}!H?fgEY*|pqO#1fLpu2@cf5_{ z(YBM1A@Q??Tz*NL&F(3G)}6;CzF$=&xLv7X*|fKgMnKZd#B`{2lTTuO3$g!-Ls6N9 zw$4(Tn)i9MCJM6mMbBxHeJDkYcS;p|oTbevDC03f_SG}B$u9U+;7Tig3J`!CIY z5q;=w4D1W`p4s!W!rtze0AbUO-oE>_mHcOgT;6y-F<`ky%0R5QJi1}9IuLf;*I*>8wcqO41$qc(Upb}K(>$aVF<(lj&axqJet$ z?K7?PmaBikQq^jhsGvZcyINWFHaMzHK2J4)a3l7Q6F()}EFQ@KiW7VNpJr1o@;hj} z?jxIREAG#9EA-#Jj*e;VMmq{_;?B?OPA()V0{{el0|7QZo1>gml5sp2bnJ+BfU)3S99h|8T`wsg{VZ*kDN6%@|lYY!LikAp=f^ zN3m_KpjR@(xD3;?@<0~>;F{?b8mLz?_(An2)bI!d!x@&c-S zSy-Ps#%^P0IFP8XZw1^SD7EQnd^8`EQn%(gBPOPB+@w@qZ{mU1an6=ckO#NV?O=|V z>yY0`ujlF>U(<7430<3Z++IuY(HK|(86N*qK-d%om5VF~`nrDP8M++_vO_*Xy)0YJ zmif*E{{3#)WTcEAncITZ&elDZ^+He+t!Z>G`J{vHcEf3{ok~M?0bZsNPWye$l>%7! zd_KN`8euO4F|b#bkcqoVn(y+Rm6P#@%0DI?ZZh|#L4@5D+AT-A*RMzJzhG~sAGjLD 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 literal 0 HcmV?d00001 diff --git a/web-clients/hearts/dist/card_atlas.json b/web-clients/hearts/dist/card_atlas.json new file mode 100644 index 00000000..638bbb9c --- /dev/null +++ b/web-clients/hearts/dist/card_atlas.json @@ -0,0 +1,322 @@ +{ + "image": "cards.png", + "size": { + "w": 1066, + "h": 944 + }, + "format": "array", + "frames": { + "hearts_A": { + "x": 0, + "y": 7, + "w": 105, + "h": 151 + }, + "hearts_2": { + "x": 105, + "y": 7, + "w": 110, + "h": 151 + }, + "hearts_3": { + "x": 215, + "y": 7, + "w": 106, + "h": 151 + }, + "hearts_4": { + "x": 321, + "y": 7, + "w": 103, + "h": 151 + }, + "hearts_5": { + "x": 424, + "y": 7, + "w": 109, + "h": 151 + }, + "hearts_6": { + "x": 0, + "y": 164, + "w": 105, + "h": 151 + }, + "hearts_7": { + "x": 105, + "y": 164, + "w": 110, + "h": 151 + }, + "hearts_8": { + "x": 215, + "y": 164, + "w": 106, + "h": 151 + }, + "hearts_9": { + "x": 321, + "y": 164, + "w": 103, + "h": 151 + }, + "hearts_10": { + "x": 424, + "y": 164, + "w": 109, + "h": 151 + }, + "hearts_J": { + "x": 0, + "y": 322, + "w": 105, + "h": 151 + }, + "hearts_Q": { + "x": 105, + "y": 322, + "w": 110, + "h": 151 + }, + "hearts_K": { + "x": 215, + "y": 322, + "w": 106, + "h": 151 + }, + "clubs_A": { + "x": 533, + "y": 7, + "w": 111, + "h": 151 + }, + "clubs_2": { + "x": 644, + "y": 7, + "w": 108, + "h": 151 + }, + "clubs_3": { + "x": 752, + "y": 7, + "w": 105, + "h": 151 + }, + "clubs_4": { + "x": 857, + "y": 7, + "w": 104, + "h": 151 + }, + "clubs_5": { + "x": 961, + "y": 7, + "w": 105, + "h": 151 + }, + "clubs_6": { + "x": 533, + "y": 164, + "w": 111, + "h": 151 + }, + "clubs_7": { + "x": 644, + "y": 164, + "w": 108, + "h": 151 + }, + "clubs_8": { + "x": 752, + "y": 164, + "w": 105, + "h": 151 + }, + "clubs_9": { + "x": 857, + "y": 164, + "w": 104, + "h": 151 + }, + "clubs_10": { + "x": 961, + "y": 164, + "w": 105, + "h": 151 + }, + "clubs_J": { + "x": 752, + "y": 322, + "w": 105, + "h": 151 + }, + "clubs_Q": { + "x": 857, + "y": 322, + "w": 104, + "h": 151 + }, + "clubs_K": { + "x": 961, + "y": 322, + "w": 105, + "h": 151 + }, + "diamonds_A": { + "x": 0, + "y": 479, + "w": 105, + "h": 151 + }, + "diamonds_2": { + "x": 105, + "y": 479, + "w": 110, + "h": 151 + }, + "diamonds_3": { + "x": 215, + "y": 479, + "w": 106, + "h": 151 + }, + "diamonds_4": { + "x": 321, + "y": 479, + "w": 103, + "h": 151 + }, + "diamonds_5": { + "x": 424, + "y": 479, + "w": 109, + "h": 151 + }, + "diamonds_6": { + "x": 0, + "y": 636, + "w": 105, + "h": 151 + }, + "diamonds_7": { + "x": 105, + "y": 636, + "w": 110, + "h": 151 + }, + "diamonds_8": { + "x": 215, + "y": 636, + "w": 106, + "h": 151 + }, + "diamonds_9": { + "x": 321, + "y": 636, + "w": 103, + "h": 151 + }, + "diamonds_10": { + "x": 424, + "y": 636, + "w": 109, + "h": 151 + }, + "diamonds_J": { + "x": 0, + "y": 794, + "w": 105, + "h": 150 + }, + "diamonds_Q": { + "x": 105, + "y": 794, + "w": 110, + "h": 150 + }, + "diamonds_K": { + "x": 215, + "y": 794, + "w": 106, + "h": 150 + }, + "spades_A": { + "x": 533, + "y": 479, + "w": 111, + "h": 151 + }, + "spades_2": { + "x": 644, + "y": 479, + "w": 108, + "h": 151 + }, + "spades_3": { + "x": 752, + "y": 479, + "w": 105, + "h": 151 + }, + "spades_4": { + "x": 857, + "y": 479, + "w": 104, + "h": 151 + }, + "spades_5": { + "x": 961, + "y": 479, + "w": 105, + "h": 151 + }, + "spades_6": { + "x": 533, + "y": 636, + "w": 111, + "h": 151 + }, + "spades_7": { + "x": 644, + "y": 636, + "w": 108, + "h": 151 + }, + "spades_8": { + "x": 752, + "y": 636, + "w": 105, + "h": 151 + }, + "spades_9": { + "x": 857, + "y": 636, + "w": 104, + "h": 151 + }, + "spades_10": { + "x": 961, + "y": 636, + "w": 105, + "h": 151 + }, + "spades_J": { + "x": 752, + "y": 794, + "w": 105, + "h": 150 + }, + "spades_Q": { + "x": 857, + "y": 794, + "w": 104, + "h": 150 + }, + "spades_K": { + "x": 961, + "y": 794, + "w": 105, + "h": 150 + } + } +} \ No newline at end of file diff --git a/web-clients/hearts/dist/cards.png b/web-clients/hearts/dist/cards.png new file mode 100644 index 0000000000000000000000000000000000000000..4c7e9c1cb6045373d4f0ec4c2794a0017a42253b GIT binary patch literal 82966 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 - +

-

Connect to Hearts Game

+

Hearts Game

- - + +
+ + +
+ + + + +

diff --git a/web-clients/hearts/src/game/HeartsGame.ts b/web-clients/hearts/src/game/HeartsGame.ts index 2ef7aba8..a0322324 100644 --- a/web-clients/hearts/src/game/HeartsGame.ts +++ b/web-clients/hearts/src/game/HeartsGame.ts @@ -10,9 +10,12 @@ export class HeartsGame { private ui: GameUI; private playerId: string = ''; private playerPositions: Map = new Map(); // Maps playerId to position (0-3) + private playerNames: Map = new Map(); // Maps playerId to player name private passingPhase: boolean = false; private myTurn: boolean = false; + private currentTrickNumber: number = 0; + private currentRoundNumber: number = 1; constructor(scene: CardScene, ui: GameUI) { this.scene = scene; @@ -111,6 +114,7 @@ export class HeartsGame { // Use the authenticated user's ID, not the passed-in playerId this.playerId = userData.id; + this.playerNames.set(this.playerId, playerName); // Track our own name console.log('Using player ID from auth:', this.playerId); this.ui.setConnectionStatus('Authenticated. Connecting to game...'); @@ -251,6 +255,7 @@ export class HeartsGame { console.log('🎮 Game started event received!', data); this.ui.showMessage('Game started!'); this.ui.setStatus('Game in progress'); + this.ui.showDevLog(); // Show developer log when game starts if (data.playerViewOfGame) { this.updateGameState(data.playerViewOfGame); @@ -314,6 +319,19 @@ export class HeartsGame { this.client.onPlayerPlayedCard(async (data) => { console.log('Player played card:', data); + // Detect if this is the start of a new trick (no cards on table) + if (this.scene.currentTrickCards.length === 0) { + this.currentTrickNumber++; + this.ui.logNewTrick(this.currentTrickNumber); + } + + // Get player name and format card + const playerName = this.playerNames.get(data.playerId) ?? 'Unknown'; + const cardStr = this.formatCard(data.card); + + // Log to dev console + this.ui.logCardPlay(playerName, cardStr); + // Skip if this is our own card - playCard will handle the animation if (data.playerId === this.playerId) { console.log('Skipping notification for our own card - animation handled by playCard'); @@ -330,6 +348,14 @@ export class HeartsGame { this.client.onTrickCompleted(async (data) => { console.log('Trick completed:', data); + + // Find the winning card + const winningPlay = data.trickCards.find(tc => tc.playerId === data.winnerId); + const winningCardStr = winningPlay ? this.formatCard(winningPlay.card) : 'Unknown'; + + // Log trick result + this.ui.logTrickResult(data.winnerName, winningCardStr, data.points); + this.ui.showMessage( `${data.winnerName || 'Player'} won the trick! (+${data.points} points)` ); @@ -351,6 +377,13 @@ export class HeartsGame { message = `${data.moonShooterName} shot the moon!`; } + // Log round end + this.ui.logRoundEnd(this.currentRoundNumber); + + // Reset trick counter for next round + this.currentTrickNumber = 0; + this.currentRoundNumber++; + this.ui.showMessage(message, 5000); this.ui.setStatus('Round ended. Waiting for next round...'); @@ -398,6 +431,7 @@ export class HeartsGame { state.otherPlayers.forEach((player, index) => { // Opponent positions: 1 (left/west), 2 (across/north), 3 (right/east) this.playerPositions.set(player.playerId, index + 1); + this.playerNames.set(player.playerId, player.name); this.scene.updateOpponentCards( player.playerId, @@ -504,6 +538,12 @@ export class HeartsGame { console.log('Player ID:', this.playerId); console.log('My turn:', this.myTurn); + // Detect if this is the start of a new trick + if (this.scene.currentTrickCards.length === 0) { + this.currentTrickNumber++; + this.ui.logNewTrick(this.currentTrickNumber); + } + const response = await this.client.playCard({ playerId: this.playerId, card: card, @@ -515,6 +555,12 @@ export class HeartsGame { this.ui.showMessage(`Error: ${response.error}`); } else { this.myTurn = false; + + // Log our own card play + const playerName = this.playerNames.get(this.playerId) ?? 'You'; + const cardStr = this.formatCard(card); + this.ui.logCardPlay(playerName, cardStr); + // Use animated card play instead of instant removal await this.scene.playCardWithAnimation(card, 0); // Current player position this.ui.setStatus('Waiting for other players...'); @@ -525,4 +571,21 @@ export class HeartsGame { this.ui.showMessage('Failed to play card'); } } + + private formatCard(card: Card): string { + const rankNames: { [key: number]: string } = { + 1: 'A', 11: 'J', 12: 'Q', 13: 'K' + }; + const rank = rankNames[card.rank] || card.rank.toString(); + + const suitSymbols: { [key: string]: string } = { + 'Hearts': '♥', + 'Diamonds': '♦', + 'Clubs': '♣', + 'Spades': '♠' + }; + const suit = suitSymbols[card.suit] || card.suit; + + return `${rank}${suit}`; + } } diff --git a/web-clients/hearts/src/ui/GameUI.ts b/web-clients/hearts/src/ui/GameUI.ts index 6c3dac8c..cb01519f 100644 --- a/web-clients/hearts/src/ui/GameUI.ts +++ b/web-clients/hearts/src/ui/GameUI.ts @@ -11,6 +11,10 @@ export class GameUI { private turnStatusEl: HTMLElement; private connectionStatusEl: HTMLElement; + private devLog: HTMLElement; + private devLogContent: HTMLElement; + private currentTrickNumber: number = 0; + constructor() { this.connectionPanel = document.getElementById('connection-panel')!; this.gameInfo = document.getElementById('game-info')!; @@ -23,6 +27,13 @@ export class GameUI { this.passDirectionEl = document.getElementById('pass-direction')!; this.turnStatusEl = document.getElementById('turn-status')!; this.connectionStatusEl = document.getElementById('connection-status')!; + + this.devLog = document.getElementById('dev-log')!; + this.devLogContent = document.getElementById('dev-log-content')!; + + // Setup clear button + const clearButton = document.getElementById('dev-log-clear')!; + clearButton.addEventListener('click', () => this.clearDevLog()); } public showConnectionPanel(): void { @@ -91,4 +102,58 @@ export class GameUI { const button = document.getElementById('connect-btn') as HTMLButtonElement; button.disabled = !enabled; } + + public showDevLog(): void { + this.devLog.classList.remove('hidden'); + } + + public hideDevLog(): void { + this.devLog.classList.add('hidden'); + } + + public clearDevLog(): void { + this.devLogContent.innerHTML = ''; + this.currentTrickNumber = 0; + } + + public logNewTrick(trickNumber: number): void { + const entry = document.createElement('div'); + entry.className = 'log-entry log-trick-header'; + entry.textContent = `=== Trick ${trickNumber} ===`; + this.devLogContent.appendChild(entry); + this.currentTrickNumber = trickNumber; + this.scrollToBottom(); + } + + public logCardPlay(playerName: string, card: string): void { + const entry = document.createElement('div'); + entry.className = 'log-entry log-card-play'; + entry.textContent = `${playerName} played ${card}`; + this.devLogContent.appendChild(entry); + this.scrollToBottom(); + } + + public logTrickResult(winnerName: string, winningCard: string, points: number): void { + const entry = document.createElement('div'); + entry.className = 'log-entry log-trick-result'; + entry.textContent = `→ Winner: ${winnerName} with ${winningCard} (+${points} pts)`; + this.devLogContent.appendChild(entry); + this.scrollToBottom(); + } + + public logRoundEnd(roundNumber: number): void { + const entry = document.createElement('div'); + entry.className = 'log-entry'; + entry.style.color = '#ff00ff'; + entry.style.fontWeight = 'bold'; + entry.style.marginTop = '12px'; + entry.style.marginBottom = '12px'; + entry.textContent = `========== Round ${roundNumber} Ended ==========`; + this.devLogContent.appendChild(entry); + this.scrollToBottom(); + } + + private scrollToBottom(): void { + this.devLogContent.scrollTop = this.devLogContent.scrollHeight; + } } From 99f7e402e7f1b88ff67b9df4564a86ae7f884cda Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 13:43:53 +0200 Subject: [PATCH 18/26] wip --- .../Games/Bullshit/BullshitClient.g.cs | 16 +++++------ .../Games/ChatRoom/ChatRoomClient.g.cs | 4 +-- .../Games/CrazyEights/CrazyEightsClient.g.cs | 16 +++++------ .../Games/Gabong/GabongClient.g.cs | 20 ++++++------- .../Games/Hearts/HeartsClient.g.cs | 8 +++--- .../Games/Idiot/IdiotClient.g.cs | 28 +++++++++---------- .../Games/TexasHoldEm/TexasHoldEmClient.g.cs | 16 +++++------ src/Deckster.Client/Games/Uno/UnoClient.g.cs | 16 +++++------ .../Games/Yaniv/YanivClient.g.cs | 8 +++--- .../Generators/CsharpClientGenerator.cs | 4 +-- 10 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/Deckster.Client/Games/Bullshit/BullshitClient.g.cs b/src/Deckster.Client/Games/Bullshit/BullshitClient.g.cs index 39f7bebe..755db2b3 100644 --- a/src/Deckster.Client/Games/Bullshit/BullshitClient.g.cs +++ b/src/Deckster.Client/Games/Bullshit/BullshitClient.g.cs @@ -109,7 +109,7 @@ public static class BullshitClientConveniences /// public static Task PutCardAsync(this BullshitClient self, Card actualCard, Card claimedToBeCard, CancellationToken cancellationToken = default) { - var request = new PutCardRequest{ ActualCard = actualCard, ClaimedToBeCard = claimedToBeCard }; + var request = new PutCardRequest{ PlayerId = self.PlayerData.Id, ActualCard = actualCard, ClaimedToBeCard = claimedToBeCard }; return self.SendAsync(request, false, cancellationToken); } /// @@ -117,7 +117,7 @@ public static Task PutCardAsync(this BullshitClient self, Card ac /// public static async Task PutCardOrThrowAsync(this BullshitClient self, Card actualCard, Card claimedToBeCard, CancellationToken cancellationToken = default) { - var request = new PutCardRequest{ ActualCard = actualCard, ClaimedToBeCard = claimedToBeCard }; + var request = new PutCardRequest{ PlayerId = self.PlayerData.Id, ActualCard = actualCard, ClaimedToBeCard = claimedToBeCard }; var response = await self.SendAsync(request, true, cancellationToken); } /// @@ -125,7 +125,7 @@ public static async Task PutCardOrThrowAsync(this BullshitClient self, Card actu /// public static Task DrawCardAsync(this BullshitClient self, CancellationToken cancellationToken = default) { - var request = new DrawCardRequest{ }; + var request = new DrawCardRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -133,7 +133,7 @@ public static Task DrawCardAsync(this BullshitClient self, Cancell /// public static async Task DrawCardOrThrowAsync(this BullshitClient self, CancellationToken cancellationToken = default) { - var request = new DrawCardRequest{ }; + var request = new DrawCardRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return response.Card; } @@ -142,7 +142,7 @@ public static async Task DrawCardOrThrowAsync(this BullshitClient self, Ca /// public static Task PassAsync(this BullshitClient self, CancellationToken cancellationToken = default) { - var request = new PassRequest{ }; + var request = new PassRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -150,7 +150,7 @@ public static Task PassAsync(this BullshitClient self, Cancellati /// public static async Task PassOrThrowAsync(this BullshitClient self, CancellationToken cancellationToken = default) { - var request = new PassRequest{ }; + var request = new PassRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); } /// @@ -158,7 +158,7 @@ public static async Task PassOrThrowAsync(this BullshitClient self, Cancellation /// public static Task CallBullshitAsync(this BullshitClient self, CancellationToken cancellationToken = default) { - var request = new BullshitRequest{ }; + var request = new BullshitRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -166,7 +166,7 @@ public static Task CallBullshitAsync(this BullshitClient self, /// public static async Task CallBullshitOrThrowAsync(this BullshitClient self, CancellationToken cancellationToken = default) { - var request = new BullshitRequest{ }; + var request = new BullshitRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return response.PunishmentCards; } diff --git a/src/Deckster.Client/Games/ChatRoom/ChatRoomClient.g.cs b/src/Deckster.Client/Games/ChatRoom/ChatRoomClient.g.cs index 7eb3be91..a5f89e92 100644 --- a/src/Deckster.Client/Games/ChatRoom/ChatRoomClient.g.cs +++ b/src/Deckster.Client/Games/ChatRoom/ChatRoomClient.g.cs @@ -51,7 +51,7 @@ public static class ChatRoomClientConveniences /// public static Task ChatAsync(this ChatRoomClient self, string message, CancellationToken cancellationToken = default) { - var request = new SendChatRequest{ Message = message }; + var request = new SendChatRequest{ PlayerId = self.PlayerData.Id, Message = message }; return self.SendAsync(request, false, cancellationToken); } /// @@ -59,7 +59,7 @@ public static Task ChatAsync(this ChatRoomClient self, string mess /// public static async Task ChatOrThrowAsync(this ChatRoomClient self, string message, CancellationToken cancellationToken = default) { - var request = new SendChatRequest{ Message = message }; + var request = new SendChatRequest{ PlayerId = self.PlayerData.Id, Message = message }; var response = await self.SendAsync(request, true, cancellationToken); } } diff --git a/src/Deckster.Client/Games/CrazyEights/CrazyEightsClient.g.cs b/src/Deckster.Client/Games/CrazyEights/CrazyEightsClient.g.cs index 359f4b3e..736d0906 100644 --- a/src/Deckster.Client/Games/CrazyEights/CrazyEightsClient.g.cs +++ b/src/Deckster.Client/Games/CrazyEights/CrazyEightsClient.g.cs @@ -101,7 +101,7 @@ public static class CrazyEightsClientConveniences /// public static Task PutCardAsync(this CrazyEightsClient self, Card card, CancellationToken cancellationToken = default) { - var request = new PutCardRequest{ Card = card }; + var request = new PutCardRequest{ PlayerId = self.PlayerData.Id, Card = card }; return self.SendAsync(request, false, cancellationToken); } /// @@ -109,7 +109,7 @@ public static Task PutCardAsync(this CrazyEightsClient self, C /// public static async Task<(List cards, Card topOfPile, Suit currentSuit, int stockPileCount, int discardPileCount, List otherPlayers)> PutCardOrThrowAsync(this CrazyEightsClient self, Card card, CancellationToken cancellationToken = default) { - var request = new PutCardRequest{ Card = card }; + var request = new PutCardRequest{ PlayerId = self.PlayerData.Id, Card = card }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentSuit, response.StockPileCount, response.DiscardPileCount, response.OtherPlayers); } @@ -118,7 +118,7 @@ public static Task PutCardAsync(this CrazyEightsClient self, C /// public static Task PutEightAsync(this CrazyEightsClient self, Card card, Suit newSuit, CancellationToken cancellationToken = default) { - var request = new PutEightRequest{ Card = card, NewSuit = newSuit }; + var request = new PutEightRequest{ PlayerId = self.PlayerData.Id, Card = card, NewSuit = newSuit }; return self.SendAsync(request, false, cancellationToken); } /// @@ -126,7 +126,7 @@ public static Task PutEightAsync(this CrazyEightsClient self, /// public static async Task<(List cards, Card topOfPile, Suit currentSuit, int stockPileCount, int discardPileCount, List otherPlayers)> PutEightOrThrowAsync(this CrazyEightsClient self, Card card, Suit newSuit, CancellationToken cancellationToken = default) { - var request = new PutEightRequest{ Card = card, NewSuit = newSuit }; + var request = new PutEightRequest{ PlayerId = self.PlayerData.Id, Card = card, NewSuit = newSuit }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentSuit, response.StockPileCount, response.DiscardPileCount, response.OtherPlayers); } @@ -135,7 +135,7 @@ public static Task PutEightAsync(this CrazyEightsClient self, /// public static Task DrawCardAsync(this CrazyEightsClient self, CancellationToken cancellationToken = default) { - var request = new DrawCardRequest{ }; + var request = new DrawCardRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -143,7 +143,7 @@ public static Task DrawCardAsync(this CrazyEightsClient self, Canc /// public static async Task DrawCardOrThrowAsync(this CrazyEightsClient self, CancellationToken cancellationToken = default) { - var request = new DrawCardRequest{ }; + var request = new DrawCardRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return response.Card; } @@ -152,7 +152,7 @@ public static async Task DrawCardOrThrowAsync(this CrazyEightsClient self, /// public static Task PassAsync(this CrazyEightsClient self, CancellationToken cancellationToken = default) { - var request = new PassRequest{ }; + var request = new PassRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -160,7 +160,7 @@ public static Task PassAsync(this CrazyEightsClient self, Cancell /// public static async Task PassOrThrowAsync(this CrazyEightsClient self, CancellationToken cancellationToken = default) { - var request = new PassRequest{ }; + var request = new PassRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); } } diff --git a/src/Deckster.Client/Games/Gabong/GabongClient.g.cs b/src/Deckster.Client/Games/Gabong/GabongClient.g.cs index 17100bca..bf634e2b 100644 --- a/src/Deckster.Client/Games/Gabong/GabongClient.g.cs +++ b/src/Deckster.Client/Games/Gabong/GabongClient.g.cs @@ -99,7 +99,7 @@ public static class GabongClientConveniences /// public static Task DrawCardAsync(this GabongClient self, CancellationToken cancellationToken = default) { - var request = new DrawCardRequest{ }; + var request = new DrawCardRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -107,7 +107,7 @@ public static Task DrawCardAsync(this GabongClient self, Cance /// public static async Task<(List cards, Card topOfPile, Suit currentSuit, int stockPileCount, int discardPileCount, bool roundStarted, Guid lastPlayMadeByPlayerId, GabongPlay lastPlay, List players, List playersOrder, int cardDebtToDraw, List cardsAdded)> DrawCardOrThrowAsync(this GabongClient self, CancellationToken cancellationToken = default) { - var request = new DrawCardRequest{ }; + var request = new DrawCardRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentSuit, response.StockPileCount, response.DiscardPileCount, response.RoundStarted, response.LastPlayMadeByPlayerId, response.LastPlay, response.Players, response.PlayersOrder, response.CardDebtToDraw, response.CardsAdded); } @@ -116,7 +116,7 @@ public static Task DrawCardAsync(this GabongClient self, Cance /// public static Task PlayGabongAsync(this GabongClient self, CancellationToken cancellationToken = default) { - var request = new PlayGabongRequest{ }; + var request = new PlayGabongRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -124,7 +124,7 @@ public static Task PlayGabongAsync(this GabongClient self, Can /// public static async Task<(List cards, Card topOfPile, Suit currentSuit, int stockPileCount, int discardPileCount, bool roundStarted, Guid lastPlayMadeByPlayerId, GabongPlay lastPlay, List players, List playersOrder, int cardDebtToDraw, List cardsAdded)> PlayGabongOrThrowAsync(this GabongClient self, CancellationToken cancellationToken = default) { - var request = new PlayGabongRequest{ }; + var request = new PlayGabongRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentSuit, response.StockPileCount, response.DiscardPileCount, response.RoundStarted, response.LastPlayMadeByPlayerId, response.LastPlay, response.Players, response.PlayersOrder, response.CardDebtToDraw, response.CardsAdded); } @@ -133,7 +133,7 @@ public static Task PlayGabongAsync(this GabongClient self, Can /// public static Task PlayBongaAsync(this GabongClient self, CancellationToken cancellationToken = default) { - var request = new PlayBongaRequest{ }; + var request = new PlayBongaRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -141,7 +141,7 @@ public static Task PlayBongaAsync(this GabongClient self, Canc /// public static async Task<(List cards, Card topOfPile, Suit currentSuit, int stockPileCount, int discardPileCount, bool roundStarted, Guid lastPlayMadeByPlayerId, GabongPlay lastPlay, List players, List playersOrder, int cardDebtToDraw, List cardsAdded)> PlayBongaOrThrowAsync(this GabongClient self, CancellationToken cancellationToken = default) { - var request = new PlayBongaRequest{ }; + var request = new PlayBongaRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentSuit, response.StockPileCount, response.DiscardPileCount, response.RoundStarted, response.LastPlayMadeByPlayerId, response.LastPlay, response.Players, response.PlayersOrder, response.CardDebtToDraw, response.CardsAdded); } @@ -150,7 +150,7 @@ public static Task PlayBongaAsync(this GabongClient self, Canc /// public static Task PassAsync(this GabongClient self, CancellationToken cancellationToken = default) { - var request = new PassRequest{ }; + var request = new PassRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -158,7 +158,7 @@ public static Task PassAsync(this GabongClient self, Cancellat /// public static async Task<(List cards, Card topOfPile, Suit currentSuit, int stockPileCount, int discardPileCount, bool roundStarted, Guid lastPlayMadeByPlayerId, GabongPlay lastPlay, List players, List playersOrder, int cardDebtToDraw, List cardsAdded)> PassOrThrowAsync(this GabongClient self, CancellationToken cancellationToken = default) { - var request = new PassRequest{ }; + var request = new PassRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentSuit, response.StockPileCount, response.DiscardPileCount, response.RoundStarted, response.LastPlayMadeByPlayerId, response.LastPlay, response.Players, response.PlayersOrder, response.CardDebtToDraw, response.CardsAdded); } @@ -167,7 +167,7 @@ public static Task PassAsync(this GabongClient self, Cancellat /// public static Task PutCardAsync(this GabongClient self, Card card, Nullable newSuit, CancellationToken cancellationToken = default) { - var request = new PutCardRequest{ Card = card, NewSuit = newSuit }; + var request = new PutCardRequest{ PlayerId = self.PlayerData.Id, Card = card, NewSuit = newSuit }; return self.SendAsync(request, false, cancellationToken); } /// @@ -175,7 +175,7 @@ public static Task PutCardAsync(this GabongClient self, Card c /// public static async Task<(List cards, Card topOfPile, Suit currentSuit, int stockPileCount, int discardPileCount, bool roundStarted, Guid lastPlayMadeByPlayerId, GabongPlay lastPlay, List players, List playersOrder, int cardDebtToDraw, List cardsAdded)> PutCardOrThrowAsync(this GabongClient self, Card card, Nullable newSuit, CancellationToken cancellationToken = default) { - var request = new PutCardRequest{ Card = card, NewSuit = newSuit }; + var request = new PutCardRequest{ PlayerId = self.PlayerData.Id, Card = card, NewSuit = newSuit }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentSuit, response.StockPileCount, response.DiscardPileCount, response.RoundStarted, response.LastPlayMadeByPlayerId, response.LastPlay, response.Players, response.PlayersOrder, response.CardDebtToDraw, response.CardsAdded); } diff --git a/src/Deckster.Client/Games/Hearts/HeartsClient.g.cs b/src/Deckster.Client/Games/Hearts/HeartsClient.g.cs index 872fd95a..61ea14c8 100644 --- a/src/Deckster.Client/Games/Hearts/HeartsClient.g.cs +++ b/src/Deckster.Client/Games/Hearts/HeartsClient.g.cs @@ -96,7 +96,7 @@ public static class HeartsClientConveniences /// public static Task PassCardsAsync(this HeartsClient self, List cards, CancellationToken cancellationToken = default) { - var request = new PassCardsRequest{ Cards = cards }; + var request = new PassCardsRequest{ PlayerId = self.PlayerData.Id, Cards = cards }; return self.SendAsync(request, false, cancellationToken); } /// @@ -104,7 +104,7 @@ public static Task PassCardsAsync(this HeartsClient self, Lis /// public static async Task> PassCardsOrThrowAsync(this HeartsClient self, List cards, CancellationToken cancellationToken = default) { - var request = new PassCardsRequest{ Cards = cards }; + var request = new PassCardsRequest{ PlayerId = self.PlayerData.Id, Cards = cards }; var response = await self.SendAsync(request, true, cancellationToken); return response.ReceivedCards; } @@ -113,7 +113,7 @@ public static async Task> PassCardsOrThrowAsync(this HeartsClient sel /// public static Task PlayCardAsync(this HeartsClient self, Card card, CancellationToken cancellationToken = default) { - var request = new PlayCardRequest{ Card = card }; + var request = new PlayCardRequest{ PlayerId = self.PlayerData.Id, Card = card }; return self.SendAsync(request, false, cancellationToken); } /// @@ -121,7 +121,7 @@ public static Task PlayCardAsync(this HeartsClient self, Card /// public static async Task<(List cards, List otherPlayers, int roundNumber, PassDirection passDirection, bool hasPassed, List currentTrick, int totalScore, int roundScore, bool heartsAreBroken, bool isMyTurn)> PlayCardOrThrowAsync(this HeartsClient self, Card card, CancellationToken cancellationToken = default) { - var request = new PlayCardRequest{ Card = card }; + var request = new PlayCardRequest{ PlayerId = self.PlayerData.Id, Card = card }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.OtherPlayers, response.RoundNumber, response.PassDirection, response.HasPassed, response.CurrentTrick, response.TotalScore, response.RoundScore, response.HeartsAreBroken, response.IsMyTurn); } diff --git a/src/Deckster.Client/Games/Idiot/IdiotClient.g.cs b/src/Deckster.Client/Games/Idiot/IdiotClient.g.cs index c533e0d2..dcbfa40a 100644 --- a/src/Deckster.Client/Games/Idiot/IdiotClient.g.cs +++ b/src/Deckster.Client/Games/Idiot/IdiotClient.g.cs @@ -125,7 +125,7 @@ public static class IdiotClientConveniences /// public static Task IamReadyAsync(this IdiotClient self, CancellationToken cancellationToken = default) { - var request = new IamReadyRequest{ }; + var request = new IamReadyRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -133,7 +133,7 @@ public static Task IamReadyAsync(this IdiotClient self, Cancellat /// public static async Task IamReadyOrThrowAsync(this IdiotClient self, CancellationToken cancellationToken = default) { - var request = new IamReadyRequest{ }; + var request = new IamReadyRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); } /// @@ -141,7 +141,7 @@ public static async Task IamReadyOrThrowAsync(this IdiotClient self, Cancellatio /// public static Task SwapCardsAsync(this IdiotClient self, Card cardOnHand, Card cardFacingUp, CancellationToken cancellationToken = default) { - var request = new SwapCardsRequest{ CardOnHand = cardOnHand, CardFacingUp = cardFacingUp }; + var request = new SwapCardsRequest{ PlayerId = self.PlayerData.Id, CardOnHand = cardOnHand, CardFacingUp = cardFacingUp }; return self.SendAsync(request, false, cancellationToken); } /// @@ -149,7 +149,7 @@ public static Task SwapCardsAsync(this IdiotClient self, Card /// public static async Task<(Card cardNowOnHand, Card cardNowFacingUp)> SwapCardsOrThrowAsync(this IdiotClient self, Card cardOnHand, Card cardFacingUp, CancellationToken cancellationToken = default) { - var request = new SwapCardsRequest{ CardOnHand = cardOnHand, CardFacingUp = cardFacingUp }; + var request = new SwapCardsRequest{ PlayerId = self.PlayerData.Id, CardOnHand = cardOnHand, CardFacingUp = cardFacingUp }; var response = await self.SendAsync(request, true, cancellationToken); return (response.CardNowOnHand, response.CardNowFacingUp); } @@ -158,7 +158,7 @@ public static Task SwapCardsAsync(this IdiotClient self, Card /// public static Task PutCardsFromHandAsync(this IdiotClient self, Card[] cards, CancellationToken cancellationToken = default) { - var request = new PutCardsFromHandRequest{ Cards = cards }; + var request = new PutCardsFromHandRequest{ PlayerId = self.PlayerData.Id, Cards = cards }; return self.SendAsync(request, false, cancellationToken); } /// @@ -166,7 +166,7 @@ public static Task PutCardsFromHandAsync(this IdiotClient sel /// public static async Task PutCardsFromHandOrThrowAsync(this IdiotClient self, Card[] cards, CancellationToken cancellationToken = default) { - var request = new PutCardsFromHandRequest{ Cards = cards }; + var request = new PutCardsFromHandRequest{ PlayerId = self.PlayerData.Id, Cards = cards }; var response = await self.SendAsync(request, true, cancellationToken); return response.Cards; } @@ -175,7 +175,7 @@ public static async Task PutCardsFromHandOrThrowAsync(this IdiotClient s /// public static Task PutCardsFacingUpAsync(this IdiotClient self, Card[] cards, CancellationToken cancellationToken = default) { - var request = new PutCardsFacingUpRequest{ Cards = cards }; + var request = new PutCardsFacingUpRequest{ PlayerId = self.PlayerData.Id, Cards = cards }; return self.SendAsync(request, false, cancellationToken); } /// @@ -183,7 +183,7 @@ public static Task PutCardsFacingUpAsync(this IdiotClient self, C /// public static async Task PutCardsFacingUpOrThrowAsync(this IdiotClient self, Card[] cards, CancellationToken cancellationToken = default) { - var request = new PutCardsFacingUpRequest{ Cards = cards }; + var request = new PutCardsFacingUpRequest{ PlayerId = self.PlayerData.Id, Cards = cards }; var response = await self.SendAsync(request, true, cancellationToken); } /// @@ -191,7 +191,7 @@ public static async Task PutCardsFacingUpOrThrowAsync(this IdiotClient self, Car /// public static Task PutCardFacingDownAsync(this IdiotClient self, int index, CancellationToken cancellationToken = default) { - var request = new PutCardFacingDownRequest{ Index = index }; + var request = new PutCardFacingDownRequest{ PlayerId = self.PlayerData.Id, Index = index }; return self.SendAsync(request, false, cancellationToken); } /// @@ -199,7 +199,7 @@ public static Task PutCardFacingDownAsync(this IdiotClient /// public static async Task<(Card attemptedCard, Card[] pullInCards)> PutCardFacingDownOrThrowAsync(this IdiotClient self, int index, CancellationToken cancellationToken = default) { - var request = new PutCardFacingDownRequest{ Index = index }; + var request = new PutCardFacingDownRequest{ PlayerId = self.PlayerData.Id, Index = index }; var response = await self.SendAsync(request, true, cancellationToken); return (response.AttemptedCard, response.PullInCards); } @@ -208,7 +208,7 @@ public static Task PutCardFacingDownAsync(this IdiotClient /// public static Task PutChanceCardAsync(this IdiotClient self, CancellationToken cancellationToken = default) { - var request = new PutChanceCardRequest{ }; + var request = new PutChanceCardRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -216,7 +216,7 @@ public static Task PutChanceCardAsync(this IdiotClient sel /// public static async Task<(Card attemptedCard, Card[] pullInCards)> PutChanceCardOrThrowAsync(this IdiotClient self, CancellationToken cancellationToken = default) { - var request = new PutChanceCardRequest{ }; + var request = new PutChanceCardRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return (response.AttemptedCard, response.PullInCards); } @@ -225,7 +225,7 @@ public static Task PutChanceCardAsync(this IdiotClient sel /// public static Task PullInDiscardPileAsync(this IdiotClient self, CancellationToken cancellationToken = default) { - var request = new PullInDiscardPileRequest{ }; + var request = new PullInDiscardPileRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -233,7 +233,7 @@ public static Task PullInDiscardPileAsync(this IdiotClient self, /// public static async Task PullInDiscardPileOrThrowAsync(this IdiotClient self, CancellationToken cancellationToken = default) { - var request = new PullInDiscardPileRequest{ }; + var request = new PullInDiscardPileRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return response.Cards; } diff --git a/src/Deckster.Client/Games/TexasHoldEm/TexasHoldEmClient.g.cs b/src/Deckster.Client/Games/TexasHoldEm/TexasHoldEmClient.g.cs index 619c4fd0..56cebb58 100644 --- a/src/Deckster.Client/Games/TexasHoldEm/TexasHoldEmClient.g.cs +++ b/src/Deckster.Client/Games/TexasHoldEm/TexasHoldEmClient.g.cs @@ -106,7 +106,7 @@ public static class TexasHoldEmClientConveniences /// public static Task PlayerBetRequestAsync(this TexasHoldEmClient self, int bet, CancellationToken cancellationToken = default) { - var request = new BetRequest{ Bet = bet }; + var request = new BetRequest{ PlayerId = self.PlayerData.Id, Bet = bet }; return self.SendAsync(request, false, cancellationToken); } /// @@ -114,7 +114,7 @@ public static Task PlayerBetRequestAsync(this TexasHoldEmClien /// public static async Task<(List cards, List cardsOnTable, int stackSize, int currentBet, int potSize, int bigBlind, int numberOfRoundsUntilBigBlindIncreases, List otherPlayers, Guid nextRoundStartingPlayerId)> PlayerBetRequestOrThrowAsync(this TexasHoldEmClient self, int bet, CancellationToken cancellationToken = default) { - var request = new BetRequest{ Bet = bet }; + var request = new BetRequest{ PlayerId = self.PlayerData.Id, Bet = bet }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.CardsOnTable, response.StackSize, response.CurrentBet, response.PotSize, response.BigBlind, response.NumberOfRoundsUntilBigBlindIncreases, response.OtherPlayers, response.NextRoundStartingPlayerId); } @@ -123,7 +123,7 @@ public static Task PlayerBetRequestAsync(this TexasHoldEmClien /// public static Task PlayerFoldRequestAsync(this TexasHoldEmClient self, CancellationToken cancellationToken = default) { - var request = new FoldRequest{ }; + var request = new FoldRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -131,7 +131,7 @@ public static Task PlayerFoldRequestAsync(this TexasHoldEmClie /// public static async Task<(List cards, List cardsOnTable, int stackSize, int currentBet, int potSize, int bigBlind, int numberOfRoundsUntilBigBlindIncreases, List otherPlayers, Guid nextRoundStartingPlayerId)> PlayerFoldRequestOrThrowAsync(this TexasHoldEmClient self, CancellationToken cancellationToken = default) { - var request = new FoldRequest{ }; + var request = new FoldRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.CardsOnTable, response.StackSize, response.CurrentBet, response.PotSize, response.BigBlind, response.NumberOfRoundsUntilBigBlindIncreases, response.OtherPlayers, response.NextRoundStartingPlayerId); } @@ -140,7 +140,7 @@ public static Task PlayerFoldRequestAsync(this TexasHoldEmClie /// public static Task PlayerCheckRequestAsync(this TexasHoldEmClient self, CancellationToken cancellationToken = default) { - var request = new CheckRequest{ }; + var request = new CheckRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -148,7 +148,7 @@ public static Task PlayerCheckRequestAsync(this TexasHoldEmCli /// public static async Task<(List cards, List cardsOnTable, int stackSize, int currentBet, int potSize, int bigBlind, int numberOfRoundsUntilBigBlindIncreases, List otherPlayers, Guid nextRoundStartingPlayerId)> PlayerCheckRequestOrThrowAsync(this TexasHoldEmClient self, CancellationToken cancellationToken = default) { - var request = new CheckRequest{ }; + var request = new CheckRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.CardsOnTable, response.StackSize, response.CurrentBet, response.PotSize, response.BigBlind, response.NumberOfRoundsUntilBigBlindIncreases, response.OtherPlayers, response.NextRoundStartingPlayerId); } @@ -157,7 +157,7 @@ public static Task PlayerCheckRequestAsync(this TexasHoldEmCli /// public static Task PlayerCallRequestAsync(this TexasHoldEmClient self, CancellationToken cancellationToken = default) { - var request = new CallRequest{ }; + var request = new CallRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -165,7 +165,7 @@ public static Task PlayerCallRequestAsync(this TexasHoldEmClie /// public static async Task<(List cards, List cardsOnTable, int stackSize, int currentBet, int potSize, int bigBlind, int numberOfRoundsUntilBigBlindIncreases, List otherPlayers, Guid nextRoundStartingPlayerId)> PlayerCallRequestOrThrowAsync(this TexasHoldEmClient self, CancellationToken cancellationToken = default) { - var request = new CallRequest{ }; + var request = new CallRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.CardsOnTable, response.StackSize, response.CurrentBet, response.PotSize, response.BigBlind, response.NumberOfRoundsUntilBigBlindIncreases, response.OtherPlayers, response.NextRoundStartingPlayerId); } diff --git a/src/Deckster.Client/Games/Uno/UnoClient.g.cs b/src/Deckster.Client/Games/Uno/UnoClient.g.cs index f48f362d..609a756b 100644 --- a/src/Deckster.Client/Games/Uno/UnoClient.g.cs +++ b/src/Deckster.Client/Games/Uno/UnoClient.g.cs @@ -89,7 +89,7 @@ public static class UnoClientConveniences /// public static Task PutCardAsync(this UnoClient self, UnoCard card, CancellationToken cancellationToken = default) { - var request = new PutCardRequest{ Card = card }; + var request = new PutCardRequest{ PlayerId = self.PlayerData.Id, Card = card }; return self.SendAsync(request, false, cancellationToken); } /// @@ -97,7 +97,7 @@ public static Task PutCardAsync(this UnoClient self, UnoCard c /// public static async Task<(List cards, UnoCard topOfPile, UnoColor currentColor, int stockPileCount, int discardPileCount, List otherPlayers)> PutCardOrThrowAsync(this UnoClient self, UnoCard card, CancellationToken cancellationToken = default) { - var request = new PutCardRequest{ Card = card }; + var request = new PutCardRequest{ PlayerId = self.PlayerData.Id, Card = card }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentColor, response.StockPileCount, response.DiscardPileCount, response.OtherPlayers); } @@ -106,7 +106,7 @@ public static Task PutCardAsync(this UnoClient self, UnoCard c /// public static Task PutWildAsync(this UnoClient self, UnoCard card, UnoColor newColor, CancellationToken cancellationToken = default) { - var request = new PutWildRequest{ Card = card, NewColor = newColor }; + var request = new PutWildRequest{ PlayerId = self.PlayerData.Id, Card = card, NewColor = newColor }; return self.SendAsync(request, false, cancellationToken); } /// @@ -114,7 +114,7 @@ public static Task PutWildAsync(this UnoClient self, UnoCard c /// public static async Task<(List cards, UnoCard topOfPile, UnoColor currentColor, int stockPileCount, int discardPileCount, List otherPlayers)> PutWildOrThrowAsync(this UnoClient self, UnoCard card, UnoColor newColor, CancellationToken cancellationToken = default) { - var request = new PutWildRequest{ Card = card, NewColor = newColor }; + var request = new PutWildRequest{ PlayerId = self.PlayerData.Id, Card = card, NewColor = newColor }; var response = await self.SendAsync(request, true, cancellationToken); return (response.Cards, response.TopOfPile, response.CurrentColor, response.StockPileCount, response.DiscardPileCount, response.OtherPlayers); } @@ -123,7 +123,7 @@ public static Task PutWildAsync(this UnoClient self, UnoCard c /// public static Task DrawCardAsync(this UnoClient self, CancellationToken cancellationToken = default) { - var request = new DrawCardRequest{ }; + var request = new DrawCardRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -131,7 +131,7 @@ public static Task DrawCardAsync(this UnoClient self, Cancellat /// public static async Task DrawCardOrThrowAsync(this UnoClient self, CancellationToken cancellationToken = default) { - var request = new DrawCardRequest{ }; + var request = new DrawCardRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); return response.Card; } @@ -140,7 +140,7 @@ public static async Task DrawCardOrThrowAsync(this UnoClient self, Canc /// public static Task PassAsync(this UnoClient self, CancellationToken cancellationToken = default) { - var request = new PassRequest{ }; + var request = new PassRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -148,7 +148,7 @@ public static Task PassAsync(this UnoClient self, CancellationTok /// public static async Task PassOrThrowAsync(this UnoClient self, CancellationToken cancellationToken = default) { - var request = new PassRequest{ }; + var request = new PassRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); } } diff --git a/src/Deckster.Client/Games/Yaniv/YanivClient.g.cs b/src/Deckster.Client/Games/Yaniv/YanivClient.g.cs index b4060725..c940d574 100644 --- a/src/Deckster.Client/Games/Yaniv/YanivClient.g.cs +++ b/src/Deckster.Client/Games/Yaniv/YanivClient.g.cs @@ -75,7 +75,7 @@ public static class YanivClientConveniences /// public static Task CallYanivAsync(this YanivClient self, CancellationToken cancellationToken = default) { - var request = new CallYanivRequest{ }; + var request = new CallYanivRequest{ PlayerId = self.PlayerData.Id }; return self.SendAsync(request, false, cancellationToken); } /// @@ -83,7 +83,7 @@ public static Task CallYanivAsync(this YanivClient self, Cancella /// public static async Task CallYanivOrThrowAsync(this YanivClient self, CancellationToken cancellationToken = default) { - var request = new CallYanivRequest{ }; + var request = new CallYanivRequest{ PlayerId = self.PlayerData.Id }; var response = await self.SendAsync(request, true, cancellationToken); } /// @@ -91,7 +91,7 @@ public static async Task CallYanivOrThrowAsync(this YanivClient self, Cancellati /// public static Task PutCardsAsync(this YanivClient self, Card[] cards, DrawCardFrom drawCardFrom, CancellationToken cancellationToken = default) { - var request = new PutCardsRequest{ Cards = cards, DrawCardFrom = drawCardFrom }; + var request = new PutCardsRequest{ PlayerId = self.PlayerData.Id, Cards = cards, DrawCardFrom = drawCardFrom }; return self.SendAsync(request, false, cancellationToken); } /// @@ -99,7 +99,7 @@ public static Task PutCardsAsync(this YanivClient self, Card[] /// public static async Task PutCardsOrThrowAsync(this YanivClient self, Card[] cards, DrawCardFrom drawCardFrom, CancellationToken cancellationToken = default) { - var request = new PutCardsRequest{ Cards = cards, DrawCardFrom = drawCardFrom }; + var request = new PutCardsRequest{ PlayerId = self.PlayerData.Id, Cards = cards, DrawCardFrom = drawCardFrom }; var response = await self.SendAsync(request, true, cancellationToken); return response.DrawnCard; } diff --git a/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs b/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs index a105b9c1..b7fc5d2e 100644 --- a/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs +++ b/src/Deckster.CodeGenerator/Generators/CsharpClientGenerator.cs @@ -118,7 +118,7 @@ public CsharpClientGenerator(CSharpGameMeta meta, string ns) Source.AppendLine($"public static Task<{extension.ReturnType.ToDisplayString()}> {extension.Name}Async(this {ClientName} self, {parameters})"); using(Source.CodeBlock()) { - var properties = extension.Parameters.Select(p => $"{p.Name.ToPascalCase()} = {p.Name}").StringJoined(", "); + var properties = extension.Parameters.Select(p => $"{p.Name.ToPascalCase()} = {p.Name}").Prepend("PlayerId = self.PlayerData.Id").StringJoined(", "); Source.AppendLine($"var request = new {extension.Method.Request.ParameterType.ToDisplayString()}{{ {properties} }};"); Source.AppendLine($"return self.SendAsync<{extension.ReturnType.ToDisplayString()}>(request, false, cancellationToken);"); } @@ -156,7 +156,7 @@ public CsharpClientGenerator(CSharpGameMeta meta, string ns) using (Source.CodeBlock()) { - var properties = extension.Parameters.Select(p => $"{p.Name.ToPascalCase()} = {p.Name}").StringJoined(", "); + var properties = extension.Parameters.Select(p => $"{p.Name.ToPascalCase()} = {p.Name}").Prepend("PlayerId = self.PlayerData.Id").StringJoined(", "); Source.AppendLine($"var request = new {extension.Method.Request.ParameterType.ToDisplayString()}{{ {properties} }};"); Source.AppendLine($"var response = await self.SendAsync<{extension.Method.ResponseType.ToDisplayString()}>(request, true, cancellationToken);"); From bde47f61aedc6d37866d7ec86ccb63cd9e73abe2 Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 13:51:38 +0200 Subject: [PATCH 19/26] fixes cards not showing after a bot wins round --- web-clients/hearts/src/game/HeartsGame.ts | 11 ++++++++++- web-clients/hearts/src/graphics/CardScene.ts | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/web-clients/hearts/src/game/HeartsGame.ts b/web-clients/hearts/src/game/HeartsGame.ts index a0322324..dec8c1b3 100644 --- a/web-clients/hearts/src/game/HeartsGame.ts +++ b/web-clients/hearts/src/game/HeartsGame.ts @@ -408,7 +408,12 @@ export class HeartsGame { } private async updateGameState(state: PlayerViewOfGame): Promise { - console.log('Updating game state:', state); + console.log('🔄 Updating game state:', state); + console.log(' - Round:', state.roundNumber); + console.log(' - Cards in state:', state.cards?.length || 0); + console.log(' - Is animating:', this.scene.isAnimating()); + console.log(' - Current trick cards:', this.scene.currentTrickCards.length); + console.log(' - Player cards before update:', this.scene.playerCards.length); // Update UI this.ui.updateGameInfo({ @@ -420,7 +425,11 @@ export class HeartsGame { // Update cards in hand if (state.cards) { + console.log(' ➡️ Adding', state.cards.length, 'cards to player hand'); await this.scene.addPlayerCards(state.cards); + console.log(' ✅ Cards added. Player cards after update:', this.scene.playerCards.length); + } else { + console.log(' ⚠️ No cards in state to add'); } // Update opponent cards and track player positions diff --git a/web-clients/hearts/src/graphics/CardScene.ts b/web-clients/hearts/src/graphics/CardScene.ts index e0909da9..c7285c55 100644 --- a/web-clients/hearts/src/graphics/CardScene.ts +++ b/web-clients/hearts/src/graphics/CardScene.ts @@ -216,8 +216,12 @@ export class CardScene { } public async addPlayerCards(cards: Card[]): Promise { + console.log('🎴 addPlayerCards called with', cards.length, 'cards'); + console.log(' - Player cards before clear:', this.playerCards.length); + // Clear existing cards this.clearPlayerCards(); + console.log(' - Player cards after clear:', this.playerCards.length); // Sort cards by suit first, then by rank const sortedCards = [...cards].sort((a, b) => { @@ -271,6 +275,8 @@ export class CardScene { this.playerCards.push(card3D); this.scene.add(card3D.mesh); }); + + console.log(' ✅ addPlayerCards complete. Final player cards count:', this.playerCards.length); } public updateOpponentCards(playerId: string, numberOfCards: number, playerIndex: number, playerName?: string): void { From c6e8e403b1d19208ea85877ca9efd0844854549b Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 14:07:16 +0200 Subject: [PATCH 20/26] some what something --- web-clients/hearts/src/game/HeartsGame.ts | 47 ++++++++++++-------- web-clients/hearts/src/graphics/CardScene.ts | 15 +++---- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/web-clients/hearts/src/game/HeartsGame.ts b/web-clients/hearts/src/game/HeartsGame.ts index dec8c1b3..34ddcc98 100644 --- a/web-clients/hearts/src/game/HeartsGame.ts +++ b/web-clients/hearts/src/game/HeartsGame.ts @@ -317,7 +317,18 @@ export class HeartsGame { }); this.client.onPlayerPlayedCard(async (data) => { - console.log('Player played card:', data); + console.log('🃏 PlayerPlayedCard notification:', data); + console.log(' - Notification playerId:', data.playerId); + console.log(' - My playerId:', this.playerId); + console.log(' - Are they equal?', data.playerId === this.playerId); + console.log(' - Type of notification playerId:', typeof data.playerId); + console.log(' - Type of my playerId:', typeof this.playerId); + + // Skip if this is our own card - playCard will handle everything + if (data.playerId === this.playerId) { + console.log('✅ Skipping notification for our own card - already handled by playCard'); + return; + } // Detect if this is the start of a new trick (no cards on table) if (this.scene.currentTrickCards.length === 0) { @@ -332,12 +343,6 @@ export class HeartsGame { // Log to dev console this.ui.logCardPlay(playerName, cardStr); - // Skip if this is our own card - playCard will handle the animation - if (data.playerId === this.playerId) { - console.log('Skipping notification for our own card - animation handled by playCard'); - return; - } - // Get player's position in the scene const playerPosition = this.playerPositions.get(data.playerId) ?? 0; console.log(`Player ${data.playerId} at position ${playerPosition} played card:`, data.card); @@ -452,24 +457,28 @@ export class HeartsGame { } // Update current trick - // Only update trick if there are cards to show AND we're not animating - // Skip trick update if animation is in progress to avoid duplicates + // DON'T clear or rebuild the trick during animations + // The onTrickCompleted handler is responsible for clearing tricks + // We only need to sync if we're out of sync (shouldn't happen normally) if (this.scene.isAnimating()) { console.log('Skipping trick update - animation in progress'); return; } - if (state.currentTrick && state.currentTrick.length > 0) { - this.scene.clearTrick(); - for (const cardPlay of state.currentTrick) { - // Use the player's actual position, not the array index - const playerPosition = this.playerPositions.get(cardPlay.playerId) ?? 0; - console.log(`Adding trick card for player ${cardPlay.playerId} at position ${playerPosition}`); - await this.scene.addTrickCard(cardPlay.card, playerPosition); + // If there's a mismatch between state and scene, sync it + // This handles edge cases like reconnection or state recovery + if (state.currentTrick) { + const stateTrickCount = state.currentTrick.length; + const sceneTrickCount = this.scene.currentTrickCards.length; + + if (stateTrickCount !== sceneTrickCount) { + console.log(`Trick count mismatch: state=${stateTrickCount}, scene=${sceneTrickCount}. Resyncing...`); + this.scene.clearTrick(); + for (const cardPlay of state.currentTrick) { + const playerPosition = this.playerPositions.get(cardPlay.playerId) ?? 0; + await this.scene.addTrickCard(cardPlay.card, playerPosition); + } } - } else if (state.currentTrick && state.currentTrick.length === 0) { - // Empty trick means we should clear - this.scene.clearTrick(); } } diff --git a/web-clients/hearts/src/graphics/CardScene.ts b/web-clients/hearts/src/graphics/CardScene.ts index c7285c55..979ce7ae 100644 --- a/web-clients/hearts/src/graphics/CardScene.ts +++ b/web-clients/hearts/src/graphics/CardScene.ts @@ -466,6 +466,11 @@ export class CardScene { // Remove from playerCards array (but don't dispose or remove from scene yet) this.playerCards.splice(cardIndex, 1); + // Add to currentTrickCards IMMEDIATELY (before animation) + // This prevents race conditions where other players' notifications + // think it's a new trick while our animation is running + this.currentTrickCards.push(card3D); + // Get target position for the trick const trickPositions = [ new THREE.Vector3(0, 0.11, 2), // South (current player) @@ -478,9 +483,6 @@ export class CardScene { // Animate the card to the trick position await card3D.animateToPosition(targetPosition, 500); - // Add to currentTrickCards - this.currentTrickCards.push(card3D); - // Rearrange remaining player cards this.rearrangePlayerCards(); } finally { @@ -547,12 +549,7 @@ export class CardScene { } public clearTrick(): void { - // Don't clear trick if animation is in progress - if (this.isAnimatingTrick) { - console.log('Skipping clearTrick - animation in progress'); - return; - } - + console.log(`🗑️ Clearing trick (${this.currentTrickCards.length} cards)`); this.currentTrickCards.forEach(card => { this.scene.remove(card.mesh); card.dispose(); From acd6977f55abdc9aae7bc30a67e38b07dca1879a Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 14:15:10 +0200 Subject: [PATCH 21/26] =?UTF-8?q?WHAT=20this=20is=20a=20working=20game=20?= =?UTF-8?q?=F0=9F=98=B2=20with=20some=20graphical=20gliches=20ofc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web-clients/hearts/src/game/HeartsGame.ts | 3 +-- web-clients/hearts/src/graphics/CardScene.ts | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/web-clients/hearts/src/game/HeartsGame.ts b/web-clients/hearts/src/game/HeartsGame.ts index 34ddcc98..5b535b60 100644 --- a/web-clients/hearts/src/game/HeartsGame.ts +++ b/web-clients/hearts/src/game/HeartsGame.ts @@ -369,9 +369,8 @@ export class HeartsGame { const winnerPosition = this.playerPositions.get(data.winnerId) ?? 0; console.log(`Winner ${data.winnerName} (ID: ${data.winnerId}) is at position ${winnerPosition}`); - // Animate cards to winner, then clear + // Animate cards to winner (animation handles disposal internally) await this.scene.animateTrickToWinner(winnerPosition, 1500); - this.scene.clearTrick(); }); this.client.onRoundEnded((data) => { diff --git a/web-clients/hearts/src/graphics/CardScene.ts b/web-clients/hearts/src/graphics/CardScene.ts index 979ce7ae..046983d4 100644 --- a/web-clients/hearts/src/graphics/CardScene.ts +++ b/web-clients/hearts/src/graphics/CardScene.ts @@ -494,6 +494,12 @@ export class CardScene { public async animateTrickToWinner(winnerPosition: number, delay: number = 1000): Promise { if (this.currentTrickCards.length === 0) return; + // Save the cards to animate and clear the array IMMEDIATELY + // This prevents new trick cards from being cleared with the old ones + const cardsToAnimate = [...this.currentTrickCards]; + this.currentTrickCards = []; + console.log(`🎬 Starting trick animation with ${cardsToAnimate.length} cards. currentTrickCards cleared.`); + // Mark that we're animating this.isAnimatingTrick = true; @@ -521,8 +527,8 @@ export class CardScene { // Wait for the delay to let players see the trick await new Promise(resolve => setTimeout(resolve, delay)); - // Animate all trick cards to the winner's position - const animations = this.currentTrickCards.map((card, index) => { + // Animate all saved trick cards to the winner's position + const animations = cardsToAnimate.map((card, index) => { // Slightly offset each card so they stack const offset = new THREE.Vector3( (Math.random() - 0.5) * 0.3, @@ -538,9 +544,17 @@ export class CardScene { // Wait a bit more so players can see where the cards went await new Promise(resolve => setTimeout(resolve, 500)); + + // Dispose of the animated cards + console.log(`🗑️ Disposing ${cardsToAnimate.length} animated trick cards`); + cardsToAnimate.forEach(card => { + this.scene.remove(card.mesh); + card.dispose(); + }); } finally { // Always mark animation as complete, even if there was an error this.isAnimatingTrick = false; + console.log('✅ Trick animation complete'); } } From b8c994a6416023512e9942bb1790392d99e6cb12 Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 14:22:51 +0200 Subject: [PATCH 22/26] wait to animation is finished before showing cards --- web-clients/hearts/src/game/HeartsGame.ts | 69 +++++++++++++------- web-clients/hearts/src/graphics/CardScene.ts | 2 +- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/web-clients/hearts/src/game/HeartsGame.ts b/web-clients/hearts/src/game/HeartsGame.ts index 5b535b60..01d11575 100644 --- a/web-clients/hearts/src/game/HeartsGame.ts +++ b/web-clients/hearts/src/game/HeartsGame.ts @@ -16,6 +16,7 @@ export class HeartsGame { private myTurn: boolean = false; private currentTrickNumber: number = 0; private currentRoundNumber: number = 1; + private queuedCardPlays: Array<{playerId: string, card: any}> = []; constructor(scene: CardScene, ui: GameUI) { this.scene = scene; @@ -318,11 +319,6 @@ export class HeartsGame { this.client.onPlayerPlayedCard(async (data) => { console.log('🃏 PlayerPlayedCard notification:', data); - console.log(' - Notification playerId:', data.playerId); - console.log(' - My playerId:', this.playerId); - console.log(' - Are they equal?', data.playerId === this.playerId); - console.log(' - Type of notification playerId:', typeof data.playerId); - console.log(' - Type of my playerId:', typeof this.playerId); // Skip if this is our own card - playCard will handle everything if (data.playerId === this.playerId) { @@ -330,25 +326,15 @@ export class HeartsGame { return; } - // Detect if this is the start of a new trick (no cards on table) - if (this.scene.currentTrickCards.length === 0) { - this.currentTrickNumber++; - this.ui.logNewTrick(this.currentTrickNumber); + // If trick animation is running, queue this notification + if (this.scene.isAnimatingTrick) { + console.log('⏸️ Trick animation in progress - queuing card play'); + this.queuedCardPlays.push({ playerId: data.playerId, card: data.card }); + return; } - // Get player name and format card - const playerName = this.playerNames.get(data.playerId) ?? 'Unknown'; - const cardStr = this.formatCard(data.card); - - // Log to dev console - this.ui.logCardPlay(playerName, cardStr); - - // Get player's position in the scene - const playerPosition = this.playerPositions.get(data.playerId) ?? 0; - console.log(`Player ${data.playerId} at position ${playerPosition} played card:`, data.card); - - // Add the played card to the trick at the correct position - await this.scene.addTrickCard(data.card, playerPosition); + // Process the card play immediately + await this.processCardPlay(data.playerId, data.card); }); this.client.onTrickCompleted(async (data) => { @@ -371,6 +357,9 @@ export class HeartsGame { // Animate cards to winner (animation handles disposal internally) await this.scene.animateTrickToWinner(winnerPosition, 1500); + + // Process any queued card plays that arrived during animation + await this.processQueuedCardPlays(); }); this.client.onRoundEnded((data) => { @@ -589,6 +578,42 @@ export class HeartsGame { } } + private async processCardPlay(playerId: string, card: any): Promise { + // Detect if this is the start of a new trick (no cards on table) + if (this.scene.currentTrickCards.length === 0) { + this.currentTrickNumber++; + this.ui.logNewTrick(this.currentTrickNumber); + } + + // Get player name and format card + const playerName = this.playerNames.get(playerId) ?? 'Unknown'; + const cardStr = this.formatCard(card); + + // Log to dev console + this.ui.logCardPlay(playerName, cardStr); + + // Get player's position in the scene + const playerPosition = this.playerPositions.get(playerId) ?? 0; + console.log(`Player ${playerId} at position ${playerPosition} played card:`, card); + + // Add the played card to the trick at the correct position + await this.scene.addTrickCard(card, playerPosition); + } + + private async processQueuedCardPlays(): Promise { + if (this.queuedCardPlays.length === 0) { + return; + } + + console.log(`▶️ Processing ${this.queuedCardPlays.length} queued card play(s)`); + + // Process all queued plays in order + while (this.queuedCardPlays.length > 0) { + const queued = this.queuedCardPlays.shift()!; + await this.processCardPlay(queued.playerId, queued.card); + } + } + private formatCard(card: Card): string { const rankNames: { [key: number]: string } = { 1: 'A', 11: 'J', 12: 'Q', 13: 'K' diff --git a/web-clients/hearts/src/graphics/CardScene.ts b/web-clients/hearts/src/graphics/CardScene.ts index 046983d4..a3e1bf5d 100644 --- a/web-clients/hearts/src/graphics/CardScene.ts +++ b/web-clients/hearts/src/graphics/CardScene.ts @@ -18,7 +18,7 @@ export class CardScene { private opponentNameLabels: { [playerId: string]: THREE.Sprite } = {}; private static bgTexture: THREE.Texture | null = null; private static textureLoader = new THREE.TextureLoader(); - private isAnimatingTrick: boolean = false; + public isAnimatingTrick: boolean = false; private isAnimatingCardPlay: boolean = false; public onCardClick?: (card: Card3D) => void; From a6138d1e2296b123e9cb38dd51d6b368f51c1a65 Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 14:58:35 +0200 Subject: [PATCH 23/26] Game works ok again --- web-clients/hearts/index.html | 3 ++ web-clients/hearts/src/game/HeartsGame.ts | 45 ++++++++++++++++++----- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/web-clients/hearts/index.html b/web-clients/hearts/index.html index c9ffedc7..ad4f6a13 100644 --- a/web-clients/hearts/index.html +++ b/web-clients/hearts/index.html @@ -208,6 +208,9 @@ margin: 4px 0; padding: 4px 0; border-bottom: 1px solid rgba(0, 255, 0, 0.2); + word-wrap: break-word; + overflow-wrap: break-word; + word-break: break-word; } .log-entry:last-child { diff --git a/web-clients/hearts/src/game/HeartsGame.ts b/web-clients/hearts/src/game/HeartsGame.ts index 01d11575..8b4efcd1 100644 --- a/web-clients/hearts/src/game/HeartsGame.ts +++ b/web-clients/hearts/src/game/HeartsGame.ts @@ -291,7 +291,9 @@ export class HeartsGame { console.log('Registering ItsYourTurn handler...'); this.client.onItsYourTurn((data) => { - console.log('✋ Your turn event received!', data); + console.log('✋ Your turn event received!'); + console.log(' - Setting myTurn = true'); + console.log(' - Is animating:', this.scene.isAnimating()); this.myTurn = true; this.ui.showMessage('Your turn!'); this.ui.setStatus('Your turn - select a card to play'); @@ -300,6 +302,7 @@ export class HeartsGame { if (data.playerViewOfGame) { this.updateGameState(data.playerViewOfGame); } + console.log(' - After updateGameState, myTurn =', this.myTurn); }); this.client.onItsPlayersTurn((data) => { @@ -408,6 +411,20 @@ export class HeartsGame { console.log(' - Current trick cards:', this.scene.currentTrickCards.length); console.log(' - Player cards before update:', this.scene.playerCards.length); + // Sync passing phase with server state + // If hasPassed is true OR passDirection is None, we're not in passing phase + const shouldBeInPassingPhase = !state.hasPassed && state.passDirection !== PassDirection.None; + if (this.passingPhase !== shouldBeInPassingPhase) { + console.log(` - Syncing passingPhase: ${this.passingPhase} -> ${shouldBeInPassingPhase}`); + this.passingPhase = shouldBeInPassingPhase; + } + + // Sync myTurn with server state + if (this.myTurn !== state.isMyTurn) { + console.log(` - Syncing myTurn: ${this.myTurn} -> ${state.isMyTurn}`); + this.myTurn = state.isMyTurn; + } + // Update UI this.ui.updateGameInfo({ roundNumber: state.roundNumber, @@ -486,9 +503,18 @@ export class HeartsGame { } private async handleCardClick(card: Card3D): Promise { - console.log('Card clicked:', card.card); - console.log('Passing phase:', this.passingPhase); - console.log('My turn:', this.myTurn); + console.log('🖱️ Card clicked:', card.card); + console.log(' - Passing phase:', this.passingPhase); + console.log(' - My turn:', this.myTurn); + console.log(' - Is animating trick:', this.scene.isAnimatingTrick); + console.log(' - Is animating card play:', this.scene.isAnimating()); + + // Block input during trick animations + if (this.scene.isAnimatingTrick) { + console.log('⏸️ Cannot play card - trick animation in progress'); + this.ui.showMessage('Please wait for animation to complete', 1500); + return; + } if (this.passingPhase) { // Handle card passing @@ -550,6 +576,12 @@ export class HeartsGame { this.ui.logNewTrick(this.currentTrickNumber); } + // Log our own card play BEFORE sending to server + // This ensures it appears in the correct order in the dev log + const playerName = this.playerNames.get(this.playerId) ?? 'You'; + const cardStr = this.formatCard(card); + this.ui.logCardPlay(playerName, cardStr); + const response = await this.client.playCard({ playerId: this.playerId, card: card, @@ -562,11 +594,6 @@ export class HeartsGame { } else { this.myTurn = false; - // Log our own card play - const playerName = this.playerNames.get(this.playerId) ?? 'You'; - const cardStr = this.formatCard(card); - this.ui.logCardPlay(playerName, cardStr); - // Use animated card play instead of instant removal await this.scene.playCardWithAnimation(card, 0); // Current player position this.ui.setStatus('Waiting for other players...'); From 59979e9cd932166d162ff3a58b3c81091a27e20b Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 15:06:19 +0200 Subject: [PATCH 24/26] ? --- web-clients/hearts/src/game/HeartsGame.ts | 18 ++++++++- web-clients/hearts/src/graphics/CardScene.ts | 42 +++++++++++++------- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/web-clients/hearts/src/game/HeartsGame.ts b/web-clients/hearts/src/game/HeartsGame.ts index 8b4efcd1..6251b1ea 100644 --- a/web-clients/hearts/src/game/HeartsGame.ts +++ b/web-clients/hearts/src/game/HeartsGame.ts @@ -570,6 +570,19 @@ export class HeartsGame { console.log('Player ID:', this.playerId); console.log('My turn:', this.myTurn); + // Find and save the Card3D object BEFORE sending to server + // This prevents race conditions where updateGameState clears playerCards + // before we can animate the card + const card3D = this.scene.playerCards.find( + c => c.card.rank === card.rank && c.card.suit === card.suit + ); + + if (!card3D) { + console.error('Card3D not found in playerCards before sending to server!'); + this.ui.showMessage('Error: Card not found'); + return; + } + // Detect if this is the start of a new trick if (this.scene.currentTrickCards.length === 0) { this.currentTrickNumber++; @@ -594,8 +607,9 @@ export class HeartsGame { } else { this.myTurn = false; - // Use animated card play instead of instant removal - await this.scene.playCardWithAnimation(card, 0); // Current player position + // Animate using the saved Card3D reference + // This works even if playerCards has been cleared by updateGameState + await this.scene.playCardWithAnimation(card, 0, card3D); // Pass the saved Card3D this.ui.setStatus('Waiting for other players...'); await this.updateGameState(response); } diff --git a/web-clients/hearts/src/graphics/CardScene.ts b/web-clients/hearts/src/graphics/CardScene.ts index a3e1bf5d..9c029b67 100644 --- a/web-clients/hearts/src/graphics/CardScene.ts +++ b/web-clients/hearts/src/graphics/CardScene.ts @@ -445,31 +445,43 @@ export class CardScene { this.scene.add(card3D.mesh); } - public async playCardWithAnimation(card: Card, playerIndex: number): Promise { + public async playCardWithAnimation(card: Card, playerIndex: number, card3D?: Card3D): Promise { // Mark that we're animating a card play this.isAnimatingCardPlay = true; try { - // Find the card in playerCards - const cardIndex = this.playerCards.findIndex(c => - c.card.rank === card.rank && c.card.suit === card.suit - ); + let cardToAnimate: Card3D; + + if (card3D) { + // Use the provided Card3D object (prevents race conditions) + cardToAnimate = card3D; + // Remove it from playerCards if it's still there + const cardIndex = this.playerCards.indexOf(card3D); + if (cardIndex !== -1) { + this.playerCards.splice(cardIndex, 1); + } + } else { + // Find the card in playerCards (fallback for backward compatibility) + const cardIndex = this.playerCards.findIndex(c => + c.card.rank === card.rank && c.card.suit === card.suit + ); - if (cardIndex === -1) { - console.error('Card not found in playerCards:', card); - return; - } + if (cardIndex === -1) { + console.error('Card not found in playerCards:', card); + return; + } - // Get the card3D object - const card3D = this.playerCards[cardIndex]; + // Get the card3D object + cardToAnimate = this.playerCards[cardIndex]; - // Remove from playerCards array (but don't dispose or remove from scene yet) - this.playerCards.splice(cardIndex, 1); + // Remove from playerCards array (but don't dispose or remove from scene yet) + this.playerCards.splice(cardIndex, 1); + } // Add to currentTrickCards IMMEDIATELY (before animation) // This prevents race conditions where other players' notifications // think it's a new trick while our animation is running - this.currentTrickCards.push(card3D); + this.currentTrickCards.push(cardToAnimate); // Get target position for the trick const trickPositions = [ @@ -481,7 +493,7 @@ export class CardScene { const targetPosition = trickPositions[playerIndex % 4]; // Animate the card to the trick position - await card3D.animateToPosition(targetPosition, 500); + await cardToAnimate.animateToPosition(targetPosition, 500); // Rearrange remaining player cards this.rearrangePlayerCards(); From d3c4cc0621dc719410606e26e18a0cc184756f65 Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 16:52:27 +0200 Subject: [PATCH 25/26] godot client generation --- .gitignore | 3 +- generated/godot/bullshit/BullshitClient.gd | 173 ++++++++ generated/godot/chatroom/ChatRoomClient.gd | 111 +++++ .../godot/crazyeights/CrazyEightsClient.gd | 165 ++++++++ generated/godot/gabong/GabongClient.gd | 163 ++++++++ generated/godot/hearts/HeartsClient.gd | 157 ++++++++ generated/godot/idiot/IdiotClient.gd | 191 +++++++++ .../godot/texasholdem/TexasHoldEmClient.gd | 169 ++++++++ generated/godot/uno/UnoClient.gd | 153 +++++++ generated/godot/yaniv/YanivClient.gd | 137 +++++++ godot_clients/.gitignore | 6 + .../chat-sample-client/.editorconfig | 4 + .../chat-sample-client/.gitattributes | 2 + godot_clients/chat-sample-client/.gitignore | 3 + .../chat-sample-client/ChatRoomClient.gd | 111 +++++ .../chat-sample-client/ChatRoomClient.gd.uid | 1 + .../chat-sample-client/QUICKSTART.md | 91 +++++ godot_clients/chat-sample-client/README.md | 241 +++++++++++ godot_clients/chat-sample-client/TESTING.md | 139 +++++++ godot_clients/chat-sample-client/icon.svg | 1 + godot_clients/chat-sample-client/main.gd | 381 ++++++++++++++++++ godot_clients/chat-sample-client/main.gd.uid | 1 + godot_clients/chat-sample-client/main.tscn | 89 ++++ .../chat-sample-client/project.godot | 16 + godot_clients/chat-sample-client/run.bat | 3 + .../Generators/GodotClientGenerator.cs | 250 ++++++++++++ src/Deckster.CodeGenerator/Program.cs | 12 + 27 files changed, 2772 insertions(+), 1 deletion(-) create mode 100644 generated/godot/bullshit/BullshitClient.gd create mode 100644 generated/godot/chatroom/ChatRoomClient.gd create mode 100644 generated/godot/crazyeights/CrazyEightsClient.gd create mode 100644 generated/godot/gabong/GabongClient.gd create mode 100644 generated/godot/hearts/HeartsClient.gd create mode 100644 generated/godot/idiot/IdiotClient.gd create mode 100644 generated/godot/texasholdem/TexasHoldEmClient.gd create mode 100644 generated/godot/uno/UnoClient.gd create mode 100644 generated/godot/yaniv/YanivClient.gd create mode 100644 godot_clients/.gitignore create mode 100644 godot_clients/chat-sample-client/.editorconfig create mode 100644 godot_clients/chat-sample-client/.gitattributes create mode 100644 godot_clients/chat-sample-client/.gitignore create mode 100644 godot_clients/chat-sample-client/ChatRoomClient.gd create mode 100644 godot_clients/chat-sample-client/ChatRoomClient.gd.uid create mode 100644 godot_clients/chat-sample-client/QUICKSTART.md create mode 100644 godot_clients/chat-sample-client/README.md create mode 100644 godot_clients/chat-sample-client/TESTING.md create mode 100644 godot_clients/chat-sample-client/icon.svg create mode 100644 godot_clients/chat-sample-client/main.gd create mode 100644 godot_clients/chat-sample-client/main.gd.uid create mode 100644 godot_clients/chat-sample-client/main.tscn create mode 100644 godot_clients/chat-sample-client/project.godot create mode 100644 godot_clients/chat-sample-client/run.bat create mode 100644 src/Deckster.CodeGenerator/Generators/GodotClientGenerator.cs diff --git a/.gitignore b/.gitignore index 5b8d2e49..98ae1432 100644 --- a/.gitignore +++ b/.gitignore @@ -98,4 +98,5 @@ DerivedData/ # nodejs -node_modules \ No newline at end of file +node_modules + diff --git a/generated/godot/bullshit/BullshitClient.gd b/generated/godot/bullshit/BullshitClient.gd new file mode 100644 index 00000000..260e80ac --- /dev/null +++ b/generated/godot/bullshit/BullshitClient.gd @@ -0,0 +1,173 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## Bullshit Game Client for Godot Engine +## +## Notifications (events) for this game: +## - GameStarted: GameStartedNotification +## - PlayerDrewCard: PlayerDrewCardNotification +## - ItsYourTurn: ItsYourTurnNotification +## - ItsPlayersTurn: ItsPlayersTurnNotification +## - PlayerPassed: PlayerPassedNotification +## - PlayerPutCard: PlayerPutCardNotification +## - GameEnded: GameEndedNotification +## - PlayerIsDone: PlayerIsDoneNotification +## - DiscardPileShuffled: DiscardPileShuffledNotification +## - PlayersBullshitHasBeenCalled: BullshitBroadcastNotification +## - YourBullshitHasBeenCalled: BullshitPlayerNotification +## - PlayerAccusedFalseBullshit: FalseBullshitCallNotification +## + +class_name BullshitClient +extends RefCounted + +## Signals for game notifications +signal gameStarted(data: Dictionary) +signal playerDrewCard(data: Dictionary) +signal itsYourTurn(data: Dictionary) +signal itsPlayersTurn(data: Dictionary) +signal playerPassed(data: Dictionary) +signal playerPutCard(data: Dictionary) +signal gameEnded(data: Dictionary) +signal playerIsDone(data: Dictionary) +signal discardPileShuffled(data: Dictionary) +signal playersBullshitHasBeenCalled(data: Dictionary) +signal yourBullshitHasBeenCalled(data: Dictionary) +signal playerAccusedFalseBullshit(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "Bullshit.GameStartedNotification": + gameStarted.emit(notification) + "Bullshit.PlayerDrewCardNotification": + playerDrewCard.emit(notification) + "Bullshit.ItsYourTurnNotification": + itsYourTurn.emit(notification) + "Bullshit.ItsPlayersTurnNotification": + itsPlayersTurn.emit(notification) + "Bullshit.PlayerPassedNotification": + playerPassed.emit(notification) + "Bullshit.PlayerPutCardNotification": + playerPutCard.emit(notification) + "Bullshit.GameEndedNotification": + gameEnded.emit(notification) + "Bullshit.PlayerIsDoneNotification": + playerIsDone.emit(notification) + "Bullshit.DiscardPileShuffledNotification": + discardPileShuffled.emit(notification) + "Bullshit.BullshitBroadcastNotification": + playersBullshitHasBeenCalled.emit(notification) + "Bullshit.BullshitPlayerNotification": + yourBullshitHasBeenCalled.emit(notification) + "Bullshit.FalseBullshitCallNotification": + playerAccusedFalseBullshit.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## PutCard +func putCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Bullshit.PutCardRequest" + return await _send_request(request_data) + +## DrawCard +func drawCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Bullshit.DrawCardRequest" + return await _send_request(request_data) + +## Pass +func pass(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Bullshit.PassRequest" + return await _send_request(request_data) + +## CallBullshit +func callBullshit(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Bullshit.BullshitRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/generated/godot/chatroom/ChatRoomClient.gd b/generated/godot/chatroom/ChatRoomClient.gd new file mode 100644 index 00000000..fb76c27b --- /dev/null +++ b/generated/godot/chatroom/ChatRoomClient.gd @@ -0,0 +1,111 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## ChatRoom Game Client for Godot Engine +## +## Notifications (events) for this game: +## - PlayerSaid: ChatNotification +## + +class_name ChatRoomClient +extends RefCounted + +## Signals for game notifications +signal playerSaid(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "ChatRoom.ChatNotification": + playerSaid.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## ChatAsync +func chatAsync(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "ChatRoom.SendChatRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/generated/godot/crazyeights/CrazyEightsClient.gd b/generated/godot/crazyeights/CrazyEightsClient.gd new file mode 100644 index 00000000..360b3fc3 --- /dev/null +++ b/generated/godot/crazyeights/CrazyEightsClient.gd @@ -0,0 +1,165 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## CrazyEights Game Client for Godot Engine +## +## Notifications (events) for this game: +## - GameStarted: GameStartedNotification +## - PlayerDrewCard: PlayerDrewCardNotification +## - ItsYourTurn: ItsYourTurnNotification +## - ItsPlayersTurn: ItsPlayersTurnNotification +## - PlayerPassed: PlayerPassedNotification +## - PlayerPutCard: PlayerPutCardNotification +## - PlayerPutEight: PlayerPutEightNotification +## - GameEnded: GameEndedNotification +## - PlayerIsDone: PlayerIsDoneNotification +## - DiscardPileShuffled: DiscardPileShuffledNotification +## + +class_name CrazyEightsClient +extends RefCounted + +## Signals for game notifications +signal gameStarted(data: Dictionary) +signal playerDrewCard(data: Dictionary) +signal itsYourTurn(data: Dictionary) +signal itsPlayersTurn(data: Dictionary) +signal playerPassed(data: Dictionary) +signal playerPutCard(data: Dictionary) +signal playerPutEight(data: Dictionary) +signal gameEnded(data: Dictionary) +signal playerIsDone(data: Dictionary) +signal discardPileShuffled(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "CrazyEights.GameStartedNotification": + gameStarted.emit(notification) + "CrazyEights.PlayerDrewCardNotification": + playerDrewCard.emit(notification) + "CrazyEights.ItsYourTurnNotification": + itsYourTurn.emit(notification) + "CrazyEights.ItsPlayersTurnNotification": + itsPlayersTurn.emit(notification) + "CrazyEights.PlayerPassedNotification": + playerPassed.emit(notification) + "CrazyEights.PlayerPutCardNotification": + playerPutCard.emit(notification) + "CrazyEights.PlayerPutEightNotification": + playerPutEight.emit(notification) + "CrazyEights.GameEndedNotification": + gameEnded.emit(notification) + "CrazyEights.PlayerIsDoneNotification": + playerIsDone.emit(notification) + "CrazyEights.DiscardPileShuffledNotification": + discardPileShuffled.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## PutCard +func putCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "CrazyEights.PutCardRequest" + return await _send_request(request_data) + +## PutEight +func putEight(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "CrazyEights.PutEightRequest" + return await _send_request(request_data) + +## DrawCard +func drawCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "CrazyEights.DrawCardRequest" + return await _send_request(request_data) + +## Pass +func pass(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "CrazyEights.PassRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/generated/godot/gabong/GabongClient.gd b/generated/godot/gabong/GabongClient.gd new file mode 100644 index 00000000..1020ae2f --- /dev/null +++ b/generated/godot/gabong/GabongClient.gd @@ -0,0 +1,163 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## Gabong Game Client for Godot Engine +## +## Notifications (events) for this game: +## - GameStarted: GameStartedNotification +## - PlayerPutCard: PlayerPutCardNotification +## - PlayerDrewCard: PlayerDrewCardNotification +## - PlayerDrewPenaltyCard: PlayerDrewPenaltyCardNotification +## - GameEnded: GameEndedNotification +## - RoundStarted: RoundStartedNotification +## - RoundEnded: RoundEndedNotification +## - PlayerLostTheirTurn: PlayerLostTheirTurnNotification +## + +class_name GabongClient +extends RefCounted + +## Signals for game notifications +signal gameStarted(data: Dictionary) +signal playerPutCard(data: Dictionary) +signal playerDrewCard(data: Dictionary) +signal playerDrewPenaltyCard(data: Dictionary) +signal gameEnded(data: Dictionary) +signal roundStarted(data: Dictionary) +signal roundEnded(data: Dictionary) +signal playerLostTheirTurn(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "Gabong.GameStartedNotification": + gameStarted.emit(notification) + "Gabong.PlayerPutCardNotification": + playerPutCard.emit(notification) + "Gabong.PlayerDrewCardNotification": + playerDrewCard.emit(notification) + "Gabong.PlayerDrewPenaltyCardNotification": + playerDrewPenaltyCard.emit(notification) + "Gabong.GameEndedNotification": + gameEnded.emit(notification) + "Gabong.RoundStartedNotification": + roundStarted.emit(notification) + "Gabong.RoundEndedNotification": + roundEnded.emit(notification) + "Gabong.PlayerLostTheirTurnNotification": + playerLostTheirTurn.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## DrawCard +func drawCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Gabong.DrawCardRequest" + return await _send_request(request_data) + +## PlayGabong +func playGabong(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Gabong.PlayGabongRequest" + return await _send_request(request_data) + +## PlayBonga +func playBonga(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Gabong.PlayBongaRequest" + return await _send_request(request_data) + +## Pass +func pass(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Gabong.PassRequest" + return await _send_request(request_data) + +## PutCard +func putCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Gabong.PutCardRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/generated/godot/hearts/HeartsClient.gd b/generated/godot/hearts/HeartsClient.gd new file mode 100644 index 00000000..109b0f47 --- /dev/null +++ b/generated/godot/hearts/HeartsClient.gd @@ -0,0 +1,157 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## Hearts Game Client for Godot Engine +## +## Notifications (events) for this game: +## - GameStarted: GameStartedNotification +## - PassingPhaseStarted: PassingPhaseStartedNotification +## - AllPlayersPassed: AllPlayersPassedNotification +## - PlayerPassedCards: PlayerPassedCardsNotification +## - ItsYourTurn: ItsYourTurnNotification +## - ItsPlayersTurn: ItsPlayersTurnNotification +## - PlayerPlayedCard: PlayerPlayedCardNotification +## - TrickCompleted: TrickCompletedNotification +## - RoundEnded: RoundEndedNotification +## - GameEnded: GameEndedNotification +## - HeartsWereBroken: HeartsAreBrokenNotification +## + +class_name HeartsClient +extends RefCounted + +## Signals for game notifications +signal gameStarted(data: Dictionary) +signal passingPhaseStarted(data: Dictionary) +signal allPlayersPassed(data: Dictionary) +signal playerPassedCards(data: Dictionary) +signal itsYourTurn(data: Dictionary) +signal itsPlayersTurn(data: Dictionary) +signal playerPlayedCard(data: Dictionary) +signal trickCompleted(data: Dictionary) +signal roundEnded(data: Dictionary) +signal gameEnded(data: Dictionary) +signal heartsWereBroken(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "Hearts.GameStartedNotification": + gameStarted.emit(notification) + "Hearts.PassingPhaseStartedNotification": + passingPhaseStarted.emit(notification) + "Hearts.AllPlayersPassedNotification": + allPlayersPassed.emit(notification) + "Hearts.PlayerPassedCardsNotification": + playerPassedCards.emit(notification) + "Hearts.ItsYourTurnNotification": + itsYourTurn.emit(notification) + "Hearts.ItsPlayersTurnNotification": + itsPlayersTurn.emit(notification) + "Hearts.PlayerPlayedCardNotification": + playerPlayedCard.emit(notification) + "Hearts.TrickCompletedNotification": + trickCompleted.emit(notification) + "Hearts.RoundEndedNotification": + roundEnded.emit(notification) + "Hearts.GameEndedNotification": + gameEnded.emit(notification) + "Hearts.HeartsAreBrokenNotification": + heartsWereBroken.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## PassCards +func passCards(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Hearts.PassCardsRequest" + return await _send_request(request_data) + +## PlayCard +func playCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Hearts.PlayCardRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/generated/godot/idiot/IdiotClient.gd b/generated/godot/idiot/IdiotClient.gd new file mode 100644 index 00000000..52a2855c --- /dev/null +++ b/generated/godot/idiot/IdiotClient.gd @@ -0,0 +1,191 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## Idiot Game Client for Godot Engine +## +## Notifications (events) for this game: +## - ItsTimeToSwapCards: ItsTimeToSwapCardsNotification +## - PlayerIsReady: PlayerIsReadyNotification +## - GameHasStarted: GameStartedNotification +## - GameEnded: GameEndedNotification +## - ItsYourTurn: ItsYourTurnNotification +## - PlayerDrewCards: PlayerDrewCardsNotification +## - PlayerPutCards: PlayerPutCardsNotification +## - DiscardPileFlushed: DiscardPileFlushedNotification +## - PlayerIsDone: PlayerIsDoneNotification +## - PlayerSwappedCards: PlayerSwappedCardsNotification +## - PlayerAttemptedPuttingCard: PlayerAttemptedPuttingCardNotification +## - PlayerPulledInDiscardPile: PlayerPulledInDiscardPileNotification +## + +class_name IdiotClient +extends RefCounted + +## Signals for game notifications +signal itsTimeToSwapCards(data: Dictionary) +signal playerIsReady(data: Dictionary) +signal gameHasStarted(data: Dictionary) +signal gameEnded(data: Dictionary) +signal itsYourTurn(data: Dictionary) +signal playerDrewCards(data: Dictionary) +signal playerPutCards(data: Dictionary) +signal discardPileFlushed(data: Dictionary) +signal playerIsDone(data: Dictionary) +signal playerSwappedCards(data: Dictionary) +signal playerAttemptedPuttingCard(data: Dictionary) +signal playerPulledInDiscardPile(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "Idiot.ItsTimeToSwapCardsNotification": + itsTimeToSwapCards.emit(notification) + "Idiot.PlayerIsReadyNotification": + playerIsReady.emit(notification) + "Idiot.GameStartedNotification": + gameHasStarted.emit(notification) + "Idiot.GameEndedNotification": + gameEnded.emit(notification) + "Idiot.ItsYourTurnNotification": + itsYourTurn.emit(notification) + "Idiot.PlayerDrewCardsNotification": + playerDrewCards.emit(notification) + "Idiot.PlayerPutCardsNotification": + playerPutCards.emit(notification) + "Idiot.DiscardPileFlushedNotification": + discardPileFlushed.emit(notification) + "Idiot.PlayerIsDoneNotification": + playerIsDone.emit(notification) + "Idiot.PlayerSwappedCardsNotification": + playerSwappedCards.emit(notification) + "Idiot.PlayerAttemptedPuttingCardNotification": + playerAttemptedPuttingCard.emit(notification) + "Idiot.PlayerPulledInDiscardPileNotification": + playerPulledInDiscardPile.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## IamReady +func iamReady(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Idiot.IamReadyRequest" + return await _send_request(request_data) + +## SwapCards +func swapCards(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Idiot.SwapCardsRequest" + return await _send_request(request_data) + +## PutCardsFromHand +func putCardsFromHand(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Idiot.PutCardsFromHandRequest" + return await _send_request(request_data) + +## PutCardsFacingUp +func putCardsFacingUp(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Idiot.PutCardsFacingUpRequest" + return await _send_request(request_data) + +## PutCardFacingDown +func putCardFacingDown(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Idiot.PutCardFacingDownRequest" + return await _send_request(request_data) + +## PutChanceCard +func putChanceCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Idiot.PutChanceCardRequest" + return await _send_request(request_data) + +## PullInDiscardPile +func pullInDiscardPile(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Idiot.PullInDiscardPileRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/generated/godot/texasholdem/TexasHoldEmClient.gd b/generated/godot/texasholdem/TexasHoldEmClient.gd new file mode 100644 index 00000000..7769d607 --- /dev/null +++ b/generated/godot/texasholdem/TexasHoldEmClient.gd @@ -0,0 +1,169 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## TexasHoldEm Game Client for Godot Engine +## +## Notifications (events) for this game: +## - GameStarted: GameStartedNotification +## - ItsYourTurn: ItsYourTurnNotification +## - RoundStarted: NewRoundStartedNotification +## - RoundEnded: RoundEndedNotification +## - PlayerBetted: PlayerBettedNotification +## - PlayerAllIn: PlayerAllInNotification +## - PlayerChecked: PlayerCheckedNotification +## - PlayerFolded: PlayerFoldedNotification +## - PlayerCalled: PlayerCalledNotification +## - NewCardsRevealed: NewCardsRevealed +## - GameEnded: GameEndedNotification +## + +class_name TexasHoldEmClient +extends RefCounted + +## Signals for game notifications +signal gameStarted(data: Dictionary) +signal itsYourTurn(data: Dictionary) +signal roundStarted(data: Dictionary) +signal roundEnded(data: Dictionary) +signal playerBetted(data: Dictionary) +signal playerAllIn(data: Dictionary) +signal playerChecked(data: Dictionary) +signal playerFolded(data: Dictionary) +signal playerCalled(data: Dictionary) +signal newCardsRevealed(data: Dictionary) +signal gameEnded(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "TexasHoldEm.GameStartedNotification": + gameStarted.emit(notification) + "TexasHoldEm.ItsYourTurnNotification": + itsYourTurn.emit(notification) + "TexasHoldEm.NewRoundStartedNotification": + roundStarted.emit(notification) + "TexasHoldEm.RoundEndedNotification": + roundEnded.emit(notification) + "TexasHoldEm.PlayerBettedNotification": + playerBetted.emit(notification) + "TexasHoldEm.PlayerAllInNotification": + playerAllIn.emit(notification) + "TexasHoldEm.PlayerCheckedNotification": + playerChecked.emit(notification) + "TexasHoldEm.PlayerFoldedNotification": + playerFolded.emit(notification) + "TexasHoldEm.PlayerCalledNotification": + playerCalled.emit(notification) + "TexasHoldEm.NewCardsRevealed": + newCardsRevealed.emit(notification) + "TexasHoldEm.GameEndedNotification": + gameEnded.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## PlayerBetRequest +func playerBetRequest(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "TexasHoldEm.BetRequest" + return await _send_request(request_data) + +## PlayerFoldRequest +func playerFoldRequest(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "TexasHoldEm.FoldRequest" + return await _send_request(request_data) + +## PlayerCheckRequest +func playerCheckRequest(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "TexasHoldEm.CheckRequest" + return await _send_request(request_data) + +## PlayerCallRequest +func playerCallRequest(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "TexasHoldEm.CallRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/generated/godot/uno/UnoClient.gd b/generated/godot/uno/UnoClient.gd new file mode 100644 index 00000000..3315a2d6 --- /dev/null +++ b/generated/godot/uno/UnoClient.gd @@ -0,0 +1,153 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## Uno Game Client for Godot Engine +## +## Notifications (events) for this game: +## - GameStarted: GameStartedNotification +## - PlayerPutCard: PlayerPutCardNotification +## - PlayerPutWild: PlayerPutWildNotification +## - PlayerDrewCard: PlayerDrewCardNotification +## - PlayerPassed: PlayerPassedNotification +## - GameEnded: GameEndedNotification +## - ItsYourTurn: ItsYourTurnNotification +## + +class_name UnoClient +extends RefCounted + +## Signals for game notifications +signal gameStarted(data: Dictionary) +signal playerPutCard(data: Dictionary) +signal playerPutWild(data: Dictionary) +signal playerDrewCard(data: Dictionary) +signal playerPassed(data: Dictionary) +signal gameEnded(data: Dictionary) +signal itsYourTurn(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "Uno.GameStartedNotification": + gameStarted.emit(notification) + "Uno.PlayerPutCardNotification": + playerPutCard.emit(notification) + "Uno.PlayerPutWildNotification": + playerPutWild.emit(notification) + "Uno.PlayerDrewCardNotification": + playerDrewCard.emit(notification) + "Uno.PlayerPassedNotification": + playerPassed.emit(notification) + "Uno.GameEndedNotification": + gameEnded.emit(notification) + "Uno.ItsYourTurnNotification": + itsYourTurn.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## PutCard +func putCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Uno.PutCardRequest" + return await _send_request(request_data) + +## PutWild +func putWild(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Uno.PutWildRequest" + return await _send_request(request_data) + +## DrawCard +func drawCard(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Uno.DrawCardRequest" + return await _send_request(request_data) + +## Pass +func pass(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Uno.PassRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/generated/godot/yaniv/YanivClient.gd b/generated/godot/yaniv/YanivClient.gd new file mode 100644 index 00000000..4355f4e6 --- /dev/null +++ b/generated/godot/yaniv/YanivClient.gd @@ -0,0 +1,137 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## Yaniv Game Client for Godot Engine +## +## Notifications (events) for this game: +## - PlayerPutCards: PlayerPutCardsNotification +## - ItsYourTurn: ItsYourTurnNotification +## - RoundStarted: RoundStartedNotification +## - RoundEnded: RoundEndedNotification +## - GameEnded: GameEndedNotification +## - DiscardPileShuffled: DiscardPileShuffledNotification +## + +class_name YanivClient +extends RefCounted + +## Signals for game notifications +signal playerPutCards(data: Dictionary) +signal itsYourTurn(data: Dictionary) +signal roundStarted(data: Dictionary) +signal roundEnded(data: Dictionary) +signal gameEnded(data: Dictionary) +signal discardPileShuffled(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "Yaniv.PlayerPutCardsNotification": + playerPutCards.emit(notification) + "Yaniv.ItsYourTurnNotification": + itsYourTurn.emit(notification) + "Yaniv.RoundStartedNotification": + roundStarted.emit(notification) + "Yaniv.RoundEndedNotification": + roundEnded.emit(notification) + "Yaniv.GameEndedNotification": + gameEnded.emit(notification) + "Yaniv.DiscardPileShuffledNotification": + discardPileShuffled.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## CallYaniv +func callYaniv(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Yaniv.CallYanivRequest" + return await _send_request(request_data) + +## PutCards +func putCards(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "Yaniv.PutCardsRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/godot_clients/.gitignore b/godot_clients/.gitignore new file mode 100644 index 00000000..d42f8f90 --- /dev/null +++ b/godot_clients/.gitignore @@ -0,0 +1,6 @@ + +# Godot-specific +.godot/ +export_presets.cfg +*.import +*.translation \ No newline at end of file diff --git a/godot_clients/chat-sample-client/.editorconfig b/godot_clients/chat-sample-client/.editorconfig new file mode 100644 index 00000000..f28239ba --- /dev/null +++ b/godot_clients/chat-sample-client/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/godot_clients/chat-sample-client/.gitattributes b/godot_clients/chat-sample-client/.gitattributes new file mode 100644 index 00000000..8ad74f78 --- /dev/null +++ b/godot_clients/chat-sample-client/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/godot_clients/chat-sample-client/.gitignore b/godot_clients/chat-sample-client/.gitignore new file mode 100644 index 00000000..0af181cf --- /dev/null +++ b/godot_clients/chat-sample-client/.gitignore @@ -0,0 +1,3 @@ +# Godot 4+ specific ignores +.godot/ +/android/ diff --git a/godot_clients/chat-sample-client/ChatRoomClient.gd b/godot_clients/chat-sample-client/ChatRoomClient.gd new file mode 100644 index 00000000..cc314924 --- /dev/null +++ b/godot_clients/chat-sample-client/ChatRoomClient.gd @@ -0,0 +1,111 @@ +## +## Autogenerated by really, really eager small hamsters. +## +## ChatRoom Game Client for Godot Engine +## +## Notifications (events) for this game: +## - PlayerSaid: ChatNotification +## + +class_name ChatRoomClient +extends RefCounted + +## Signals for game notifications +signal playerSaid(data: Dictionary) + +## WebSocket connections +var _action_socket: WebSocketPeer +var _notification_socket: WebSocketPeer +var _pending_requests: Dictionary = {} +var _request_id_counter: int = 0 + +## Constructor +func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void: + _action_socket = action_socket + _notification_socket = notification_socket + +## Poll sockets for new messages. Call this regularly (e.g., in _process) +func poll() -> void: + _action_socket.poll() + _notification_socket.poll() + + # Process action socket responses + while _action_socket.get_available_packet_count() > 0: + var packet = _action_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var response = JSON.parse_string(json_string) + _handle_action_response(response) + + # Process notification socket messages + while _notification_socket.get_available_packet_count() > 0: + var packet = _notification_socket.get_packet() + var json_string = packet.get_string_from_utf8() + var notification = JSON.parse_string(json_string) + _handle_notification(notification) + +## Internal: Handle responses from action socket +func _handle_action_response(response: Dictionary) -> void: + if response.has("_request_id"): + var request_id = response["_request_id"] + if _pending_requests.has(request_id): + var callback = _pending_requests[request_id] + _pending_requests.erase(request_id) + callback.call(response) + +## Internal: Handle notifications from notification socket +func _handle_notification(notification: Dictionary) -> void: + if not notification.has("type"): + push_warning("Notification missing 'type' field") + return + + var msg_type = notification["type"] + match msg_type: + "ChatRoom.ChatNotification": + playerSaid.emit(notification) + _: + push_warning("Unknown notification type: " + msg_type) + +## Internal: Send a request and wait for response +func _send_request(request_data: Dictionary) -> Dictionary: + var request_id = _request_id_counter + _request_id_counter += 1 + request_data["_request_id"] = request_id + + var response_received = false + var response_data: Dictionary = {} + + var callback = func(response: Dictionary): + response_received = true + response_data = response + + _pending_requests[request_id] = callback + + var json_string = JSON.stringify(request_data) + _action_socket.send_text(json_string) + + # Wait for response (polling) + var timeout = 30.0 # 30 seconds timeout + var elapsed = 0.0 + while not response_received and elapsed < timeout: + poll() + await Engine.get_main_loop().process_frame + elapsed += Engine.get_main_loop().root.get_process_delta_time() + + if not response_received: + _pending_requests.erase(request_id) + push_error("Request timeout") + return {"hasError": true, "error": "Request timeout"} + + return response_data + +## ============================================ +## Game Action Methods +## ============================================ + +## ChatAsync +func chatAsync(request: Dictionary) -> Dictionary: + var request_data = request.duplicate() + request_data["type"] = "ChatRoom.SendChatRequest" + return await _send_request(request_data) + +## End of generated client diff --git a/godot_clients/chat-sample-client/ChatRoomClient.gd.uid b/godot_clients/chat-sample-client/ChatRoomClient.gd.uid new file mode 100644 index 00000000..1fefebae --- /dev/null +++ b/godot_clients/chat-sample-client/ChatRoomClient.gd.uid @@ -0,0 +1 @@ +uid://dnvplhooe10a7 diff --git a/godot_clients/chat-sample-client/QUICKSTART.md b/godot_clients/chat-sample-client/QUICKSTART.md new file mode 100644 index 00000000..924b2687 --- /dev/null +++ b/godot_clients/chat-sample-client/QUICKSTART.md @@ -0,0 +1,91 @@ +# Quick Start Guide + +## Step 1: Start the Deckster Server + +Open a terminal and run: + +```bash +cd src/Deckster.Server +dotnet run +``` + +Wait for the message: +``` +info: Microsoft.Hosting.Lifetime[14] + Now listening on: http://localhost:13992 +``` + +Note: The default port is 13992, not 5000! + +## Step 2: Run the Godot Client + +### Option A: Double-click +- Double-click `run.bat` in this folder + +### Option B: Command line +```bash +cd godot_clients/chat-sample-client +C:\godot\godot.exe --path . +``` + +### Option C: Open in Godot Editor +1. Open `C:\godot\godot.exe` +2. Click "Import" +3. Browse to this folder and select `project.godot` +4. Press F5 to run + +## Step 3: Connect and Chat + +1. The client opens with default settings: + - Server URL: `ws://localhost:13992` + - Room name: `godot-room` +2. (Optional) Change the room name to join a different room or create a new one +3. Click **Connect** - this will: + - Authenticate with the server + - Create/join the specified game room + - Connect via WebSockets +4. You'll see: "Connected! You can now send messages." +5. Type a message and press Enter or click **Send** + +## Step 4: Test with Multiple Clients + +### Option A: Run another Godot client +- Run `run.bat` again in a new window +- Or run the client again from Godot +- **Important**: Use the same room name in both clients to chat together! + +### Option B: Run the .NET sample client +```bash +cd src/Deckster.ChatRoom.SampleClient +dotnet run +# When prompted, enter the same room name (e.g., "godot-room") +``` + +Now send messages from either client - they'll appear in both! + +## What You'll See + +``` +Welcome to Deckster Chat Room! +Your name: Player123 +Click 'Connect' to join the chat room +Connecting to ws://localhost:5000... +Connected! You can now send messages. +Player123: Hello from Godot! +Player456: Hello from .NET! +``` + +## Troubleshooting + +**Can't connect?** +- Make sure the server is running (`dotnet run` in `src/Deckster.Server`) +- Check that nothing else is using port 13992 +- The client will show which step failed (Authentication, Create Room, or WebSocket connection) + +**Godot won't open?** +- Verify Godot is installed at `C:\godot\godot.exe` +- Or edit `run.bat` to point to your Godot installation + +**Messages not showing?** +- Check the Godot console (F12) for errors +- Verify you clicked "Connect" first diff --git a/godot_clients/chat-sample-client/README.md b/godot_clients/chat-sample-client/README.md new file mode 100644 index 00000000..95231a85 --- /dev/null +++ b/godot_clients/chat-sample-client/README.md @@ -0,0 +1,241 @@ +# Deckster Chat Room Sample Client (Godot) + +A sample Godot 4.5 client demonstrating how to use the auto-generated `ChatRoomClient.gd` to connect to a Deckster chat room server. + +## Prerequisites + +- Godot 4.5 (located at `C:\godot\godot.exe`) +- Deckster server running on `http://localhost:13992` (or another address) + +## Project Structure + +``` +chat-sample-client/ +├── ChatRoomClient.gd # Auto-generated client from Deckster.CodeGenerator +├── main.tscn # Main UI scene +├── main.gd # Main script that uses ChatRoomClient +├── project.godot # Godot project file +└── README.md # This file +``` + +## Running the Server + +Before running the client, start the Deckster server: + +```bash +# From the deckster repository root +cd src/Deckster.Server +dotnet run +``` + +The server should start on `http://localhost:13992` (WebSocket at `ws://localhost:13992`). + +## Running the Client + +### Option 1: Using Godot Editor + +1. Open Godot (`C:\godot\godot.exe`) +2. Click "Import" +3. Browse to this directory and select `project.godot` +4. Click "Import & Edit" +5. Press F5 to run the project + +### Option 2: Using Command Line + +```bash +cd godot_clients/chat-sample-client +C:\godot\godot.exe --path . --debug +``` + +### Option 3: Running Without Editor + +```bash +cd godot_clients/chat-sample-client +C:\godot\godot.exe --headless --path . --main-pack . +``` + +## Using the Client + +1. **Connect to Server**: + - The default server URL is `ws://localhost:13992` + - Change it if your server is running on a different address + - Enter a room name (default is `godot-room`) + - You can join existing rooms by entering their name + - If the room doesn't exist, it will be created + - Click "Connect" - this will automatically: + - Authenticate you with a random username + - Create/join the specified game room + - Connect via WebSockets + +2. **Send Messages**: + - Type your message in the input field + - Press Enter or click "Send" + - Your messages will appear in the chat log + +3. **Receive Messages**: + - Messages from other players appear in the chat log + - Your own messages are shown in light blue + - Other players' messages are shown in white + +4. **Disconnect**: + - Click "Disconnect" to close the connection + +## How It Works + +### ChatRoomClient.gd + +The `ChatRoomClient.gd` file is auto-generated from the Deckster server's API. It provides: + +**Signals (Notifications)**: +- `playerSaid(data: Dictionary)` - Emitted when any player sends a message + +**Methods (Actions)**: +- `chatAsync(request: Dictionary) -> Dictionary` - Send a message to the chat room +- `poll()` - Process incoming WebSocket messages (must be called regularly) + +### Authentication via Headers + +The client uses Godot 4's `set_handshake_headers()` method to send the Bearer token during the WebSocket handshake: + +```gdscript +var headers = PackedStringArray(["Authorization: Bearer " + auth_token]) +action_socket.set_handshake_headers(headers) +action_socket.connect_to_url(server_url + "/chatroom/join/" + game_id) +``` + +This works with the standard Deckster authentication that expects tokens in the `Authorization` header. + +### main.gd + +The main script demonstrates: + +1. **Authentication**: + ```gdscript + # POST to /login to get auth token + var response = await http.request(server_url + "/login", headers, POST, body) + auth_token = json["accessToken"] + ``` + +2. **Game Creation**: + ```gdscript + # POST to /chatroom/create/{roomname} with Bearer token + var response = await http.request(server_url + "/chatroom/create/godot-room", ...) + game_id = json["id"] + ``` + +3. **WebSocket Handshake**: + ```gdscript + # Set Authorization header for WebSocket handshake + var headers = PackedStringArray(["Authorization: Bearer " + auth_token]) + action_socket.set_handshake_headers(headers) + + # Connect to /chatroom/join/{game_id} + action_socket.connect_to_url(server_url + "/chatroom/join/" + game_id) + + # Wait for HelloSuccessMessage with connectionId + var hello = JSON.parse_string(action_socket.get_packet().get_string_from_utf8()) + connection_id = hello["connectionId"] + + # Connect notification socket with same auth header + notification_socket.set_handshake_headers(headers) + notification_socket.connect_to_url(server_url + "/chatroom/join/" + connection_id + "/finish") + + # Wait for ConnectSuccessMessage + # Now ready to use! + + client = ChatRoomClient.new(action_socket, notification_socket) + ``` + +4. **Listening for Notifications**: + ```gdscript + client.playerSaid.connect(_on_player_said) + + func _on_player_said(data: Dictionary): + var sender = data.get("sender", "Unknown") + var message = data.get("message", "") + add_to_chat("%s: %s" % [sender, message]) + ``` + +5. **Sending Messages**: + ```gdscript + var request = { + "message": message + } + var response = await client.chatAsync(request) + + if response.get("hasError", false): + print("Error: ", response.get("error")) + ``` + +6. **Polling for Messages**: + ```gdscript + func _process(_delta): + if client: + client.poll() + ``` + +## Key Features Demonstrated + +- ✅ HTTP authentication with bearer tokens +- ✅ RESTful game room creation +- ✅ WebSocket handshake protocol (HelloSuccessMessage, ConnectSuccessMessage) +- ✅ WebSocket connection management (dual sockets) +- ✅ Using auto-generated client class +- ✅ Signal-based event handling +- ✅ Async/await for sending actions +- ✅ Error handling with detailed step feedback +- ✅ Connection state management +- ✅ UI integration with RichTextLabel for chat + +## Testing with Multiple Clients + +To test the chat functionality: + +1. Run the Deckster server +2. Launch this Godot client +3. Run another instance: + - Open another terminal and run the client again, OR + - Run a .NET sample client: `cd src/Deckster.ChatRoom.SampleClient && dotnet run` + +Messages sent from any client will be broadcast to all connected clients! + +## Troubleshooting + +**"Authentication failed"**: +- Make sure the Deckster server is running +- Check the server URL is correct (should be `ws://localhost:13992`) +- Verify the server is listening on port 13992 + +**"Failed to create game"**: +- The server might not have the ChatRoom game registered +- Check server logs for errors + +**"Connection Failed"**: +- The server might take a moment to start accepting connections +- Try clicking Connect again after a few seconds + +**Messages not appearing**: +- Ensure `client.poll()` is being called in `_process()` +- Check the console for any error messages + +## Regenerating ChatRoomClient.gd + +If the server API changes, regenerate the client: + +```bash +cd src/Deckster.CodeGenerator +dotnet run +``` + +Then copy the updated file: + +```bash +cp generated/godot/chatroom/ChatRoomClient.gd godot_clients/chat-sample-client/ +``` + +## Notes + +- Player names are randomly generated on startup +- Connection state is maintained throughout the session +- WebSocket connections are properly cleaned up on exit +- The client uses Godot's built-in `WebSocketPeer` (Godot 4.x) diff --git a/godot_clients/chat-sample-client/TESTING.md b/godot_clients/chat-sample-client/TESTING.md new file mode 100644 index 00000000..3838314b --- /dev/null +++ b/godot_clients/chat-sample-client/TESTING.md @@ -0,0 +1,139 @@ +# Testing Guide + +## Recent Fixes Applied + +### Issue 1: WebSocket Connection Error +**Problem**: WebSocket connection was failing due to missing authentication. +**Solution**: Used Godot 4's `set_handshake_headers()` method to send the `Authorization: Bearer {token}` header during the WebSocket handshake. + +### Issue 2: Room Name Selection +**Problem**: All clients joined the same hardcoded room. +**Solution**: Added a room name input field so users can specify which room to join or create. + +## How to Test + +### Step 1: Ensure the Deckster Server is Running + +Make sure the server is running: + +```bash +cd src/Deckster.Server +dotnet run +``` + +Wait for the server to start and show: +``` +info: Microsoft.Hosting.Lifetime[14] + Now listening on: http://localhost:13992 +``` + +### Step 2: Run the Godot Client + +#### Option A: Using the batch file +```bash +cd godot_clients/chat-sample-client +run.bat +``` + +#### Option B: Using Godot directly +```bash +cd godot_clients/chat-sample-client +C:\godot\godot.exe --path . +``` + +### Step 3: Test the Connection + +1. **Verify Settings**: + - Server URL: `ws://localhost:13992` (default) + - Room name: `godot-room` (default, or enter a custom room name) +2. **Click Connect**: Watch the status messages: + - `Step 1: Authenticating...` - Should succeed + - `Step 2: Joining room '...'...` - Should succeed + - `Step 3: Connecting to game...` - Should succeed +3. **Send a Message**: Type a message and press Enter +4. **Verify Receipt**: Your message should appear in the chat log + +### Step 4: Test with Multiple Clients + +#### Option A: Run another Godot instance +1. Run `run.bat` again in a new terminal window +2. **Important**: Enter the same room name in both clients to chat together +3. Click Connect in the second client + +#### Option B: Run the .NET sample client +```bash +cd src/Deckster.ChatRoom.SampleClient +dotnet run +# When prompted, enter the same room name (e.g., "godot-room") +``` + +Send messages from both clients and verify they appear in both chat windows. + +## Expected Behavior + +### Successful Connection +``` +Your name: GodotPlayer123 +Click 'Connect' to join the chat room +Step 1: Authenticating... +Authenticated as GodotPlayer123 +Step 2: Joining room 'godot-room'... +Game room created: godot-room +Step 3: Connecting to game... +Action socket connected (ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) +Notification socket connected +Connected! You can now send messages. +Status: Connected to 'godot-room' as GodotPlayer123 +``` + +### Successful Message Exchange +``` +GodotPlayer123: Hello from Godot! +GodotPlayer456: Hello from another client! +``` + +## Troubleshooting + +### Authentication Fails +- Ensure the server is running on port 13992 +- Check server logs for errors +- Verify the server has been restarted after the authentication changes + +### Connection Timeout +- Check firewall settings +- Ensure no other process is using port 13992 +- Try restarting both server and client + +### Messages Not Appearing +- Verify `client.poll()` is being called in `_process()` +- Check the Godot console (View → Tool Windows → Output) for errors +- Ensure both sockets connected successfully + +## Technical Details + +### Authentication Flow +1. **HTTP Login** (`POST /login`) + - Sends: `{"username": "GodotPlayerXXX", "password": "godot123"}` + - Receives: `{"accessToken": "..."}` + +2. **Game Creation** (`POST /chatroom/create/godot-room`) + - Header: `Authorization: Bearer {token}` + - Receives: `{"id": "godot-room"}` + +3. **WebSocket Handshake** + - Set authentication header: + ```gdscript + var headers = PackedStringArray(["Authorization: Bearer " + auth_token]) + action_socket.set_handshake_headers(headers) + ``` + - Action Socket: `ws://localhost:13992/chatroom/join/godot-room` + - Receives: `HelloSuccessMessage` with `connectionId` + - Notification Socket: `ws://localhost:13992/chatroom/join/{connectionId}/finish` + - Receives: `ConnectSuccessMessage` + +4. **Ready to Play** + - Send actions via action socket + - Receive notifications via notification socket + +### Authentication Method +The client uses Godot 4's `set_handshake_headers()` method to send the Bearer token in the `Authorization` header during the WebSocket handshake. This works with the standard Deckster server authentication without any server-side modifications. diff --git a/godot_clients/chat-sample-client/icon.svg b/godot_clients/chat-sample-client/icon.svg new file mode 100644 index 00000000..c6bbb7d8 --- /dev/null +++ b/godot_clients/chat-sample-client/icon.svg @@ -0,0 +1 @@ + diff --git a/godot_clients/chat-sample-client/main.gd b/godot_clients/chat-sample-client/main.gd new file mode 100644 index 00000000..cbc2030e --- /dev/null +++ b/godot_clients/chat-sample-client/main.gd @@ -0,0 +1,381 @@ +extends Control + +## WebSocket connections +var action_socket: WebSocketPeer +var notification_socket: WebSocketPeer + +## Chat client +var client: ChatRoomClient + +## Auth and game info +var auth_token: String = "" +var connection_id: String = "" +var player_id: String = "" +var player_name: String = "" +var game_id: String = "" +var is_connected: bool = false + +## UI References +@onready var server_input: LineEdit = $VBoxContainer/ConnectionContainer/ServerInput +@onready var room_input: LineEdit = $VBoxContainer/ConnectionContainer/RoomInput +@onready var connect_button: Button = $VBoxContainer/ConnectionContainer/ConnectButton +@onready var status_label: Label = $VBoxContainer/StatusLabel +@onready var chat_log: RichTextLabel = $VBoxContainer/ChatLog +@onready var message_input: LineEdit = $VBoxContainer/InputContainer/MessageInput +@onready var send_button: Button = $VBoxContainer/InputContainer/SendButton + +func _ready(): + # Generate random player name + player_name = "GodotPlayer" + str(randi() % 1000) + + # Connect UI signals + connect_button.pressed.connect(_on_connect_button_pressed) + send_button.pressed.connect(_on_send_button_pressed) + message_input.text_submitted.connect(_on_message_submitted) + + # Disable send controls initially + message_input.editable = false + send_button.disabled = true + + add_to_chat("[color=yellow]Your name: %s[/color]" % player_name) + add_to_chat("[color=gray]Click 'Connect' to join the chat room[/color]") + +func _process(_delta): + # Poll the client every frame to process messages + if client and is_connected: + client.poll() + + # Check WebSocket states + if action_socket: + action_socket.poll() + var state = action_socket.get_ready_state() + if state == WebSocketPeer.STATE_CLOSED: + _handle_disconnection() + + if notification_socket: + notification_socket.poll() + +func _on_connect_button_pressed(): + if is_connected: + disconnect_from_server() + else: + connect_to_server() + +func connect_to_server(): + var server_url = server_input.text + if server_url.is_empty(): + add_to_chat("[color=red]Error: Please enter a server URL[/color]") + return + + var room_name = room_input.text.strip_edges() + if room_name.is_empty(): + add_to_chat("[color=red]Error: Please enter a room name[/color]") + return + + add_to_chat("[color=cyan]Step 1: Authenticating...[/color]") + status_label.text = "Status: Authenticating..." + connect_button.disabled = true + + # Step 1: Login to get auth token + if not await login(server_url): + connect_button.disabled = false + return + + add_to_chat("[color=cyan]Step 2: Joining room '%s'...[/color]" % room_name) + status_label.text = "Status: Joining room..." + + # Step 2: Create a game room (or join if it exists) + if not await create_game(server_url, room_name): + connect_button.disabled = false + return + + add_to_chat("[color=cyan]Step 3: Connecting to game...[/color]") + status_label.text = "Status: Connecting..." + + # Step 3: Connect to the game via WebSocket + if not await connect_websockets(server_url): + connect_button.disabled = false + return + + # Success! + initialize_client() + +func login(server_url: String) -> bool: + # Convert ws:// to http:// + var http_url = server_url.replace("ws://", "http://").replace("wss://", "https://") + + var http = HTTPRequest.new() + add_child(http) + + var body = JSON.stringify({ + "username": player_name, + "password": "godot123" + }) + + var headers = ["Content-Type: application/json"] + http.request(http_url + "/login", headers, HTTPClient.METHOD_POST, body) + + var response = await http.request_completed + http.queue_free() + + var result = response[0] + var response_code = response[1] + var response_body = response[3] + + if result != HTTPRequest.RESULT_SUCCESS or response_code != 200: + add_to_chat("[color=red]Authentication failed: %d[/color]" % response_code) + status_label.text = "Status: Auth Failed" + return false + + var json = JSON.parse_string(response_body.get_string_from_utf8()) + if json == null or not json.has("accessToken"): + add_to_chat("[color=red]Invalid auth response[/color]") + status_label.text = "Status: Auth Failed" + return false + + auth_token = json["accessToken"] + add_to_chat("[color=green]Authenticated as %s[/color]" % player_name) + return true + +func create_game(server_url: String, room_name: String) -> bool: + var http_url = server_url.replace("ws://", "http://").replace("wss://", "https://") + + var http = HTTPRequest.new() + add_child(http) + + var headers = [ + "Content-Type: application/json", + "Authorization: Bearer " + auth_token + ] + + http.request(http_url + "/chatroom/create/" + room_name, headers, HTTPClient.METHOD_POST, "") + + var response = await http.request_completed + http.queue_free() + + var result = response[0] + var response_code = response[1] + var response_body = response[3] + + if result != HTTPRequest.RESULT_SUCCESS or response_code != 200: + add_to_chat("[color=red]Failed to create game: %d[/color]" % response_code) + add_to_chat("[color=gray]%s[/color]" % response_body.get_string_from_utf8()) + status_label.text = "Status: Create Failed" + return false + + var json = JSON.parse_string(response_body.get_string_from_utf8()) + if json == null or not json.has("id"): + add_to_chat("[color=red]Invalid create game response[/color]") + status_label.text = "Status: Create Failed" + return false + + game_id = json["id"] + add_to_chat("[color=green]Game room created: %s[/color]" % game_id) + return true + +func connect_websockets(server_url: String) -> bool: + # Step 3a: Connect action socket + action_socket = WebSocketPeer.new() + + # Set the Authorization header for the WebSocket handshake + var headers = PackedStringArray(["Authorization: Bearer " + auth_token]) + action_socket.set_handshake_headers(headers) + + var action_url = server_url + "/chatroom/join/" + game_id + var err = action_socket.connect_to_url(action_url) + + if err != OK: + add_to_chat("[color=red]Failed to connect action socket: %d[/color]" % err) + status_label.text = "Status: Connection Failed" + return false + + # Wait for connection + for i in range(50): # 5 second timeout + action_socket.poll() + if action_socket.get_ready_state() == WebSocketPeer.STATE_OPEN: + break + await get_tree().create_timer(0.1).timeout + + if action_socket.get_ready_state() != WebSocketPeer.STATE_OPEN: + add_to_chat("[color=red]Action socket failed to connect[/color]") + status_label.text = "Status: Connection Failed" + return false + + # Wait for HelloSuccessMessage + for i in range(50): + action_socket.poll() + if action_socket.get_available_packet_count() > 0: + break + await get_tree().create_timer(0.1).timeout + + if action_socket.get_available_packet_count() == 0: + add_to_chat("[color=red]No hello message received[/color]") + status_label.text = "Status: Handshake Failed" + return false + + var packet = action_socket.get_packet() + var hello_json = JSON.parse_string(packet.get_string_from_utf8()) + + if hello_json == null or not hello_json.has("connectionId"): + add_to_chat("[color=red]Invalid hello message[/color]") + status_label.text = "Status: Handshake Failed" + return false + + connection_id = hello_json["connectionId"] + if hello_json.has("player"): + player_id = hello_json["player"].get("id", "") + + add_to_chat("[color=green]Action socket connected (ID: %s)[/color]" % connection_id) + + # Step 3b: Connect notification socket + notification_socket = WebSocketPeer.new() + + # Set the Authorization header for the notification socket as well + notification_socket.set_handshake_headers(headers) + + var notification_url = server_url + "/chatroom/join/" + connection_id + "/finish" + err = notification_socket.connect_to_url(notification_url) + + if err != OK: + add_to_chat("[color=red]Failed to connect notification socket: %d[/color]" % err) + status_label.text = "Status: Connection Failed" + return false + + # Wait for connection + for i in range(50): + notification_socket.poll() + if notification_socket.get_ready_state() == WebSocketPeer.STATE_OPEN: + break + await get_tree().create_timer(0.1).timeout + + if notification_socket.get_ready_state() != WebSocketPeer.STATE_OPEN: + add_to_chat("[color=red]Notification socket failed to connect[/color]") + status_label.text = "Status: Connection Failed" + return false + + # Wait for ConnectSuccessMessage + for i in range(50): + notification_socket.poll() + if notification_socket.get_available_packet_count() > 0: + break + await get_tree().create_timer(0.1).timeout + + if notification_socket.get_available_packet_count() > 0: + var _finish_packet = notification_socket.get_packet() + # Just consume the finish message + + add_to_chat("[color=green]Notification socket connected[/color]") + return true + +func initialize_client(): + # Create the chat client + client = ChatRoomClient.new(action_socket, notification_socket) + + # Connect to game notification signals + client.playerSaid.connect(_on_player_said) + + is_connected = true + status_label.text = "Status: Connected to '%s' as %s" % [game_id, player_name] + connect_button.text = "Disconnect" + connect_button.disabled = false + server_input.editable = false + room_input.editable = false + + # Enable send controls + message_input.editable = true + send_button.disabled = false + message_input.grab_focus() + + add_to_chat("[color=green]Connected! You can now send messages.[/color]") + +func disconnect_from_server(): + if action_socket: + action_socket.close() + if notification_socket: + notification_socket.close() + + _handle_disconnection() + +func _handle_disconnection(): + is_connected = false + status_label.text = "Status: Disconnected" + connect_button.text = "Connect" + connect_button.disabled = false + server_input.editable = true + room_input.editable = true + + # Disable send controls + message_input.editable = false + send_button.disabled = true + + add_to_chat("[color=yellow]Disconnected from server[/color]") + +## ==================================================== +## Signal Handlers (Game Notifications) +## ==================================================== + +func _on_player_said(data: Dictionary): + var sender = data.get("sender", "Unknown") + var message = data.get("message", "") + + # Color our own messages differently + if sender == player_name: + add_to_chat("[color=lightblue][b]%s:[/b] %s[/color]" % [sender, message]) + else: + add_to_chat("[b]%s:[/b] %s" % [sender, message]) + +## ==================================================== +## Game Action Methods +## ==================================================== + +func send_message(message: String): + if not is_connected or not client: + add_to_chat("[color=red]Error: Not connected to server[/color]") + return + + if message.is_empty(): + return + + var request = { + "message": message + } + + # All action methods are async and return a response + var response = await client.chatAsync(request) + + # Check for errors + if response.get("hasError", false): + var error = response.get("error", "Unknown error") + add_to_chat("[color=red]Failed to send message: %s[/color]" % error) + # Note: We don't need to add our message to chat here because + # the server will broadcast it back to us via the playerSaid notification + +## ==================================================== +## UI Event Handlers +## ==================================================== + +func _on_send_button_pressed(): + var message = message_input.text.strip_edges() + if message.is_empty(): + return + + send_message(message) + message_input.clear() + +func _on_message_submitted(text: String): + _on_send_button_pressed() + +## ==================================================== +## Helper Methods +## ==================================================== + +func add_to_chat(text: String): + chat_log.append_text(text + "\n") + # Auto-scroll is enabled in the scene + +## ==================================================== +## Cleanup +## ==================================================== + +func _exit_tree(): + disconnect_from_server() diff --git a/godot_clients/chat-sample-client/main.gd.uid b/godot_clients/chat-sample-client/main.gd.uid new file mode 100644 index 00000000..3b9106a4 --- /dev/null +++ b/godot_clients/chat-sample-client/main.gd.uid @@ -0,0 +1 @@ +uid://bucwnm6rme4mu diff --git a/godot_clients/chat-sample-client/main.tscn b/godot_clients/chat-sample-client/main.tscn new file mode 100644 index 00000000..f260375d --- /dev/null +++ b/godot_clients/chat-sample-client/main.tscn @@ -0,0 +1,89 @@ +[gd_scene load_steps=2 format=3 uid="uid://b3wyhyakr8f7c"] + +[ext_resource type="Script" path="res://main.gd" id="1_3vkqp"] + +[node name="Main" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_3vkqp") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 20.0 +offset_top = 20.0 +offset_right = -20.0 +offset_bottom = -20.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="TitleLabel" type="Label" parent="VBoxContainer"] +layout_mode = 2 +theme_override_font_sizes/font_size = 24 +text = "Deckster Chat Room Client" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="ConnectionContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="ServerLabel" type="Label" parent="VBoxContainer/ConnectionContainer"] +layout_mode = 2 +text = "Server:" + +[node name="ServerInput" type="LineEdit" parent="VBoxContainer/ConnectionContainer"] +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 +text = "ws://localhost:13992" +placeholder_text = "ws://localhost:13992" + +[node name="RoomLabel" type="Label" parent="VBoxContainer/ConnectionContainer"] +layout_mode = 2 +text = "Room:" + +[node name="RoomInput" type="LineEdit" parent="VBoxContainer/ConnectionContainer"] +custom_minimum_size = Vector2(150, 0) +layout_mode = 2 +text = "godot-room" +placeholder_text = "room name" + +[node name="ConnectButton" type="Button" parent="VBoxContainer/ConnectionContainer"] +layout_mode = 2 +text = "Connect" + +[node name="StatusLabel" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Status: Disconnected" + +[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="ChatLog" type="RichTextLabel" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +bbcode_enabled = true +text = "[color=gray]Welcome to Deckster Chat Room![/color]" +scroll_following = true + +[node name="HSeparator3" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="InputContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="MessageInput" type="LineEdit" parent="VBoxContainer/InputContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Type your message here..." + +[node name="SendButton" type="Button" parent="VBoxContainer/InputContainer"] +layout_mode = 2 +text = "Send" diff --git a/godot_clients/chat-sample-client/project.godot b/godot_clients/chat-sample-client/project.godot new file mode 100644 index 00000000..edfa1e38 --- /dev/null +++ b/godot_clients/chat-sample-client/project.godot @@ -0,0 +1,16 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="ChatSampleClient" +run/main_scene="res://main.tscn" +config/features=PackedStringArray("4.5", "Forward Plus") +config/icon="res://icon.svg" diff --git a/godot_clients/chat-sample-client/run.bat b/godot_clients/chat-sample-client/run.bat new file mode 100644 index 00000000..597d1f6f --- /dev/null +++ b/godot_clients/chat-sample-client/run.bat @@ -0,0 +1,3 @@ +@echo off +echo Starting Deckster Chat Room Client... +C:\godot\godot.exe --path . %* diff --git a/src/Deckster.CodeGenerator/Generators/GodotClientGenerator.cs b/src/Deckster.CodeGenerator/Generators/GodotClientGenerator.cs new file mode 100644 index 00000000..46793dc9 --- /dev/null +++ b/src/Deckster.CodeGenerator/Generators/GodotClientGenerator.cs @@ -0,0 +1,250 @@ +using Deckster.Core.Extensions; +using Deckster.Games.CodeGeneration.Meta; + +namespace Deckster.CodeGenerator.Generators; + +public class GodotClientGenerator : ClientGenerator +{ + public GodotClientGenerator(GameMeta meta, string className) + { + Source + .AppendLine("##") + .AppendLine("## Autogenerated by really, really eager small hamsters.") + .AppendLine("##") + .AppendLine($"## {meta.Name} Game Client for Godot Engine") + .AppendLine("##") + .AppendLine("## Notifications (events) for this game:") + .AppendLines(meta.Notifications.Select(n => $"## - {n.Name}: {n.Message.Name}")) + .AppendLine("##") + .AppendLine() + .AppendLine($"class_name {className}") + .AppendLine("extends RefCounted") + .AppendLine(); + + // Signals (events) for notifications + if (meta.Notifications.Any()) + { + Source.AppendLine("## Signals for game notifications"); + foreach (var notification in meta.Notifications) + { + Source.AppendLine($"signal {notification.Name.ToCamelCase()}(data: Dictionary)"); + } + Source.AppendLine(); + } + + // Member variables + Source + .AppendLine("## WebSocket connections") + .AppendLine("var _action_socket: WebSocketPeer") + .AppendLine("var _notification_socket: WebSocketPeer") + .AppendLine("var _pending_requests: Dictionary = {}") + .AppendLine("var _request_id_counter: int = 0") + .AppendLine(); + + // Constructor + Source.AppendLine("## Constructor"); + Source.AppendLine("func _init(action_socket: WebSocketPeer, notification_socket: WebSocketPeer) -> void:"); + using (Source.Indent()) + { + Source + .AppendLine("_action_socket = action_socket") + .AppendLine("_notification_socket = notification_socket"); + } + Source.AppendLine(); + + // Poll method (should be called regularly) + Source.AppendLine("## Poll sockets for new messages. Call this regularly (e.g., in _process)"); + Source.AppendLine("func poll() -> void:"); + using (Source.Indent()) + { + Source + .AppendLine("_action_socket.poll()") + .AppendLine("_notification_socket.poll()") + .AppendLine() + .AppendLine("# Process action socket responses") + .AppendLine("while _action_socket.get_available_packet_count() > 0:"); + using (Source.Indent()) + { + Source + .AppendLine("var packet = _action_socket.get_packet()") + .AppendLine("var json_string = packet.get_string_from_utf8()") + .AppendLine("var response = JSON.parse_string(json_string)") + .AppendLine("_handle_action_response(response)"); + } + Source.AppendLine() + .AppendLine("# Process notification socket messages") + .AppendLine("while _notification_socket.get_available_packet_count() > 0:"); + using (Source.Indent()) + { + Source + .AppendLine("var packet = _notification_socket.get_packet()") + .AppendLine("var json_string = packet.get_string_from_utf8()") + .AppendLine("var notification = JSON.parse_string(json_string)") + .AppendLine("_handle_notification(notification)"); + } + } + Source.AppendLine(); + + // Handle action response + Source.AppendLine("## Internal: Handle responses from action socket"); + Source.AppendLine("func _handle_action_response(response: Dictionary) -> void:"); + using (Source.Indent()) + { + Source.AppendLine("if response.has(\"_request_id\"):"); + using (Source.Indent()) + { + Source + .AppendLine("var request_id = response[\"_request_id\"]") + .AppendLine("if _pending_requests.has(request_id):"); + using (Source.Indent()) + { + Source + .AppendLine("var callback = _pending_requests[request_id]") + .AppendLine("_pending_requests.erase(request_id)") + .AppendLine("callback.call(response)"); + } + } + } + Source.AppendLine(); + + // Handle notification + Source.AppendLine("## Internal: Handle notifications from notification socket"); + Source.AppendLine("func _handle_notification(notification: Dictionary) -> void:"); + using (Source.Indent()) + { + Source.AppendLine("if not notification.has(\"type\"):"); + using (Source.Indent()) + { + Source.AppendLine("push_warning(\"Notification missing 'type' field\")"); + Source.AppendLine("return"); + } + Source.AppendLine(); + Source.AppendLine("var msg_type = notification[\"type\"]"); + Source.AppendLine("match msg_type:"); + using (Source.Indent()) + { + foreach (var notification in meta.Notifications) + { + Source.AppendLine($"\"{notification.Message.Type}\":"); + using (Source.Indent()) + { + Source.AppendLine($"{notification.Name.ToCamelCase()}.emit(notification)"); + } + } + Source.AppendLine("_:"); + using (Source.Indent()) + { + Source.AppendLine("push_warning(\"Unknown notification type: \" + msg_type)"); + } + } + } + Source.AppendLine(); + + // Send request helper + Source.AppendLine("## Internal: Send a request and wait for response"); + Source.AppendLine("func _send_request(request_data: Dictionary) -> Dictionary:"); + using (Source.Indent()) + { + Source + .AppendLine("var request_id = _request_id_counter") + .AppendLine("_request_id_counter += 1") + .AppendLine("request_data[\"_request_id\"] = request_id") + .AppendLine() + .AppendLine("var response_received = false") + .AppendLine("var response_data: Dictionary = {}") + .AppendLine() + .AppendLine("var callback = func(response: Dictionary):"); + using (Source.Indent()) + { + Source + .AppendLine("response_received = true") + .AppendLine("response_data = response"); + } + Source + .AppendLine() + .AppendLine("_pending_requests[request_id] = callback") + .AppendLine() + .AppendLine("var json_string = JSON.stringify(request_data)") + .AppendLine("_action_socket.send_text(json_string)") + .AppendLine() + .AppendLine("# Wait for response (polling)") + .AppendLine("var timeout = 30.0 # 30 seconds timeout") + .AppendLine("var elapsed = 0.0") + .AppendLine("while not response_received and elapsed < timeout:"); + using (Source.Indent()) + { + Source + .AppendLine("poll()") + .AppendLine("await Engine.get_main_loop().process_frame") + .AppendLine("elapsed += Engine.get_main_loop().root.get_process_delta_time()"); + } + Source + .AppendLine() + .AppendLine("if not response_received:"); + using (Source.Indent()) + { + Source + .AppendLine("_pending_requests.erase(request_id)") + .AppendLine("push_error(\"Request timeout\")") + .AppendLine("return {\"hasError\": true, \"error\": \"Request timeout\"}"); + } + Source + .AppendLine() + .AppendLine("return response_data"); + } + Source.AppendLine(); + + // Game methods + if (meta.Methods.Any()) + { + Source.AppendLine("## ============================================"); + Source.AppendLine("## Game Action Methods"); + Source.AppendLine("## ============================================"); + Source.AppendLine(); + + foreach (var method in meta.Methods) + { + var parameters = string.Join(", ", method.Parameters.Select(p => $"{p.Name}: Dictionary")); + var methodName = method.Name.ToCamelCase(); + + Source.AppendLine($"## {method.Name}"); + Source.AppendLine($"func {methodName}({parameters}) -> Dictionary:"); + using (Source.Indent()) + { + // Build request payload + if (method.Parameters.Count() == 1) + { + var param = method.Parameters.First(); + Source + .AppendLine($"var request_data = {param.Name}.duplicate()") + .AppendLine($"request_data[\"type\"] = \"{param.Type.Type}\""); + } + else if (method.Parameters.Any()) + { + Source.AppendLine("var request_data = {"); + using (Source.Indent()) + { + foreach (var param in method.Parameters) + { + Source.AppendLine($"\"{param.Name}\": {param.Name},"); + } + Source.AppendLine("\"type\": \"Unknown\""); + } + Source.AppendLine("}"); + } + else + { + Source.AppendLine("var request_data = {\"type\": \"Unknown\"}"); + } + + Source + .AppendLine("return await _send_request(request_data)"); + } + Source.AppendLine(); + } + } + + // Close class (implicit in GDScript, just add comment) + Source.AppendLine("## End of generated client"); + } +} diff --git a/src/Deckster.CodeGenerator/Program.cs b/src/Deckster.CodeGenerator/Program.cs index 229cdf54..0ca9455e 100644 --- a/src/Deckster.CodeGenerator/Program.cs +++ b/src/Deckster.CodeGenerator/Program.cs @@ -89,6 +89,7 @@ private static async Task GenerateClientsAsync(DirectoryInfo gitDirectory) .ToArray(); var kotlinDirectory = gitDirectory.GetCleanSubDirectory("generated", "kotlin"); + var godotDirectory = gitDirectory.GetCleanSubDirectory("generated", "godot"); var typeScriptDirectory = gitDirectory.GetSubDirectory("generated", "typescript"); if (!typeScriptDirectory.Exists) { @@ -125,6 +126,7 @@ private static async Task GenerateClientsAsync(DirectoryInfo gitDirectory) if (GameMeta.TryGetFor(type, out var game)) { await GenerateKotlinAsync(kotlinDirectory, type, game); + await GenerateGodotAsync(godotDirectory, type, game); gameClients.Add((type, game, gameMeta)); } } @@ -227,4 +229,14 @@ private static async Task GenerateTypeScriptAsync(DirectoryInfo typeScriptDirect var typeScript = new TypeScriptClientGenerator(game, ns, gameSpecificTypeNames); await typeScript.WriteToAsync(file); } + + private static async Task GenerateGodotAsync(DirectoryInfo godotDirectory, Type type, GameMeta game) + { + var ns = type.Namespace?.Split('.').LastOrDefault()?.ToLowerInvariant() ?? throw new Exception($"OMG CANT HAZ NAEMSPAZE OF ITZ TAYP '{type.Name}'"); + var file = godotDirectory.GetFile(ns, $"{game.Name}Client.gd"); + + Console.WriteLine(file); + var godot = new GodotClientGenerator(game, $"{game.Name}Client"); + await godot.WriteToAsync(file); + } } From 35c84cf30dc12772199e5e8281040ebdad30907e Mon Sep 17 00:00:00 2001 From: stho Date: Sat, 11 Oct 2025 17:13:19 +0200 Subject: [PATCH 26/26] Godot chat client --- .../chat-sample-client/QUICKSTART.md | 24 ++++- godot_clients/chat-sample-client/README.md | 75 +++++++++++--- godot_clients/chat-sample-client/main.gd | 99 ++++++++++++++++++- godot_clients/chat-sample-client/main.tscn | 27 ++++- 4 files changed, 201 insertions(+), 24 deletions(-) diff --git a/godot_clients/chat-sample-client/QUICKSTART.md b/godot_clients/chat-sample-client/QUICKSTART.md index 924b2687..bd1e994b 100644 --- a/godot_clients/chat-sample-client/QUICKSTART.md +++ b/godot_clients/chat-sample-client/QUICKSTART.md @@ -12,7 +12,7 @@ dotnet run Wait for the message: ``` info: Microsoft.Hosting.Lifetime[14] - Now listening on: http://localhost:13992 + Now listening on: http://localhost:13992 ``` Note: The default port is 13992, not 5000! @@ -34,17 +34,31 @@ C:\godot\godot.exe --path . 3. Browse to this folder and select `project.godot` 4. Press F5 to run -## Step 3: Connect and Chat +## Step 3: Browse Rooms and Connect 1. The client opens with default settings: - Server URL: `ws://localhost:13992` - Room name: `godot-room` -2. (Optional) Change the room name to join a different room or create a new one -3. Click **Connect** - this will: + +2. Connect to a room: + + **Option A: Browse and Join Existing Room** + - Click **Refresh** to see all active rooms + - Click **Join** next to any room to connect directly + - This joins the existing room (no creation attempt) + + **Option B: Create or Join Manually** + - Enter a room name to join/create + - Click **Connect** + - Creates the room if it doesn't exist + +3. Once connected, the client will: - Authenticate with the server - Create/join the specified game room - Connect via WebSockets + 4. You'll see: "Connected! You can now send messages." + 5. Type a message and press Enter or click **Send** ## Step 4: Test with Multiple Clients @@ -52,7 +66,7 @@ C:\godot\godot.exe --path . ### Option A: Run another Godot client - Run `run.bat` again in a new window - Or run the client again from Godot -- **Important**: Use the same room name in both clients to chat together! +- **Important**: Join the same room (use Refresh and Join, or enter the same room name) ### Option B: Run the .NET sample client ```bash diff --git a/godot_clients/chat-sample-client/README.md b/godot_clients/chat-sample-client/README.md index 95231a85..46d8b27d 100644 --- a/godot_clients/chat-sample-client/README.md +++ b/godot_clients/chat-sample-client/README.md @@ -56,28 +56,34 @@ C:\godot\godot.exe --headless --path . --main-pack . ## Using the Client -1. **Connect to Server**: +1. **Browse and Join Existing Rooms**: + - Click "Refresh" to see a list of available rooms + - Each room shows the room name and number of players + - Click "Join" next to any room to connect directly + - This joins the existing room without trying to create it + +2. **Create or Join Room Manually** (Alternative): - The default server URL is `ws://localhost:13992` - Change it if your server is running on a different address - Enter a room name (default is `godot-room`) - - You can join existing rooms by entering their name - - If the room doesn't exist, it will be created + - If the room doesn't exist, it will be created + - If it already exists, you'll join it - Click "Connect" - this will automatically: - - Authenticate you with a random username - - Create/join the specified game room - - Connect via WebSockets + - Authenticate you with a random username + - Create/join the specified game room + - Connect via WebSockets -2. **Send Messages**: +3. **Send Messages**: - Type your message in the input field - Press Enter or click "Send" - Your messages will appear in the chat log -3. **Receive Messages**: +4. **Receive Messages**: - Messages from other players appear in the chat log - Your own messages are shown in light blue - Other players' messages are shown in white -4. **Disconnect**: +5. **Disconnect**: - Click "Disconnect" to close the connection ## How It Works @@ -151,27 +157,61 @@ The main script demonstrates: client.playerSaid.connect(_on_player_said) func _on_player_said(data: Dictionary): - var sender = data.get("sender", "Unknown") - var message = data.get("message", "") - add_to_chat("%s: %s" % [sender, message]) + var sender = data.get("sender", "Unknown") + var message = data.get("message", "") + add_to_chat("%s: %s" % [sender, message]) ``` 5. **Sending Messages**: ```gdscript var request = { - "message": message + "message": message } var response = await client.chatAsync(request) if response.get("hasError", false): - print("Error: ", response.get("error")) + print("Error: ", response.get("error")) ``` 6. **Polling for Messages**: ```gdscript func _process(_delta): - if client: - client.poll() + if client: + client.poll() + ``` + +7. **Browsing Available Rooms**: + ```gdscript + # Fetch rooms from the server + http.request(server_url + "/chatroom/games") + var response = await http.request_completed + var rooms = JSON.parse_string(response_body.get_string_from_utf8()) + + # Display each room with a join button + for room in rooms: + var room_name = room.get("name", "Unknown") + var player_count = room["players"].size() + add_room_to_list(room_name, player_count) + ``` + +8. **Two Connection Flows**: + + **Join Existing Room** (from room list): + ```gdscript + func join_existing_room(room_name: String): + await login(server_url) # Authenticate + game_id = room_name # Use room name directly + await connect_websockets(server_url) # Connect (no create) + initialize_client() + ``` + + **Create/Join Room** (manual entry): + ```gdscript + func connect_to_server(): + await login(server_url) # Authenticate + await create_game(server_url, room_name) # Create or join + await connect_websockets(server_url) # Connect + initialize_client() ``` ## Key Features Demonstrated @@ -186,6 +226,9 @@ The main script demonstrates: - ✅ Error handling with detailed step feedback - ✅ Connection state management - ✅ UI integration with RichTextLabel for chat +- ✅ Room browsing and discovery (fetching active rooms from server) +- ✅ Dynamic UI updates with room lists +- ✅ Two connection flows: join existing vs create/join ## Testing with Multiple Clients diff --git a/godot_clients/chat-sample-client/main.gd b/godot_clients/chat-sample-client/main.gd index cbc2030e..72850b1e 100644 --- a/godot_clients/chat-sample-client/main.gd +++ b/godot_clients/chat-sample-client/main.gd @@ -20,6 +20,8 @@ var is_connected: bool = false @onready var room_input: LineEdit = $VBoxContainer/ConnectionContainer/RoomInput @onready var connect_button: Button = $VBoxContainer/ConnectionContainer/ConnectButton @onready var status_label: Label = $VBoxContainer/StatusLabel +@onready var refresh_button: Button = $VBoxContainer/RoomListContainer/RoomListHeader/RefreshButton +@onready var room_list_container: VBoxContainer = $VBoxContainer/RoomListContainer/RoomListScroll/RoomList @onready var chat_log: RichTextLabel = $VBoxContainer/ChatLog @onready var message_input: LineEdit = $VBoxContainer/InputContainer/MessageInput @onready var send_button: Button = $VBoxContainer/InputContainer/SendButton @@ -32,6 +34,7 @@ func _ready(): connect_button.pressed.connect(_on_connect_button_pressed) send_button.pressed.connect(_on_send_button_pressed) message_input.text_submitted.connect(_on_message_submitted) + refresh_button.pressed.connect(_on_refresh_rooms_pressed) # Disable send controls initially message_input.editable = false @@ -39,6 +42,7 @@ func _ready(): add_to_chat("[color=yellow]Your name: %s[/color]" % player_name) add_to_chat("[color=gray]Click 'Connect' to join the chat room[/color]") + add_to_chat("[color=gray]Click 'Refresh' to see available rooms[/color]") func _process(_delta): # Poll the client every frame to process messages @@ -81,8 +85,8 @@ func connect_to_server(): connect_button.disabled = false return - add_to_chat("[color=cyan]Step 2: Joining room '%s'...[/color]" % room_name) - status_label.text = "Status: Joining room..." + add_to_chat("[color=cyan]Step 2: Creating/Joining room '%s'...[/color]" % room_name) + status_label.text = "Status: Creating/Joining room..." # Step 2: Create a game room (or join if it exists) if not await create_game(server_url, room_name): @@ -182,6 +186,8 @@ func connect_websockets(server_url: String) -> bool: action_socket.set_handshake_headers(headers) var action_url = server_url + "/chatroom/join/" + game_id + print("DEBUG: Connecting to WebSocket URL: ", action_url) + print("DEBUG: Using game_id: ", game_id) var err = action_socket.connect_to_url(action_url) if err != OK: @@ -373,6 +379,95 @@ func add_to_chat(text: String): chat_log.append_text(text + "\n") # Auto-scroll is enabled in the scene +## ==================================================== +## Room List Methods +## ==================================================== + +func _on_refresh_rooms_pressed(): + refresh_rooms() + +func refresh_rooms(): + var server_url = server_input.text + if server_url.is_empty(): + add_to_chat("[color=red]Error: Please enter a server URL first[/color]") + return + + var http_url = server_url.replace("ws://", "http://").replace("wss://", "https://") + + var http = HTTPRequest.new() + add_child(http) + + # Fetch the list of chat rooms + http.request(http_url + "/chatroom/games") + + var response = await http.request_completed + http.queue_free() + + var result = response[0] + var response_code = response[1] + var response_body = response[3] + + if result != HTTPRequest.RESULT_SUCCESS or response_code != 200: + add_to_chat("[color=red]Failed to fetch rooms: %d[/color]" % response_code) + return + + var json = JSON.parse_string(response_body.get_string_from_utf8()) + if json == null: + add_to_chat("[color=red]Invalid response from server[/color]") + return + + # Clear existing room list + for child in room_list_container.get_children(): + child.queue_free() + + # Add rooms to the list + if json is Array and json.size() > 0: + for room in json: + print("DEBUG: Room data: ", JSON.stringify(room)) + # Try both camelCase and PascalCase + var room_name = room.get("name", room.get("Name", "Unknown")) + var player_count = 0 + var players = room.get("players", room.get("Players", [])) + if players is Array: + player_count = players.size() + + print("DEBUG: Extracted room_name: ", room_name, ", player_count: ", player_count) + add_room_to_list(room_name, player_count) + + add_to_chat("[color=cyan]Found %d room(s)[/color]" % json.size()) + else: + var no_rooms_label = Label.new() + no_rooms_label.text = "No rooms available" + no_rooms_label.add_theme_color_override("font_color", Color(0.6, 0.6, 0.6)) + room_list_container.add_child(no_rooms_label) + add_to_chat("[color=gray]No rooms found[/color]") + +func add_room_to_list(room_name: String, player_count: int): + var room_item = HBoxContainer.new() + + var room_label = Label.new() + room_label.text = "%s (%d player%s)" % [room_name, player_count, "s" if player_count != 1 else ""] + room_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + room_item.add_child(room_label) + + var join_button = Button.new() + join_button.text = "Join" + join_button.pressed.connect(_on_join_room_pressed.bind(room_name)) + room_item.add_child(join_button) + + room_list_container.add_child(room_item) + +func _on_join_room_pressed(room_name: String): + if is_connected: + add_to_chat("[color=yellow]Already connected. Disconnect first to join another room.[/color]") + return + + # Fill the room name and use the normal connect flow + # This will attempt to create/join the room + room_input.text = room_name + add_to_chat("[color=cyan]Joining room: %s[/color]" % room_name) + connect_to_server() + ## ==================================================== ## Cleanup ## ==================================================== diff --git a/godot_clients/chat-sample-client/main.tscn b/godot_clients/chat-sample-client/main.tscn index f260375d..27a8b3e6 100644 --- a/godot_clients/chat-sample-client/main.tscn +++ b/godot_clients/chat-sample-client/main.tscn @@ -66,6 +66,31 @@ text = "Status: Disconnected" [node name="HSeparator2" type="HSeparator" parent="VBoxContainer"] layout_mode = 2 +[node name="RoomListContainer" type="VBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="RoomListHeader" type="HBoxContainer" parent="VBoxContainer/RoomListContainer"] +layout_mode = 2 + +[node name="RoomListLabel" type="Label" parent="VBoxContainer/RoomListContainer/RoomListHeader"] +layout_mode = 2 +text = "Available Rooms:" + +[node name="RefreshButton" type="Button" parent="VBoxContainer/RoomListContainer/RoomListHeader"] +layout_mode = 2 +text = "Refresh" + +[node name="RoomListScroll" type="ScrollContainer" parent="VBoxContainer/RoomListContainer"] +custom_minimum_size = Vector2(0, 100) +layout_mode = 2 + +[node name="RoomList" type="VBoxContainer" parent="VBoxContainer/RoomListContainer/RoomListScroll"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HSeparator3" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + [node name="ChatLog" type="RichTextLabel" parent="VBoxContainer"] layout_mode = 2 size_flags_vertical = 3 @@ -73,7 +98,7 @@ bbcode_enabled = true text = "[color=gray]Welcome to Deckster Chat Room![/color]" scroll_following = true -[node name="HSeparator3" type="HSeparator" parent="VBoxContainer"] +[node name="HSeparator4" type="HSeparator" parent="VBoxContainer"] layout_mode = 2 [node name="InputContainer" type="HBoxContainer" parent="VBoxContainer"]