protected override void Awake()
        {
            base.Awake();
            var controller = GetComponent <DatingController>();

            controller.judgements.ObserveAdd()
            .Subscribe(judgement =>
            {
                var profile = controller.currentProfileView.data;
                AnalyticsEvent.Custom("swipe", new Dictionary <string, object>()
                {
                    {
                        "on_profile", profile.name
                    },
                    {
                        "matched", judgement.Value.judgement == DatingProfileJudgement.Matched
                    },
                    {
                        "order", judgement.Index
                    }
                });
                var eventHitBuilder = new EventHitBuilder()
                                      .SetEventCategory("dating")
                                      .SetEventAction("swipe")
                                      .SetEventLabel(profile.name)
                                      .SetEventValue(judgement.Value.judgement == DatingProfileJudgement.Matched ? 1L : 0L)
                                      .SetCustomMetric(0, judgement.Index);
                GoogleAnalyticsV4.getInstance().LogEvent(eventHitBuilder);
            })
            .AddTo(this);
        }
        private void OnDialogueEnded(DialogueItem dialogue, CompositeDisposable subscriptions)
        {
            subscriptions.Dispose();
            dialogue.ended = true;

            m_ChatBoxController.HideOptions();
            m_ConversationController.StopTyping();
            m_DialogueEnded.OnNext(new DialogEndedEvent
            {
                item      = selectedDialogue.Value,
                profile   = profile.Value,
                succeeded = dialogue.succeeded
            });

            m_ExitButton.SetActive(true);
            m_ChatBoxController.gameObject.SetActive(false);

            AnalyticsEvent.LevelComplete(profile.Value.name, new Dictionary <string, object>()
            {
                { "succeeded", dialogue.succeeded }
            });
            var eventHitBuilder1 = new EventHitBuilder()
                                   .SetEventCategory("conversation")
                                   .SetEventAction("ended")
                                   .SetEventLabel(profile.Value.name)
                                   .SetEventValue(dialogue.succeeded ? 1L : 0L);

            GoogleAnalyticsV4.getInstance().LogEvent(eventHitBuilder1);
        }
        protected override void Awake()
        {
            base.Awake();

            Debug.Log($"DialogueConversationController: Loaded {m_Sprites.Length} sprite(s).");

            // When a text phase event is processed from the dialogue system and it didn't have choices, this will post
            // a delayed dialogue continuation to make it look like the other person was typing. Posts the length
            // of the output for the purposes of making an appropriate delay.
            var lastChoice = -1;
            CompositeDisposable subscriptions = null;

            m_ChatBoxController.choices
            .Subscribe(choice => { lastChoice = choice.index; })
            .AddTo(this);

            profile
            .Where(item => item != null)
            .Subscribe(item =>
            {
                m_DatingProfileView.data = item;
                m_ConversationController.conversantName = profile.Value.name;
            })
            .AddTo(this);

            selectedDialogue
            .StartWith((DialogueItem)null)
            .Pairwise()
            .Subscribe(dialogues =>
            {
                var oldDialogue = dialogues.Previous;
                var newDialogue = dialogues.Current;
                if (oldDialogue == newDialogue || newDialogue == null)
                {
                    return;
                }

                subscriptions?.Dispose();
                subscriptions = ResumeStory(newDialogue, oldDialogue);

                AnalyticsEvent.Custom("chat_with", new Dictionary <string, object>()
                {
                    { "on_profile", profile.Value?.name }
                });
                var eventHitBuilder1 = new EventHitBuilder()
                                       .SetEventCategory("conversation")
                                       .SetEventAction("chat_with")
                                       .SetEventLabel(profile.Value?.name);
                GoogleAnalyticsV4.getInstance().LogEvent(eventHitBuilder1);
            })
            .AddTo(this);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Undoes the last stamping action
        /// </summary>
        public void Undo()
        {
            drawingView.stampItems.RemoveAt(drawingView.stampItems.Count - 1);

            // Analytics
            var hit = new EventHitBuilder()
                      .SetEventCategory("profile creator")
                      .SetEventAction("undo")
                      .SetEventValue(drawingView.stampItems.Count);

            GoogleAnalyticsV4.getInstance().LogEvent(hit);
            m_CanUndo.Value = drawingView.stampItems.Count > 0;
        }
Ejemplo n.º 5
0
        protected override void Awake()
        {
            base.Awake();
            var screenView = GetComponent <ScreenView>();

            screenView.onScreenBeginTransition.AsObservable()
            .Subscribe(next =>
            {
                var nextScreen = screenView.materialScreen[next];
                AnalyticsEvent.ScreenVisit(nextScreen.gameObject.name);
                GoogleAnalyticsV4.getInstance().LogScreen(nextScreen.gameObject.name);
            })
            .AddTo(this);
        }
Ejemplo n.º 6
0
    private void SendGaHitWithMeasurementProtocol(string url)
    {
        if (String.IsNullOrEmpty(url))
        {
            if (GoogleAnalyticsV4.belowThreshold(logLevel, GoogleAnalyticsV4.DebugMode.WARNING))
            {
                Debug.Log("No tracking code set for 'Other' platforms - hit will not be sent.");
            }

            return;
        }

        if (dryRun || optOut)
        {
            if (GoogleAnalyticsV4.belowThreshold(logLevel, GoogleAnalyticsV4.DebugMode.WARNING))
            {
                Debug.Log("Dry run or opt out enabled - hits will not be sent.");
            }

            return;
        }

        if (startSessionOnNextHit)
        {
            url += AddOptionalMPParameter(Fields.SESSION_CONTROL, "start");
            startSessionOnNextHit = false;
        }
        else if (endSessionOnNextHit)
        {
            url += AddOptionalMPParameter(Fields.SESSION_CONTROL, "end");
            endSessionOnNextHit = false;
        }
        // Add random z to avoid caching
        string newUrl = url + "&z=" + UnityEngine.Random.Range(0, 500);

        if (GoogleAnalyticsV4.belowThreshold(logLevel, GoogleAnalyticsV4.DebugMode.VERBOSE))
        {
            Debug.Log(newUrl);
        }

        GoogleAnalyticsV4.getInstance().StartCoroutine(this.HandleWWW(new WWW(newUrl)));
    }
Ejemplo n.º 7
0
        // Start is called before the first frame update
        protected override void Start()
        {
            m_CategoryPagerView.items.Value = m_Categories;

            var categoryObservable = category as IObservable <CategoryEnum>;
            var isDragAndDropping  = new BoolReactiveProperty(false);

            // If we have at least one category, start with it
            if (m_Categories.Length > 0)
            {
                categoryObservable = categoryObservable.StartWith(m_Categories[0].category);
            }

            // Change the catalogue pager whenever the category button is pressed or the color changes.
            Observable.Merge(
                categoryObservable
                .DistinctUntilChanged()
                .AsUnitObservable(),
                flipped.DistinctUntilChanged()
                .AsUnitObservable(),
                color.DistinctUntilChanged()
                .AsUnitObservable()
                )
            .Subscribe(ignored =>
            {
                var catalogueItems = m_Asset[category.Value, color.Value]
                                     .Select(item => new CatalogueItem()
                {
                    flipped = flipped.Value,
                    asset   = item
                })
                                     .ToArray();

                m_CataloguePagerView.items.Value = catalogueItems;

                if (m_Brush.Value != null)
                {
                    var index = Array.FindIndex(catalogueItems,
                                                item => item.asset.name == m_Brush.Value.catalogueItem.asset.name);

                    if (index >= 0)
                    {
                        // If the color or flip state changed, it now changed here
                        var brush = new BrushItem()
                        {
                            catalogueItem = catalogueItems[index]
                        };
                        m_Brush.SetValueAndForceNotify(brush);
                    }
                }

                var hit = new EventHitBuilder()
                          .SetEventCategory("profile creator")
                          .SetEventAction("brush")
                          .SetEventLabel($"category={category.Value}, color={color.Value}, flipped={flipped.Value}")
                          .SetEventValue(drawingView.stampItems.Count);
                GoogleAnalyticsV4.getInstance().LogEvent(hit);
            })
            .AddTo(this);

            category.Value = m_Categories[0].category;

            // Whenever we click on a catalogue item, set that image as the current brush, then stamp its pixels onto
            // the drawing image with our brush when it is clicked
            m_CataloguePagerView.OnCatalogueItemPointerClickAsObservable()
            .Subscribe(tuple =>
            {
                // If we clicked instead of dragged the item, we're definitely not dragging
                isDragAndDropping.Value = false;
                brush.Value             = new BrushItem()
                {
                    catalogueItem = tuple.Item2
                };
            })
            .AddTo(this);

            // If we switch into the screen view that contains the editing profile text, copy in the image to it
            m_UiScreenView.onScreenBeginTransition.AsObservable()
            .Where(targetScreen => targetScreen == m_EditingProfileTextScreen.screenIndex)
            .Subscribe(ignored => { Drawing.PostDrawing(drawingView, m_EditingProfileTextDrawingView); })
            .AddTo(this);

            // Drawing code
            var opaque      = new Color(1f, 1f, 1f, 1f);
            var transparent = new Color(1f, 1f, 1f, m_PreviewBrushTransparency);

            // Draw a preview of the brush
            var previewBrush = new GameObject("Preview Brush");
            var previewImage = previewBrush.AddComponent <Image>();

            // The preview image brush naturally should not receive raycasts / should not block
            previewImage.raycastTarget = false;
            var previewBrushTransform = previewBrush.transform as RectTransform;

            Debug.Assert(previewBrushTransform != null, nameof(previewBrushTransform) + " != null");

            // Changes the preview's sprite as long as the brush is not null. The brush is actually set inactive later.
            // Also reacts to when the flipping setting changes.
            brush
            .Where(b => brush.Value != null && brush.Value.sprite != null)
            .Subscribe(b =>
            {
                previewImage.sprite = b.sprite;
                previewImage.rectTransform.localScale =
                    new Vector3(b.flipped ? -1.0f : 1f, 1f, 1f);
                previewImage.SetNativeSize();
            })
            .AddTo(this);

            // Move the preview brush along with the mouse as long as there is a brush selected
            // Whether or not it will be visible depends on which layer it's on and whether or not we're on a mobile
            // device. Mobile devices do not show the preview when the item was just clicked. The layer is changed later.
            Observable.EveryUpdate()
            .Where(ignored => isActiveAndEnabled)
            .Subscribe(ignored =>
            {
                if (brush.Value == null ||
                    Application.isMobilePlatform && !isDragAndDropping.Value)
                {
                    previewBrush.SetActive(false);
                    return;
                }

                previewBrush.SetActive(true);
                var pointer           = ContinuousStandaloneInputModule.instance.pointerEventData;
                var isOverDrawingView = pointer.pointerCurrentRaycast.gameObject ==
                                        m_DrawingView.raycastTarget.gameObject;

                previewImage.color = isDragAndDropping.Value ? isOverDrawingView ? opaque : transparent : opaque;
                previewBrushTransform.transform.position = BrushPosition(pointer);
            })
            .AddTo(this);


            // When we are drag and dropping, put the preview brush on the root canvas layer so that its totally in
            // the foreground. Otherwise, put it in the preview layer so it only appears when the user's pointer is
            // hovering over the drawing canvas
            isDragAndDropping.StartWith(false)
            .Subscribe(dragging =>
            {
                previewBrushTransform.SetParent(dragging ? m_ScreenRectTransform : m_DrawingView.previewLayer);
            })
            .AddTo(this);

            // Draw the brush when it is stamped
            var foreground = m_DrawingView.stampLayer;

            m_DrawingView.OnPointerClickAsObservable()
            .Where(ignored => brush.Value != null)
            .Subscribe(pointer => { Stamp(pointer, foreground, brush.Value.flipped); })
            .AddTo(this);

            // Enable drag and dropping a specific sprite. Temporarily switches the brush and activates drag and drop mode
            m_CataloguePagerView
            .OnCatalogueItemBeginDragAsObservable()
            .Subscribe(tuple =>
            {
                isDragAndDropping.Value = true;
                brush.Value             = new BrushItem()
                {
                    catalogueItem = tuple.Item2
                };
            })
            .AddTo(this);

            // Stamp when we stop dragging a catalogue item
            m_CataloguePagerView
            .OnCatalogueItemEndDragAsObservable()
            .Subscribe(tuple =>
            {
                isDragAndDropping.Value = false;
                // If we're over the drawing view, we should stamp the sprite
                var isOverDrawingView = tuple.Item1.pointerCurrentRaycast.gameObject ==
                                        m_DrawingView.raycastTarget.gameObject;
                if (isOverDrawingView)
                {
                    Stamp(tuple.Item1, m_DrawingView.stampLayer, tuple.Item2.flipped);
                }

                // Then clear the brush no matter what
                brush.Value = null;
            })
            .AddTo(this);

            // Toggle the flip automatically if this particular asset is configured to do so
            stampEvents.Where(stamp => stamp != null && stamp.brush.flipsAfterStamp)
            .Subscribe(stamp => { flipped.Value = !flipped.Value; })
            .AddTo(this);

            drawingView.stampItems.ObserveCountChanged(true)
            .Subscribe(count => { m_CanUndo.Value = count > 0; })
            .AddTo(this);

            // Save as the user stamps
            stampEvents
            .Subscribe(stampEvent =>
            {
                // This throttles internally
                SaveGameController.instance.Save();

                if (stampEvent != null)
                {
                    // Analytics
                    var hit = new EventHitBuilder()
                              .SetEventCategory("profile creator")
                              .SetEventAction("stamp")
                              .SetEventLabel(stampEvent.brush.sprite.name)
                              .SetEventValue(drawingView.stampItems.Count);
                    GoogleAnalyticsV4.getInstance().LogEvent(hit);
                }
            })
            .AddTo(this);
        }
        private void OnNextStory(DialogueItem dialogue, Subject <DialogueEvent> events, Choice choice = null,
                                 string overrideMessage = null, bool silent = false)
        {
            var story    = dialogue.story;
            var self     = false;
            var noDelay  = false;
            var noBubble = false;
            var success  = false;

            if (choice != null)
            {
                var substring = choice.text?.Substring(0, Mathf.Min(choice.text?.Length ?? 0, 8));
                AnalyticsEvent.Custom("choice", new Dictionary <string, object>()
                {
                    { "path", story.state?.currentPathString },
                    { "profile", profile.Value?.name },
                    { "text", substring },
                    { "index", choice.index }
                });
                var eventHitBuilder1 = new EventHitBuilder()
                                       .SetEventCategory("conversation")
                                       .SetEventAction("choice")
                                       .SetEventLabel(choice.text)
                                       .SetCustomDimension(0, story.state?.currentPathString)
                                       .SetCustomDimension(1, profile.Value?.name);
                GoogleAnalyticsV4.getInstance().LogEvent(eventHitBuilder1);

                story.ChooseChoiceIndex(choice.index);
                self    = true;
                noDelay = true;
            }

            var eventHitBuilder2 = new EventHitBuilder()
                                   .SetEventCategory("conversation")
                                   .SetEventAction("position")
                                   .SetEventLabel(story.currentText)
                                   .SetCustomDimension(0, story.state?.currentPathString)
                                   .SetCustomDimension(1, profile.Value?.name);

            GoogleAnalyticsV4.getInstance().LogEvent(eventHitBuilder2);

            if (story.canContinue)
            {
                var message = story.Continue();
                success  = story.currentTags.Any(s => s.ToLower() == DialogueConversationController.success);
                noBubble = story.currentTags.Any(s => s.ToLower() == DialogueConversationController.noBubble);
                self    |= story.currentTags.Any(s => s.ToLower() == DialogueConversationController.self);
                silent  |= story.currentTags.Any(s => s.ToLower() == DialogueConversationController.silent);
                if (success)
                {
                    dialogue.succeeded = true;
                }

                // Remove starting and ending quotation marks, extraneous line returns
                message = message.Trim('\n', '"');

                if (message.StartsWith(m_StartOfSelfConversation))
                {
                    self   |= true;
                    message = message.Substring(1);
                }

                // If this is the last message of the dialogue, no delay
                if (!story.canContinue && (story.currentChoices?.Count ?? 0) == 0)
                {
                    noDelay = true;
                }

                var dialogueEvent = new DialogueEvent
                {
                    text     = overrideMessage ?? message,
                    noBubble = noBubble,
                    choices  = story.currentChoices,
                    self     = self,
                    noDelay  = noDelay,
                    success  = success,
                    silent   = silent
                };
                dialogue.lastEvent = dialogueEvent;
                events.OnNext(dialogueEvent);
            }
            else
            {
                var dialogueEvent = new DialogueEvent
                {
                    finished = true,
                    success  = dialogue.succeeded
                };
                dialogue.lastEvent = dialogueEvent;
                events.OnNext(dialogueEvent);
            }
        }
        private void OnDialogueEvent(DialogueItem dialogue, DialogueEvent data, Subject <DialogueEvent> events,
                                     Subject <DialogueEvent> dialogueContinue)
        {
            // Handle the function call for riddles here. This flag prevents also fake choices used to implement
            // the "Future<int>" that we're doing here from appearing inside the chat box.
            var story      = dialogue.story;
            var dataRiddle = data.riddle;

            if (dataRiddle != null)
            {
                dialogue.suppressChoices = true;
                m_ChatBoxController.RequestInput(res =>
                {
#if UNITY_WEBGL
                    // ReSharper disable once SpecifyStringComparison
                    var answerWasCorrect = res.Trim().ToLower() == dataRiddle.Trim().ToLower();
#else
                    var answerWasCorrect = string.Equals(res, riddle, StringComparison.CurrentCultureIgnoreCase);
#endif
                    AnalyticsEvent.Custom("riddle_input", new Dictionary <string, object>()
                    {
                        { "answer", res }
                    });

                    var eventHitBuilder1 = new EventHitBuilder()
                                           .SetEventCategory("conversation")
                                           .SetEventAction("riddle_input")
                                           .SetEventLabel(res);
                    GoogleAnalyticsV4.getInstance().LogEvent(eventHitBuilder1);

                    OnNextStory(dialogue, events,
                                story.currentChoices[answerWasCorrect ? 1 : 0], overrideMessage: res);
                });
            }
            else if (data.text != null && !data.silent)
            {
                var self = data.self;
                var text = data.text;
                // Render images if one was specified
                var spriteName = ParseSpriteName(text);
                // Retrieves all the sprites that have been referenced SOMEWHERE in the scene. See m_Sprites on this
                // instance and add the sprites to make sure the image can render in the chat.
                var sprite = spriteName == null ? null : Drawing.sprites[spriteName];

                m_ConversationController.Add(new[]
                {
                    new ChatMessage
                    {
                        noBubble = data.noBubble,
                        message  = spriteName != null ? "" : data.text, image = sprite,
                        self     = self
                    }
                });
            }

            // This is definitely no longer the first message.
            dialogue.first = false;

            // Show the choices if there are any to show AND we're not awaiting an input
            if (data.choices?.Count == 0 && dataRiddle == null)
            {
                dialogueContinue?.OnNext(data);
            }
            else if (data.choices?.Count > 0 && dataRiddle == null)
            {
                m_ChatBoxController.responses.Clear();
                if (dialogue.suppressChoices)
                {
                    dialogue.suppressChoices = false;
                }
                else
                {
                    foreach (var choice in data.choices)
                    {
                        m_ChatBoxController.responses.Add(choice.text);
                    }
                }
            }
        }