internal static void SetUpdateState(UpdateStates state) { Scheduler.Add(delegate { if (state == UpdateState) { return; } UpdateState = state; VoidDelegate d = UpdateStateChanged; if (d != null) { d(); } switch (UpdateState) { case UpdateStates.EmergencyFallback: //let's hope we never need this. OsuMain.Repair(true); break; case UpdateStates.Completed: ConfigManager.sUpdateFailCount.Value = 0; //Update has completed and doesn't need a restart. ConfigManager.sUpdatePending.Value = false; ConfigManager.SaveConfig(); string lastVersion = ConfigManager.sLastVersion; NotificationManager.ShowMessage( string.Format(LocalisationManager.GetString(OsuString.Update_Complete), General.BUILD_NAME) + '\n' + LocalisationManager.GetString(OsuString.GameBase_Updater_Changelog), Color.Pink, 10000, delegate { if (string.IsNullOrEmpty(General.SUBVERSION)) { //public releases GameBase.ProcessStart(string.Format(@"https://osu.ppy.sh/p/changelog?v={0}&s={1}&l={2}", General.BUILD_NAME, General.TargetedPublicStream.ToString().ToLower(), lastVersion)); } else { //beta or cutting edge GameBase.ProcessStart(@"https://osu.ppy.sh/p/changelog?v=next"); } }); break; case UpdateStates.Error: ConfigManager.sUpdatePending.Value = false; if (CommonUpdater.LastError != null) { if (CommonUpdater.LastError is MissingFrameworkVersionException) { CommonUpdater.ResetError(); NotificationManager.ShowMessage(LocalisationManager.GetString(OsuString.GameBase_UpdateFailedFrameworkVersion), Color.Red, 300000, delegate { OsuMain.ForceUpdate(true); }); } else { RunBackgroundThread(delegate { ErrorSubmission.Submit(new OsuError(CommonUpdater.LastError) { Feedback = @"update error", ILTrace = CommonUpdater.LastErrorExtraInformation ?? string.Empty }); CommonUpdater.ResetError(); }); } } ConfigManager.ResetHashes(); ConfigManager.sUpdateFailCount.Value++; break; case UpdateStates.NeedsRestart: //the update could have already moved the files into their new place, so we want to make sure we have reloaded the master config file. ConfigManager.ReloadHashCache(); ConfigManager.sUpdateFailCount.Value = 0; bool isNewUpdate = !ConfigManager.sUpdatePending.Value; ConfigManager.sUpdatePending.Value = true; //Update completed but needs a restart. We either want to force a restart or just wait for the next user-triggered restart. if (UpdateForceRestart) { CompleteUpdate(); } else if (Mode != OsuModes.Menu && isNewUpdate) { NotificationManager.ShowMessage(LocalisationManager.GetString(OsuString.General_NewVersion), Color.Pink, 10000); } UpdatePendingRestart = true; break; case UpdateStates.NoUpdate: ConfigManager.sUpdateFailCount.Value = 0; break; } }); }
public void TestScheduleOnce([Values(false, true)] bool fromMainThread, [Values(false, true)] bool forceScheduled) { this.fromMainThread = fromMainThread; int invocations = 0; scheduler.Add(() => invocations++, forceScheduled); if (fromMainThread && !forceScheduled) { Assert.AreEqual(1, invocations); } else { Assert.AreEqual(0, invocations); } scheduler.Update(); Assert.AreEqual(1, invocations); // Ensures that the delegate runs only once in the scheduled/not on main thread branch scheduler.Update(); Assert.AreEqual(1, invocations); }
public void Execute(Action op) { Scheduler.Add(op); }
Task IMultiplayerClient.SettingsChanged(MultiplayerRoomSettings newSettings) { Scheduler.Add(() => updateLocalRoomSettings(newSettings)); return(Task.CompletedTask); }
private void onAutoSize() { Scheduler.Add(() => activityAutosize.FadeOutFromOne(1)); }
private void onInvalidate(Drawable d) { Scheduler.Add(() => activityInvalidate.FadeOutFromOne(1)); }
/// <summary> /// Retrieves the total score of a <see cref="ScoreInfo"/> in the given <see cref="ScoringMode"/>. /// The score is returned in a callback that is run on the update thread. /// </summary> /// <param name="score">The <see cref="ScoreInfo"/> to calculate the total score of.</param> /// <param name="callback">The callback to be invoked with the total score.</param> /// <param name="mode">The <see cref="ScoringMode"/> to return the total score as.</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the process.</param> public void GetTotalScore([NotNull] ScoreInfo score, [NotNull] Action <long> callback, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default) { GetTotalScoreAsync(score, mode, cancellationToken) .ContinueWith(s => scheduler.Add(() => callback(s.Result)), TaskContinuationOptions.OnlyOnRanToCompletion); }
public void TestLogOutputFromManyQueuedTasks([Values(false, true)] bool withFlushing) { int matchingLogCount = 0; using (var storage = new TemporaryNativeStorage(nameof(TestLogOutputFromManyQueuedTasks))) { Logger.Storage = storage; Logger.Enabled = true; Logger.NewEntry += logTest; Assert.AreEqual(0, matchingLogCount); for (int i = 0; i < Scheduler.LOG_EXCESSSIVE_QUEUE_LENGTH_INTERVAL / 2; i++) { scheduler.Add(() => { }); if (withFlushing) { scheduler.Update(); } } Assert.AreEqual(0, matchingLogCount); for (int i = 0; i < Scheduler.LOG_EXCESSSIVE_QUEUE_LENGTH_INTERVAL / 2; i++) { scheduler.Add(() => { }); if (withFlushing) { scheduler.Update(); } } Assert.AreEqual(withFlushing ? 0 : 1, matchingLogCount); for (int i = 0; i < Scheduler.LOG_EXCESSSIVE_QUEUE_LENGTH_INTERVAL; i++) { scheduler.Add(() => { }); if (withFlushing) { scheduler.Update(); } } Assert.AreEqual(withFlushing ? 0 : 2, matchingLogCount); Logger.NewEntry -= logTest; Logger.Enabled = false; Logger.Flush(); void logTest(LogEntry entry) { if (entry.Target == LoggingTarget.Performance && entry.Message.Contains("tasks pending")) { matchingLogCount++; } } } }
//~EventWorld() //{ // //CurrentEvent.EventEnd(this, (TwitchChat)mod); //} public void AddTask(Action task) { WorldScheduler.Add(task); }
private void currentChannelChanged(ValueChangedEvent <Channel> e) { if (e.NewValue == null) { textbox.Current.Disabled = true; currentChannelContainer.Clear(false); ChannelSelectionOverlay.Show(); checkIsLoggedIn(); return; } if (e.NewValue is ChannelSelectorTabItem.ChannelSelectorTabChannel) { checkIsLoggedIn(); return; } textbox.Current.Disabled = e.NewValue.ReadOnly; if (ChannelTabControl.Current.Value != e.NewValue) { Scheduler.Add(() => ChannelTabControl.Current.Value = e.NewValue); } var loaded = loadedChannels.Find(d => d.Channel == e.NewValue); if (loaded == null) { currentChannelContainer.FadeOut(500, Easing.OutQuint); loading.Show(); loaded = new DrawableChannel(e.NewValue); loadedChannels.Add(loaded); LoadComponentAsync(loaded, l => { if (currentChannel.Value != e.NewValue) { checkIsLoggedIn(); return; } loading.Hide(); currentChannelContainer.Clear(false); currentChannelContainer.Add(loaded); currentChannelContainer.FadeIn(500, Easing.OutQuint); }); } else { currentChannelContainer.Clear(false); currentChannelContainer.Add(loaded); } // mark channel as read when channel switched if (e.NewValue.Messages.Any()) { channelManager.MarkChannelAsRead(e.NewValue); } checkIsLoggedIn(); }
private void InitializeTester() { if (!PREDEFINED_TEST) { return; } if (BeatmapManager.Beatmaps.Count > 0) { if (USE_LAST_PLAYED_BEATMAP) { List <Beatmap> temp = new List <Beatmap>(BeatmapManager.Beatmaps); temp.Sort((a, b) => { return(a.DateLastPlayed.CompareTo(b.DateLastPlayed)); }); BeatmapManager.Current = temp[temp.Count - 1]; } else //Choose a random beatmap { BeatmapManager.Current = BeatmapManager.Beatmaps[RNG.Next(0, BeatmapManager.Beatmaps.Count)]; } } if (MULTIPLAYER_MATCH) { if (BeatmapManager.Current == null) { NotificationManager.ShowMessage("Couldn't start in specified test mode because no beatmaps were available."); return; } BanchoClient.Start(); Mode = OsuModes.MatchSetup; const int player_count = 8; while (!BanchoClient.Connected || !BanchoClient.InitializationComplete) { Scheduler.Update(); } PresenceCache.QueryAll(); while (User.Id <= 0 || BanchoClient.Users.Count < player_count) { Scheduler.Update(); } List <User> users = BanchoClient.Users.FindAll(u => u.InitialLoadComplete && u.Id != User.Id); users.Insert(0, User); //we are the first user. MatchSetup.Match = new ClientSideMatch(new bMatch(MatchTypes.Standard, MatchScoringTypes.Score, MatchTeamTypes.TeamVs, PlayModes.Osu, @"My test game", string.Empty, player_count, BeatmapManager.Current.SortTitle, BeatmapManager.Current.BeatmapChecksum, BeatmapManager.Current.BeatmapId, MODS_TO_USE, 2, MultiSpecialModes.FreeMod )); for (int i = 0; i < player_count; i++) { MatchSetup.Match.slotId[i] = users[i].Id; MatchSetup.Match.UserSlots[i] = users[i]; MatchSetup.Match.slotStatus[i] = SlotStatus.Playing; switch (MatchSetup.Match.matchTeamType) { case MatchTeamTypes.TagTeamVs: case MatchTeamTypes.TeamVs: MatchSetup.Match.slotTeam[i] = i % 2 == 0 ? SlotTeams.Blue : SlotTeams.Red; break; } } bScoreFrame[] frames = new bScoreFrame[player_count]; for (int i = 0; i < player_count; i++) { frames[i] = new bScoreFrame { id = (byte)i, pass = true, currentHp = 200 } } ; RunBackgroundThread(delegate { Thread.Sleep(5000); for (int i = 0; i < player_count; i++) { PlayerVs.MatchPlayerSkipped(i); Thread.Sleep(100); } Thread.Sleep(2000); Player.QueueSkip(); Player.Instance?.DoSkip(); PlayerVs.AllPlayersLoaded = true; PlayerVs.AllPlayersCompleted = true; while (true) { byte player = (byte)RNG.Next(0, player_count); switch (RNG.Next(0, 30)) { default: frames[player].count300 += 1; frames[player].currentCombo++; frames[player].currentHp += 3; break; case 1: case 2: case 3: frames[player].count100 += 1; frames[player].currentCombo++; frames[player].currentHp += 2; break; case 4: case 5: frames[player].count50 += 1; frames[player].currentHp += 1; frames[player].currentCombo++; break; case 6: frames[player].countMiss += 1; frames[player].currentHp -= 50; frames[player].currentCombo = 0; break; } frames[player].currentHp = OsuMathHelper.Clamp(frames[player].currentHp, 0, 200); if (frames[player].currentHp == 0) { frames[player].pass = false; } else if (frames[player].currentHp > 100) { frames[player].pass = true; } frames[player].totalScore += frames[player].currentCombo * 300; frames[player].maxCombo = Math.Max(frames[player].maxCombo, frames[player].currentCombo); PlayerVs.MatchScoreUpdate(frames[player]); Thread.Sleep(50); } }); } switch (INITIAL_MODE) { case OsuModes.Play: if (BeatmapManager.Current == null) { NotificationManager.ShowMessage("Couldn't start in specified test mode because no beatmaps were available."); return; } ModManager.ModStatus = MODS_TO_USE; if (AUTOMATIC_SKIP) { GameBase.RunBackgroundThread(delegate { while (true) { if (Player.Instance != null && Player.Instance.Status != PlayerStatus.Busy) { Scheduler.Add(delegate { Player.Instance?.DoSkip(); }); if (Player.HasSkipped) { break; } } Thread.Sleep(200); } }); } if (AUTOPLAY) { ModManager.ModStatus |= Mods.Autoplay; } break; } QueuedMode = INITIAL_MODE; Player.Mode = INITIAL_PLAY_MODE; } }
private void Start() { scheduler.Add(0, "School"); scheduler.Add(1, "School"); }
/// <summary> /// Register a component to receive API events. /// Fires <see cref="IOnlineComponent.APIStateChanged"/> once immediately to ensure a correct state. /// </summary> /// <param name="component"></param> public void Register(IOnlineComponent component) { Scheduler.Add(delegate { components.Add(component); }); component.APIStateChanged(this, state); }
private void onMatchStarted() => Scheduler.Add(() => { loadingDisplay.Hide(); base.StartGameplay(); });
private void currentChannelChanged(ValueChangedEvent <Channel> e) { if (e.NewValue == null) { textBox.Current.Disabled = true; currentChannelContainer.Clear(false); ChannelSelectionOverlay.Show(); return; } if (e.NewValue is ChannelSelectorTabItem.ChannelSelectorTabChannel) { return; } textBox.Current.Disabled = e.NewValue.ReadOnly; if (ChannelTabControl.Current.Value != e.NewValue) { Scheduler.Add(() => ChannelTabControl.Current.Value = e.NewValue); } var loaded = loadedChannels.Find(d => d.Channel == e.NewValue); if (loaded == null) { currentChannelContainer.FadeOut(500, Easing.OutQuint); loading.Show(); loaded = new DrawableChannel(e.NewValue); loadedChannels.Add(loaded); LoadComponentAsync(loaded, l => { if (currentChannel.Value != e.NewValue) { return; } // check once more to ensure the channel hasn't since been removed from the loaded channels list (may have been left by some automated means). if (!loadedChannels.Contains(loaded)) { return; } loading.Hide(); currentChannelContainer.Clear(false); currentChannelContainer.Add(loaded); currentChannelContainer.FadeIn(500, Easing.OutQuint); }); } else { currentChannelContainer.Clear(false); currentChannelContainer.Add(loaded); } // mark channel as read when channel switched if (e.NewValue.Messages.Any()) { channelManager.MarkChannelAsRead(e.NewValue); } }
internal static void ScheduleDisposal(Action disposalAction) { host?.UpdateThread.Scheduler.Add(() => reset_scheduler.Add(disposalAction.Invoke)); }
/// <summary> /// Enqueues a texture to be uploaded in the next frame. /// </summary> /// <param name="texture">The texture to be uploaded.</param> public static void EnqueueTextureUpload(TextureGL texture) { //todo: don't use scheduler resetScheduler.Add(() => texture.Upload()); }
private BuildResultCode BuildSlave() { // Mount build path ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory); VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath); // Open WCF channel with master builder var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { SendTimeout = TimeSpan.FromSeconds(300.0), MaxReceivedMessageSize = int.MaxValue }; var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(builderOptions.SlavePipe)); try { RegisterRemoteLogger(processBuilderRemote); // Make sure to laod all assemblies containing serializers // TODO: Review how costly it is to do so, and possibily find a way to restrict what needs to be loaded (i.e. only app plugins?) foreach (var assemblyLocation in processBuilderRemote.GetAssemblyContainerLoadedAssemblies()) { AssemblyContainer.Default.LoadAssemblyFromPath(assemblyLocation, builderOptions.Logger); } // Create scheduler var scheduler = new Scheduler(); var status = ResultStatus.NotProcessed; // Schedule command string buildPath = builderOptions.BuildDirectory; Builder.OpenObjectDatabase(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName); var logger = builderOptions.Logger; MicroThread microthread = scheduler.Add(async() => { // Deserialize command and parameters Command command = processBuilderRemote.GetCommandToExecute(); // Run command var inputHashes = FileVersionTracker.GetDefault(); var builderContext = new BuilderContext(inputHashes, null); var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger); MicrothreadLocalDatabases.MountDatabase(commandContext.GetOutputObjectsGroups()); command.PreCommand(commandContext); status = await command.DoCommand(commandContext); command.PostCommand(commandContext, status); // Returns result to master builder processBuilderRemote.RegisterResult(commandContext.ResultEntry); }); while (true) { scheduler.Run(); // Exit loop if no more micro threads lock (scheduler.MicroThreads) { if (!scheduler.MicroThreads.Any()) { break; } } Thread.Sleep(0); } // Rethrow any exception that happened in microthread if (microthread.Exception != null) { builderOptions.Logger.Fatal(microthread.Exception.ToString()); return(BuildResultCode.BuildError); } if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful) { return(BuildResultCode.Successful); } return(BuildResultCode.BuildError); } finally { // Close WCF channel // ReSharper disable SuspiciousTypeConversion.Global ((IClientChannel)processBuilderRemote).Close(); // ReSharper restore SuspiciousTypeConversion.Global } }
private BuildResultCode BuildSlave() { // Mount build path ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory); PrepareDatabases(); VirtualFileSystem.CreateDirectory("/data/"); VirtualFileSystem.CreateDirectory("/data/db/"); // Open WCF channel with master builder var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { SendTimeout = TimeSpan.FromSeconds(300.0) }; var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(builderOptions.SlavePipe)); try { RegisterRemoteLogger(processBuilderRemote); // Create scheduler var scheduler = new Scheduler(); var status = ResultStatus.NotProcessed; // Schedule command string buildPath = builderOptions.BuildDirectory; string buildProfile = builderOptions.BuildProfile; Builder.SetupBuildPath(buildPath); var logger = builderOptions.Logger; MicroThread microthread = scheduler.Add(async() => { // Deserialize command and parameters Command command = processBuilderRemote.GetCommandToExecute(); BuildParameterCollection parameters = processBuilderRemote.GetBuildParameters(); // Run command var inputHashes = FileVersionTracker.GetDefault(); var builderContext = new BuilderContext(buildPath, buildProfile, inputHashes, parameters, 0, null); var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger); IndexFileCommand.MountDatabase(commandContext.GetOutputObjectsGroups()); command.PreCommand(commandContext); status = await command.DoCommand(commandContext); command.PostCommand(commandContext, status); // Returns result to master builder processBuilderRemote.RegisterResult(commandContext.ResultEntry); }); while (true) { scheduler.Run(); // Exit loop if no more micro threads lock (scheduler.MicroThreads) { if (!scheduler.MicroThreads.Any()) { break; } } Thread.Sleep(0); } // Rethrow any exception that happened in microthread if (microthread.Exception != null) { builderOptions.Logger.Fatal(microthread.Exception.ToString()); return(BuildResultCode.BuildError); } if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful) { return(BuildResultCode.Successful); } return(BuildResultCode.BuildError); } finally { // Close WCF channel // ReSharper disable SuspiciousTypeConversion.Global ((IClientChannel)processBuilderRemote).Close(); // ReSharper restore SuspiciousTypeConversion.Global } }
private void onLayout() { Scheduler.Add(() => activityLayout.FadeOutFromOne(1)); }
public void Unregister(IOnlineComponent component) { Scheduler.Add(delegate { components.Remove(component); }); }
private void schedule(Action action) => Scheduler.Add(action, false);
private BuildResultCode BuildSlave() { // Mount build path ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory); VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath); // Open ServiceWire Client Channel using (var client = new NpClient <IProcessBuilderRemote>(new NpEndPoint(builderOptions.SlavePipe), new StrideServiceWireSerializer())) { RegisterRemoteLogger(client); // Make sure to laod all assemblies containing serializers // TODO: Review how costly it is to do so, and possibily find a way to restrict what needs to be loaded (i.e. only app plugins?) foreach (var assemblyLocation in client.Proxy.GetAssemblyContainerLoadedAssemblies()) { AssemblyContainer.Default.LoadAssemblyFromPath(assemblyLocation, builderOptions.Logger); } // Create scheduler var scheduler = new Scheduler(); var status = ResultStatus.NotProcessed; // Schedule command string buildPath = builderOptions.BuildDirectory; Builder.OpenObjectDatabase(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName); var logger = builderOptions.Logger; MicroThread microthread = scheduler.Add(async() => { // Deserialize command and parameters Command command = client.Proxy.GetCommandToExecute(); // Run command var inputHashes = FileVersionTracker.GetDefault(); var builderContext = new BuilderContext(inputHashes, null); var commandContext = new RemoteCommandContext(client.Proxy, command, builderContext, logger); MicrothreadLocalDatabases.MountDatabase(commandContext.GetOutputObjectsGroups()); command.PreCommand(commandContext); status = await command.DoCommand(commandContext); command.PostCommand(commandContext, status); // Returns result to master builder client.Proxy.RegisterResult(commandContext.ResultEntry); }); while (true) { scheduler.Run(); // Exit loop if no more micro threads lock (scheduler.MicroThreads) { if (!scheduler.MicroThreads.Any()) { break; } } Thread.Sleep(0); } // Rethrow any exception that happened in microthread if (microthread.Exception != null) { builderOptions.Logger.Fatal(microthread.Exception.ToString()); return(BuildResultCode.BuildError); } if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful) { return(BuildResultCode.Successful); } return(BuildResultCode.BuildError); } }
public void Execute(Task task) { Scheduler.Add(task.RunSynchronously); }
/// <summary> /// Applies a new <see cref="HitObject"/> to be represented by this <see cref="DrawableHitObject"/>. /// </summary> /// <param name="hitObject">The <see cref="HitObject"/> to apply.</param> /// <param name="lifetimeEntry">The <see cref="HitObjectLifetimeEntry"/> controlling the lifetime of <paramref name="hitObject"/>.</param> public void Apply([NotNull] HitObject hitObject, [CanBeNull] HitObjectLifetimeEntry lifetimeEntry) { free(); HitObject = hitObject ?? throw new InvalidOperationException($"Cannot apply a null {nameof(HitObject)}."); this.lifetimeEntry = lifetimeEntry; if (lifetimeEntry != null) { // Transfer lifetime from the entry. LifetimeStart = lifetimeEntry.LifetimeStart; LifetimeEnd = lifetimeEntry.LifetimeEnd; // Copy any existing result from the entry (required for rewind / judgement revert). Result = lifetimeEntry.Result; } else { LifetimeStart = HitObject.StartTime - InitialLifetimeOffset; } // Ensure this DHO has a result. Result ??= CreateResult(HitObject.CreateJudgement()) ?? throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); // Copy back the result to the entry for potential future retrieval. if (lifetimeEntry != null) { lifetimeEntry.Result = Result; } foreach (var h in HitObject.NestedHitObjects) { var pooledDrawableNested = pooledObjectProvider?.GetPooledDrawableRepresentation(h); var drawableNested = pooledDrawableNested ?? CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}."); // Invoke the event only if this nested object is just created by `CreateNestedHitObject`. if (pooledDrawableNested == null) { OnNestedDrawableCreated?.Invoke(drawableNested); } drawableNested.OnNewResult += onNewResult; drawableNested.OnRevertResult += onRevertResult; drawableNested.ApplyCustomUpdateState += onApplyCustomUpdateState; nestedHitObjects.Value.Add(drawableNested); AddNestedHitObject(drawableNested); drawableNested.OnParentReceived(this); } StartTimeBindable.BindTo(HitObject.StartTimeBindable); StartTimeBindable.BindValueChanged(onStartTimeChanged); if (HitObject is IHasComboInformation combo) { comboIndexBindable.BindTo(combo.ComboIndexBindable); } samplesBindable.BindTo(HitObject.SamplesBindable); samplesBindable.BindCollectionChanged(onSamplesChanged, true); HitObject.DefaultsApplied += onDefaultsApplied; OnApply(hitObject); HitObjectApplied?.Invoke(this); // If not loaded, the state update happens in LoadComplete(). Otherwise, the update is scheduled to allow for lifetime updates. if (IsLoaded) { Scheduler.Add(() => { if (Result.IsHit) { updateState(ArmedState.Hit, true); } else if (Result.HasResult) { updateState(ArmedState.Miss, true); } else { updateState(ArmedState.Idle, true); } }); } hasHitObjectApplied = true; }
/// <summary> /// Creates a <see cref="OsuTKWindow"/> with a given <see cref="IGameWindow"/> implementation. /// </summary> protected OsuTKWindow([NotNull] IGameWindow osuTKGameWindow) { OsuTKGameWindow = osuTKGameWindow; OsuTKGameWindow.KeyDown += OnKeyDown; CurrentDisplay.Value = PrimaryDisplay; // Moving or resizing the window needs to check to see if we've moved to a different display. // This will update the CurrentDisplay bindable. Move += (sender, e) => checkCurrentDisplay(); Resize += (sender, e) => checkCurrentDisplay(); Closing += (sender, e) => e.Cancel = ExitRequested?.Invoke() ?? false; Closed += (sender, e) => Exited?.Invoke(); MouseEnter += (sender, args) => cursorInWindow.Value = true; MouseLeave += (sender, args) => cursorInWindow.Value = false; FocusedChanged += (o, e) => isActive.Value = Focused; supportedWindowModes.AddRange(DefaultSupportedWindowModes); UpdateFrame += (o, e) => UpdateFrameScheduler.Update(); UpdateFrameScheduler.Add(() => isActive.Value = Focused); WindowStateChanged += (o, e) => isActive.Value = WindowState != WindowState.Minimised; MakeCurrent(); string version = GL.GetString(StringName.Version); string versionNumberSubstring = getVersionNumberSubstring(version); GLVersion = new Version(versionNumberSubstring); // As defined by https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetString.xml IsEmbedded = version.Contains("OpenGL ES"); version = GL.GetString(StringName.ShadingLanguageVersion); if (!string.IsNullOrEmpty(version)) { try { GLSLVersion = new Version(versionNumberSubstring); } catch (Exception e) { Logger.Error(e, $@"couldn't set GLSL version using string '{version}'"); } } if (GLSLVersion == null) { GLSLVersion = new Version(); } Logger.Log($@"GL Initialized GL Version: {GL.GetString(StringName.Version)} GL Renderer: {GL.GetString(StringName.Renderer)} GL Shader Language version: {GL.GetString(StringName.ShadingLanguageVersion)} GL Vendor: {GL.GetString(StringName.Vendor)} GL Extensions: {GL.GetString(StringName.Extensions)}"); }
protected override void LoadComplete() { base.LoadComplete(); Scheduler.Add(updateTimeWithReschedule); }