Remove text update scheduler entirely

Remove text update scheduler entirely

It was added in 2016, nobody can remember why it existed anyway, IME
paths that could be the cause for it to be added are not hooked up
anyway, and key event handlers happily ignored that scheduler entirely
and just mutated `text` to their heart's content.

In the meanwhile anything setting `Text` in conjunction with custom
validation rules (like max length, etc.) would experience weird bugs
due to the `Text` setter going through the scheduler and therefore
having a delayed effect. c2350c2 removed that scheduler's usage in the
aforementioned setter.

--- osu.Framework/Graphics/UserInterface/TextBox.cs
+++ osu.Framework/Graphics/UserInterface/TextBox.cs
@@ -9,17 +9,14 @@
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Graphics.Sprites;
 using osu.Framework.Input;
-using osu.Framework.Threading;
 using osuTK;
 using osuTK.Graphics;
 using osuTK.Input;
 using osu.Framework.Allocation;
 using osu.Framework.Bindables;
-using osu.Framework.Development;
 using osu.Framework.Platform;
 using osu.Framework.Input.Bindings;
 using osu.Framework.Input.Events;
-using osu.Framework.Timing;
 using osu.Framework.Localisation;

 namespace osu.Framework.Graphics.UserInterface
@@ -102,8 +99,6 @@
         /// This usually happens on pressing enter, but can also be triggered on focus loss automatically, via <see cref="CommitOnFocusLost"/>.
         /// </summary>
         public event OnCommitHandler OnCommit;
-
-        private readonly Scheduler textUpdateScheduler = new Scheduler(() => ThreadSafety.IsUpdateThread, null);

         protected TextBox()
         {
@@ -143,20 +138,6 @@
         {
             textInput = host.GetTextInput();
             clipboard = host.GetClipboard();
-
-            if (textInput != null)
-            {
-                textInput.OnNewImeComposition += s =>
-                {
-                    textUpdateScheduler.Add(() => onImeComposition(s));
-                    cursorAndLayout.Invalidate();
-                };
-                textInput.OnNewImeResult += s =>
-                {
-                    textUpdateScheduler.Add(onImeResult);
-                    cursorAndLayout.Invalidate();
-                };
-            }
         }

         protected override void LoadComplete()
@@ -356,12 +337,6 @@
             }
         }

-        internal override void UpdateClock(IFrameBasedClock clock)
-        {
-            base.UpdateClock(clock);
-            textUpdateScheduler.UpdateClock(Clock);
-        }
-
         protected override void Dispose(bool isDisposing)
         {
             OnCommit = null;
@@ -378,8 +353,6 @@
         private void updateCursorAndLayout()
         {
             Placeholder.Font = Placeholder.Font.With(size: CalculatedTextSize);
-
-            textUpdateScheduler.Update();

             float cursorPos = 0;
             if (text.Length > 0)
@@ -724,8 +697,6 @@

         private void setText(string value)
         {
-            textUpdateScheduler.CancelDelayedTasks();
-
             int startBefore = selectionStart;
             selectionStart = selectionEnd = 0;


Remove banana positioning comment

Remove banana positioning comment

--- osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -30,8 +30,7 @@
                 AddNested(new Banana
                 {
                     Samples = Samples,
-                    StartTime = i,
-                    X = 0   // The position will be set on the post processing
+                    StartTime = i
                 });
         }


Use Enum for Settings

Use Enum for Settings

--- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs
+++ osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs
@@ -29,12 +29,7 @@
         public override Type[] IncompatibleMods => new[] { typeof(OsuModTarget), typeof(OsuModStrictTracking) };

         [SettingSource("Beat divisor")]
-        public BindableFloat BeatDivisor { get; } = new BindableFloat(1)
-        {
-            MinValue = .25f,
-            MaxValue = 5,
-            Precision = .25f
-        };
+        public Bindable<BeatDivisor> Divisor { get; } = new Bindable<BeatDivisor>(BeatDivisor.Measure);

         public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
         {
@@ -48,11 +43,11 @@
             foreach (var obj in beatmap.HitObjects.OfType<OsuHitObject>())
             {
                 var lastTimingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime + 1);
+                // +1 is added due to First HitCircle in each measure not appearing appropriately without it
                 double controlPointDifference = obj.StartTime + 1 - lastTimingPoint.Time;
-                double remainder = controlPointDifference % (lastTimingPoint.BeatLength * BeatDivisor.Value);
+                double remainder = controlPointDifference % (lastTimingPoint.BeatLength * getMeasure(Divisor.Value));

                 double finalPreempt = obj.TimePreempt + remainder;
-                obj.TimePreempt = finalPreempt;
                 applyFadeInAdjustment(obj);

                 void applyFadeInAdjustment(OsuHitObject osuObject)
@@ -64,14 +59,41 @@
             }
         }

-        protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
+        protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { }
+
+        protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) { }
+
+        private float getMeasure(BeatDivisor divisor)
         {
+            switch (divisor)
+            {
+                case BeatDivisor.Quarter_Measure:
+                    return 0.25f;
+
+                case BeatDivisor.Half_Measure:
+                    return 0.5f;
+
+                case BeatDivisor.Measure:
+                    return 1;
+
+                case BeatDivisor.Double_Measure:
+                    return 2;
+
+                case BeatDivisor.Quadruple_Measure:
+                    return 4;
+
+                default:
+                    throw new ArgumentOutOfRangeException(nameof(divisor), divisor, null);
+            }
         }

-        protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyFrozenState(hitObject, state);
-
-        private void applyFrozenState(DrawableHitObject drawableObject, ArmedState state)
+        public enum BeatDivisor
         {
+            Quarter_Measure,
+            Half_Measure,
+            Measure,
+            Double_Measure,
+            Quadruple_Measure
         }
     }
 }


Web: Disable VS application insights

Web: Disable VS application insights

--- Web/Program.cs
+++ Web/Program.cs
@@ -1,5 +1,6 @@
 using Microsoft.AspNetCore;
 using Microsoft.AspNetCore.Hosting;
+using Microsoft.ApplicationInsights.Extensibility;

 namespace DominikStiller.VertretungsplanServer.Web
 {
@@ -7,6 +8,8 @@
     {
         public static void Main(string[] args)
         {
+            TelemetryConfiguration.Active.DisableTelemetry = true;
+
             var host = WebHost.CreateDefaultBuilder(args)
                 .UseStartup<Startup>()
                 .Build();


deprecation fix

deprecation fix

--- dotnet/Pyrolite.Tests/Pickle/UnpickleComplexTests.cs
+++ dotnet/Pyrolite.Tests/Pickle/UnpickleComplexTests.cs
@@ -55,7 +55,7 @@
 		Pickler p=new Pickler();
 		byte[] pickled_proxy=p.dumps(proxy);
 		object result=U(pickled_proxy);
-		Assert.IsInstanceOfType(typeof(System.Collections.Hashtable), result); // proxy objects cannot be properly pickled and are pickled as bean, hence HashMap
+		Assert.IsInstanceOf<System.Collections.Hashtable>(result); // proxy objects cannot be properly pickled and are pickled as bean, hence Hashtable
 	}

 	[Test]


Added z-buffering, even though it's not needed, but good to show how it's done with D3D10.

--- samples/Direct3D10/SimpleModel10/SimpleModel10Sample.cs
+++ samples/Direct3D10/SimpleModel10/SimpleModel10Sample.cs
@@ -31,6 +31,8 @@
     class SimpleModel10Sample : Sample {
         protected override void Dispose(bool disposeManagedResources) {
             if(disposeManagedResources) {
+                depthStencilView.Dispose();
+                depthStencilState.Dispose();
                 jupiterTexture.Dispose();
                 jupiterMesh.Dispose();
                 effect.Dispose();
@@ -54,6 +56,32 @@
                 renderTargetView = new RenderTargetView(Context10.Device, swapChainBuffer);
             }

+            var depthBufferDesc = new Texture2DDescription {
+                ArraySize = 1,
+                BindFlags = BindFlags.DepthStencil,
+                CpuAccessFlags = CpuAccessFlags.None,
+                Format = Format.D32_Float,
+                Height = WindowHeight,
+                Width = WindowWidth,
+                MipLevels = 1,
+                OptionFlags = ResourceOptionFlags.None,
+                SampleDescription = new SampleDescription(1, 0),
+                Usage = ResourceUsage.Default
+            };
+
+            using(var depthBuffer = new Texture2D(Context10.Device, depthBufferDesc)) {
+                depthStencilView = new DepthStencilView(Context10.Device, depthBuffer);
+            }
+
+            var dssd = new DepthStencilStateDescription {
+                IsDepthEnabled = true,
+                IsStencilEnabled = false,
+                DepthWriteMask = DepthWriteMask.All,
+                DepthComparison = Comparison.Less
+            };
+
+            depthStencilState = DepthStencilState.FromDescription(Context10.Device, dssd);
+
             InputElement[] elements;
             using(var meshLoader = new XLoader()) {
                 jupiterMesh = meshLoader.LoadFile(Context10.Device, "jupiter.X", out elements);
@@ -63,15 +91,15 @@

             string compilationErrors;
             effect = Effect.FromFile(Context10.Device, "SimpleModel10.fx", "fx_4_0", ShaderFlags.None, EffectFlags.None, null, null, out compilationErrors);
-            technique = effect.GetTechniqueByIndex(0);
-            pass = technique.GetPassByIndex(0);
+            var technique = effect.GetTechniqueByIndex(0);

-            var signature = pass.Description.Signature;
-            layout = new InputLayout(Context10.Device, signature, elements);
+            layout = new InputLayout[technique.Description.PassCount];
+            for(var pass = 0; pass < technique.Description.PassCount; ++pass) {
+                layout[pass] = new InputLayout(Context10.Device, technique.GetPassByIndex(pass).Description.Signature, elements);
+            }

             proj = Matrix.PerspectiveFovLH(45.0f, (float) WindowWidth/(float) WindowHeight, 1.0f, 1000.0f);
             view = Matrix.LookAtLH(new Vector3(0, 0, 160), new Vector3(0, 0, -128.0f), Vector3.UnitY);
-            var world = Matrix.Identity;

             effect.GetVariableByName("jupiterTexture").AsResource().SetResource(new ShaderResourceView(Context10.Device, jupiterTexture));
             effect.GetVariableByName("view").AsMatrix().SetMatrix(view);
@@ -81,10 +109,29 @@
         protected override void OnResize() {
             Context10.Device.ClearState();
             renderTargetView.Dispose();
+            depthStencilView.Dispose();

             Context10.SwapChain.ResizeBuffers(1, WindowWidth, WindowHeight, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch);
+
             using (var texture = Resource.FromSwapChain<Texture2D>(Context10.SwapChain, 0)) {
                 renderTargetView = new RenderTargetView(Context10.Device, texture);
+            }
+
+            var depthBufferDesc = new Texture2DDescription {
+                ArraySize = 1,
+                BindFlags = BindFlags.DepthStencil,
+                CpuAccessFlags = CpuAccessFlags.None,
+                Format = Format.D32_Float,
+                Height = WindowHeight,
+                Width = WindowWidth,
+                MipLevels = 1,
+                OptionFlags = ResourceOptionFlags.None,
+                SampleDescription = new SampleDescription(1, 0),
+                Usage = ResourceUsage.Default
+            };
+
+            using (var depthBuffer = new Texture2D(Context10.Device, depthBufferDesc)) {
+                depthStencilView = new DepthStencilView(Context10.Device, depthBuffer);
             }

             proj = Matrix.PerspectiveFovLH(45.0f, (float)WindowWidth / (float)WindowHeight, 1.0f, 1000.0f);
@@ -92,9 +139,12 @@
         }

         protected override void OnRenderBegin() {
-            Context10.Device.OutputMerger.SetTargets(renderTargetView);
+            Context10.Device.OutputMerger.DepthStencilState = depthStencilState;
+            Context10.Device.OutputMerger.SetTargets(depthStencilView, renderTargetView);
+
             Context10.Device.Rasterizer.SetViewports(new Viewport(0, 0, WindowWidth, WindowHeight, 0.0f, 1.0f));
             Context10.Device.ClearRenderTargetView(renderTargetView, new Color4(0.0f, 0.0f, 0.0f));
+            Context10.Device.ClearDepthStencilView(depthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0);
         }

         protected override void OnRender() {
@@ -110,9 +160,12 @@

             effect.GetVariableByName("world").AsMatrix().SetMatrix(world);

-            Context10.Device.InputAssembler.SetInputLayout(layout);
-            pass.Apply();
-            jupiterMesh.DrawSubset(0);
+            var technique = effect.GetTechniqueByIndex(0);
+            for (var passIndex = 0; passIndex < technique.Description.PassCount; ++passIndex) {
+                Context10.Device.InputAssembler.SetInputLayout(layout[passIndex]);
+                technique.GetPassByIndex(passIndex).Apply();
+                jupiterMesh.DrawSubset(0);
+            }
         }

         protected override void OnRenderEnd() {
@@ -120,16 +173,18 @@
         }

         #region Implementation Detail
+
         private RenderTargetView renderTargetView;
         private Mesh jupiterMesh;
         private Texture2D jupiterTexture;
         private Effect effect;
-        private EffectTechnique technique;
-        private EffectPass pass;
         private Matrix view;
         private Matrix proj;
-        private InputLayout layout;
+        private InputLayout[] layout;
         private float rotation;
+        private DepthStencilView depthStencilView;
+        private DepthStencilState depthStencilState;
+
         #endregion
     }
 }


final coverage

final coverage

--- test/csMACnz.SeaOrDew.Tests/CommandErrorTests.cs
+++ test/csMACnz.SeaOrDew.Tests/CommandErrorTests.cs
@@ -42,6 +42,13 @@

         [Theory]
         [MemberData(nameof(NullOrEmptyStrings))]
+        public void StringExceptionConstructor_NullOrWhitespaceMessageFails(string input)
+        {
+            Assert.Throws<ArgumentException>(() => new CommandError(input, new Exception()));
+        }
+
+        [Theory]
+        [MemberData(nameof(NullOrEmptyStrings))]
         public void CodeStringExceptionConstructor_NullOrWhitespaceMessageFails(string input)
         {
             Assert.Throws<ArgumentException>(() => new CommandError(42, input, new Exception()));
@@ -69,6 +76,39 @@
             Assert.Equal(message, error.Message);
             Assert.Equal(code, error.ErrorCode);
             Assert.Null(error.Ex);
+        }
+
+        [Fact]
+        public void StringExceptionConstructor_nullException_ExceptionSet()
+        {
+            var message = "Failed.";
+            Exception exception = null;
+            var error = new CommandError(message, exception);
+
+            Assert.Equal(message, error.Message);
+            Assert.Null(error.Ex);
+        }
+
+        [Fact]
+        public void StringExceptionConstructor_newException_ExceptionSet()
+        {
+            var message = "Failed.";
+            var exception = new Exception();
+            var error = new CommandError(message, exception);
+
+            Assert.Equal(message, error.Message);
+            Assert.Equal(exception, error.Ex);
+        }
+
+        [Fact]
+        public void StringExceptionConstructor_CustomException_ExceptionSet()
+        {
+            var message = "Failed.";
+            var exception = new CustomException();
+            var error = new CommandError(message, exception);
+
+            Assert.Equal(message, error.Message);
+            Assert.Equal(exception, error.Ex);
         }

         [Fact]


SimplePngImage: Updated tests

SimplePngImage: Updated tests

--- tests/Tests.Medo/Drawing/SimplePngImage.Tests.cs
+++ tests/Tests.Medo/Drawing/SimplePngImage.Tests.cs
@@ -30,6 +30,7 @@
             //bmp.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "png-color-basic.png"));
             var memStream = new MemoryStream();
             bmp.Save(memStream);
+            Assert.Equal(76, memStream.Length);
             Assert.Equal("89504E470D0A1A0A0000000D4948445200000002000000030802000000368849D60000001349444154789C63F8CFC0F0FF3F9068608080FF0D0C0D00D6C212940000000049454E44AE426082",
                          BitConverter.ToString(memStream.ToArray()).Replace("-", ""));
         }
@@ -56,6 +57,7 @@
             //bmp.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "png-color-transparency.png"));
             var memStream = new MemoryStream();
             bmp.Save(memStream);
+            Assert.Equal(80, memStream.Length);
             Assert.Equal("89504E470D0A1A0A0000000D4948445200000002000000030806000000B9EADE810000001749444154789C63F8CFC0F01F0418181A18800404FF6F6068680000700275140000000049454E44AE426082",
                          BitConverter.ToString(memStream.ToArray()).Replace("-", ""));
         }
@@ -79,6 +81,7 @@
             //bmp.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "png-mono-basic.png"));
             var memStream = new MemoryStream();
             bmp.Save(memStream);
+            Assert.Equal(67, memStream.Length);
             Assert.Equal("89504E470D0A1A0A0000000D494844520000000200000002080000000057DD52F80000000A49444154789C6360686058F91F00384FDB7F0000000049454E44AE426082",
                          BitConverter.ToString(memStream.ToArray()).Replace("-", ""));
         }
@@ -101,6 +104,7 @@
             //bmp.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "png-mono-transparency.png"));
             var memStream = new MemoryStream();
             bmp.Save(memStream);
+            Assert.Equal(71, memStream.Length);
             Assert.Equal("89504E470D0A1A0A0000000D4948445200000002000000020804000000D8BFC5AF0000000E49444154789C6360F8DFF09F61E5FFFF0700F55FDCD50000000049454E44AE426082",
                          BitConverter.ToString(memStream.ToArray()).Replace("-", ""));
         }
@@ -130,6 +134,7 @@
             //bmp.Save(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "png-clone.png"));
             var memStream = new MemoryStream();
             bmp.Save(memStream);
+            Assert.Equal(76, memStream.Length);
             Assert.Equal("89504E470D0A1A0A0000000D4948445200000002000000030802000000368849D60000001349444154789C63F8CFC0F0FF3F9068608080FF0D0C0D00D6C212940000000049454E44AE426082",
                          BitConverter.ToString(memStream.ToArray()).Replace("-", ""));
         }


Added test for null argument in ctor

Added test for null argument in ctor

--- Octokit.Tests/Clients/ReferencesClientTests.cs
+++ Octokit.Tests/Clients/ReferencesClientTests.cs
@@ -12,6 +12,15 @@
     {
         public class TheGetMethod
         {
+            public class TheCtor
+            {
+                [Fact]
+                public void EnsuresArgument()
+                {
+                    Assert.Throws<ArgumentNullException>(() => new ReferencesClient(null));
+                }
+            }
+
             [Fact]
             public async void EnsuresNonNullArguments()
             {


Remove dependency of home controller since it is no longer needed

--- Oogstplanner.Web/Controllers/HomeController.cs
+++ Oogstplanner.Web/Controllers/HomeController.cs
@@ -15,15 +15,8 @@
     {
         readonly ICalendarService calendarService;

-        public HomeController(ICalendarService calendarService)
-        {
-            if (calendarService == null)
-            {
-                throw new ArgumentNullException("calendarService");
-            }
-
-            this.calendarService = calendarService;
-        }
+        public HomeController()
+        { }

         //
         // GET: /welkom
@@ -31,5 +24,12 @@
         {
             return View();
         }
+
+        //
+        // GET: /veelgesteldevragen
+        public ActionResult Faq()
+        {
+            return View();
+        }
     }
 }


change the drop order to see if this affects unit test fails

From: Sean Dague <8038578a0881e375af8b27042555a6f74d9d7478@gmail.com>

--- OpenSim/Data/MySQL/Tests/MySQLInventoryTest.cs
+++ OpenSim/Data/MySQL/Tests/MySQLInventoryTest.cs
@@ -76,9 +76,9 @@
             }
             if (database != null)
             {
-                database.ExecuteSql("drop table migrations");
                 database.ExecuteSql("drop table inventoryitems");
                 database.ExecuteSql("drop table inventoryfolders");
+                database.ExecuteSql("drop table migrations");
             }
         }
     }


Apply patch to reduce git revision text length if running sim directly from a git tree See http://opensimulator.org/mantis/view.php?id=4030 Thanks ChrisDown (and Bruce for reporting)

--- OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -442,7 +442,7 @@
             if (File.Exists(gitCommitFileName))
             {
                 StreamReader CommitFile = File.OpenText(gitCommitFileName);
-                buildVersion = Environment.NewLine + "git# " + CommitFile.ReadLine();
+                buildVersion = CommitFile.ReadLine();
                 CommitFile.Close();
                 m_version += buildVersion ?? "";
             }


BulletSim: only check position sanity if the prim is physical -- the user can do anything dumb they wish.

--- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -1399,7 +1399,7 @@
             _rotationalVelocity = entprop.RotationalVelocity;

             // The sanity check can change the velocity and/or position.
-            if (PositionSanityCheck(true))
+            if (IsPhysical && PositionSanityCheck(true))
             {
                 entprop.Position = _position;
                 entprop.Velocity = _velocity;
@@ -1412,8 +1412,6 @@
             OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;   // DEBUG DEBUG DEBUG
             DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
                     LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
-
-            // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr);   // DEBUG DEBUG DEBUG

             base.RequestPhysicsterseUpdate();
         }


made linemaps discardable

made linemaps discardable

--- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -1733,6 +1733,7 @@
                         catch (Exception)
                         {
                         }
+                        m_AssemblyLineMaps.Remove(m_Assemblies[assetID]);
                         m_Assemblies.Remove(assetID);
                     }
                 }


Add a few more colinear tests

Add a few more colinear tests

--- osu.Framework.Tests/Polygons/LineIntersections.cs
+++ osu.Framework.Tests/Polygons/LineIntersections.cs
@@ -57,6 +57,9 @@
             new object[] { new Line(up_1, origin), new Line(origin, up_1), false, 0f },
             new object[] { new Line(origin, up_1), new Line(up_1, origin), false, 0f },
             new object[] { new Line(up_1, origin), new Line(up_1, origin), false, 0f },
+            // Colinear touching
+            new object[] { new Line(origin, up_1), new Line(origin, down_1), false, 0f },
+            new object[] { new Line(origin, up_1), new Line(down_1, origin), false, 0f },
         };

         [TestCaseSource(nameof(testCases))]


Obsolete `X` getter

Obsolete `X` getter

--- osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
+++ osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
@@ -1,6 +1,7 @@
 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
 // See the LICENCE file in the repository root for full licence text.

+using System;
 using osu.Framework.Bindables;
 using osu.Game.Beatmaps;
 using osu.Game.Beatmaps.ControlPoints;
@@ -29,6 +30,7 @@
         /// </summary>
         public float X
         {
+            [Obsolete("Use EffectiveX instead")]
             get => EffectiveX;
             set => OriginalXBindable.Value = value;
         }


Refactor scale and rotation operations to share code better

Also adds support for scaling individual sliders.

--- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
+++ osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
@@ -2,6 +2,7 @@
 // See the LICENCE file in the repository root for full licence text.

 using System;
+using System.Collections.Generic;
 using System.Linq;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Primitives;
@@ -40,84 +41,70 @@
         /// </summary>
         private Vector2? referenceOrigin;

-        public override bool HandleScaleY(in float scale, Anchor reference)
-        {
-            int direction = (reference & Anchor.y0) > 0 ? -1 : 1;
+        public override bool HandleScaleY(in float scale, Anchor reference) =>
+            scaleSelection(new Vector2(0, ((reference & Anchor.y0) > 0 ? -1 : 1) * scale), reference);

-            if (direction < 0)
-            {
-                // when resizing from a top drag handle, we want to move the selection first
-                if (!moveSelection(new Vector2(0, scale)))
-                    return false;
-            }
-
-            return scaleSelection(new Vector2(0, direction * scale));
-        }
-
-        public override bool HandleScaleX(in float scale, Anchor reference)
-        {
-            int direction = (reference & Anchor.x0) > 0 ? -1 : 1;
-
-            if (direction < 0)
-            {
-                // when resizing from a left drag handle, we want to move the selection first
-                if (!moveSelection(new Vector2(scale, 0)))
-                    return false;
-            }
-
-            return scaleSelection(new Vector2(direction * scale, 0));
-        }
+        public override bool HandleScaleX(in float scale, Anchor reference) =>
+            scaleSelection(new Vector2(((reference & Anchor.x0) > 0 ? -1 : 1) * scale, 0), reference);

         public override bool HandleRotation(float delta)
         {
-            Quad quad = getSelectionQuad();
+            var hitObjects = selectedMovableObjects;
+
+            Quad quad = getSurroundingQuad(hitObjects);

             referenceOrigin ??= quad.Centre;

-            foreach (var h in SelectedHitObjects.OfType<OsuHitObject>())
+            foreach (var h in hitObjects)
             {
-                if (h is Spinner)
-                {
-                    // Spinners don't support position adjustments
-                    continue;
-                }
-
                 h.Position = rotatePointAroundOrigin(h.Position, referenceOrigin.Value, delta);

                 if (h is IHasPath path)
                 {
                     foreach (var point in path.Path.ControlPoints)
-                    {
                         point.Position.Value = rotatePointAroundOrigin(point.Position.Value, Vector2.Zero, delta);
-                    }
                 }
             }

-            // todo: not always
+            // this isn't always the case but let's be lenient for now.
             return true;
         }

-        private bool scaleSelection(Vector2 scale)
+        private bool scaleSelection(Vector2 scale, Anchor reference)
         {
-            Quad quad = getSelectionQuad();
+            var hitObjects = selectedMovableObjects;

-            Vector2 minPosition = quad.TopLeft;
+            // for the time being, allow resizing of slider paths only if the slider is
+            // the only hit object selected. with a group selection, it's likely the user
+            // is not looking to change the duration of the slider but expand the whole pattern.
+            if (hitObjects.Length == 1 && hitObjects.First() is Slider slider)
+            {
+                var quad = getSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value));
+                Vector2 delta = Vector2.One + new Vector2(scale.X / quad.Width, scale.Y / quad.Height);

-            Vector2 size = quad.Size;
-            Vector2 newSize = size + scale;
+                foreach (var point in slider.Path.ControlPoints)
+                    point.Position.Value *= delta;
+            }
+            else
+            {
+                // move the selection before scaling if dragging from top or left anchors.
+                if ((reference & Anchor.x0) > 0 && !moveSelection(new Vector2(-scale.X, 0))) return false;
+                if ((reference & Anchor.y0) > 0 && !moveSelection(new Vector2(0, -scale.Y))) return false;

-            foreach (var h in SelectedHitObjects.OfType<OsuHitObject>())
-            {
-                if (h is Spinner)
+                Quad quad = getSurroundingQuad(hitObjects);
+
+                Vector2 minPosition = quad.TopLeft;
+
+                Vector2 size = quad.Size;
+                Vector2 newSize = size + scale;
+
+                foreach (var h in hitObjects)
                 {
-                    // Spinners don't support position adjustments
-                    continue;
+                    if (scale.X != 1)
+                        h.Position = new Vector2(minPosition.X + (h.X - minPosition.X) / size.X * newSize.X, h.Y);
+                    if (scale.Y != 1)
+                        h.Position = new Vector2(h.X, minPosition.Y + (h.Y - minPosition.Y) / size.Y * newSize.Y);
                 }
-
-                if (scale.X != 1)
-                    h.Position = new Vector2(minPosition.X + (h.X - minPosition.X) / size.X * newSize.X, h.Y);
-                if (scale.Y != 1)
-                    h.Position = new Vector2(h.X, minPosition.Y + (h.Y - minPosition.Y) / size.Y * newSize.Y);
             }

             return true;
@@ -125,44 +112,34 @@

         private bool moveSelection(Vector2 delta)
         {
-            Vector2 minPosition = new Vector2(float.MaxValue, float.MaxValue);
-            Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue);
+            var hitObjects = selectedMovableObjects;

-            // Go through all hitobjects to make sure they would remain in the bounds of the editor after movement, before any movement is attempted
-            foreach (var h in SelectedHitObjects.OfType<OsuHitObject>())
-            {
-                if (h is Spinner)
-                {
-                    // Spinners don't support position adjustments
-                    continue;
-                }
+            Quad quad = getSurroundingQuad(hitObjects);

-                // Stacking is not considered
-                minPosition = Vector2.ComponentMin(minPosition, Vector2.ComponentMin(h.EndPosition + delta, h.Position + delta));
-                maxPosition = Vector2.ComponentMax(maxPosition, Vector2.ComponentMax(h.EndPosition + delta, h.Position + delta));
-            }
-
-            if (minPosition.X < 0 || minPosition.Y < 0 || maxPosition.X > DrawWidth || maxPosition.Y > DrawHeight)
+            if (quad.TopLeft.X + delta.X < 0 ||
+                quad.TopLeft.Y + delta.Y < 0 ||
+                quad.BottomRight.X + delta.X > DrawWidth ||
+                quad.BottomRight.Y + delta.Y > DrawHeight)
                 return false;

-            foreach (var h in SelectedHitObjects.OfType<OsuHitObject>())
-            {
-                if (h is Spinner)
-                {
-                    // Spinners don't support position adjustments
-                    continue;
-                }
-
+            foreach (var h in hitObjects)
                 h.Position += delta;
-            }

             return true;
         }

         /// <summary>
-        /// Returns a gamefield-space quad surrounding the current selection.
+        /// Returns a gamefield-space quad surrounding the provided hit objects.
         /// </summary>
-        private Quad getSelectionQuad()
+        /// <param name="hitObjects">The hit objects to calculate a quad for.</param>
+        private Quad getSurroundingQuad(OsuHitObject[] hitObjects) =>
+            getSurroundingQuad(hitObjects.SelectMany(h => new[] { h.Position, h.EndPosition }));
+
+        /// <summary>
+        /// Returns a gamefield-space quad surrounding the provided points.
+        /// </summary>
+        /// <param name="points">The points to calculate a quad for.</param>
+        private Quad getSurroundingQuad(IEnumerable<Vector2> points)
         {
             if (!SelectedHitObjects.Any())
                 return new Quad();
@@ -171,23 +148,24 @@
             Vector2 maxPosition = new Vector2(float.MinValue, float.MinValue);

             // Go through all hitobjects to make sure they would remain in the bounds of the editor after movement, before any movement is attempted
-            foreach (var h in SelectedHitObjects.OfType<OsuHitObject>())
+            foreach (var p in points)
             {
-                if (h is Spinner)
-                {
-                    // Spinners don't support position adjustments
-                    continue;
-                }
-
-                // Stacking is not considered
-                minPosition = Vector2.ComponentMin(minPosition, Vector2.ComponentMin(h.EndPosition, h.Position));
-                maxPosition = Vector2.ComponentMax(maxPosition, Vector2.ComponentMax(h.EndPosition, h.Position));
+                minPosition = Vector2.ComponentMin(minPosition, p);
+                maxPosition = Vector2.ComponentMax(maxPosition, p);
             }

             Vector2 size = maxPosition - minPosition;

             return new Quad(minPosition.X, minPosition.Y, size.X, size.Y);
         }
+
+        /// <summary>
+        /// All osu! hitobjects which can be moved/rotated/scaled.
+        /// </summary>
+        private OsuHitObject[] selectedMovableObjects => SelectedHitObjects
+                                                         .OfType<OsuHitObject>()
+                                                         .Where(h => !(h is Spinner))
+                                                         .ToArray();

         /// <summary>
         /// Rotate a point around an arbitrary origin.


Update `TestSceneLeadIn` to use new assert style

--- osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs
+++ osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs
@@ -1,7 +1,5 @@
 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
 // See the LICENCE file in the repository root for full licence text.
-
-#nullable disable

 using System.Linq;
 using NUnit.Framework;
@@ -19,7 +17,7 @@
 {
     public class TestSceneLeadIn : RateAdjustedBeatmapTestScene
     {
-        private LeadInPlayer player;
+        private LeadInPlayer player = null!;

         private const double lenience_ms = 10;

@@ -36,11 +34,7 @@
                 BeatmapInfo = { AudioLeadIn = leadIn }
             });

-            AddStep("check first frame time", () =>
-            {
-                Assert.That(player.FirstFrameClockTime, Is.Not.Null);
-                Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms));
-            });
+            checkFirstFrameTime(expectedStartTime);
         }

         [TestCase(1000, 0)]
@@ -59,11 +53,7 @@

             loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), storyboard);

-            AddStep("check first frame time", () =>
-            {
-                Assert.That(player.FirstFrameClockTime, Is.Not.Null);
-                Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms));
-            });
+            checkFirstFrameTime(expectedStartTime);
         }

         [TestCase(1000, 0, false)]
@@ -97,14 +87,13 @@

             loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), storyboard);

-            AddStep("check first frame time", () =>
-            {
-                Assert.That(player.FirstFrameClockTime, Is.Not.Null);
-                Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms));
-            });
+            checkFirstFrameTime(expectedStartTime);
         }

-        private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
+        private void checkFirstFrameTime(double expectedStartTime) =>
+            AddAssert("check first frame time", () => player.FirstFrameClockTime, () => Is.EqualTo(expectedStartTime).Within(lenience_ms));
+
+        private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard? storyboard = null)
         {
             AddStep("create player", () =>
             {
@@ -126,11 +115,7 @@

             public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;

-            public double GameplayStartTime => DrawableRuleset.GameplayStartTime;
-
             public double FirstHitObjectTime => DrawableRuleset.Objects.First().StartTime;
-
-            public double GameplayClockTime => GameplayClockContainer.CurrentTime;

             protected override void UpdateAfterChildren()
             {


#57 - Search issue - terms with preceding bracket are not found. Reverted special characters treated as separators.

--- PsISEProjectExplorer/FullText/TokenizeRules.cs
+++ PsISEProjectExplorer/FullText/TokenizeRules.cs
@@ -4,9 +4,12 @@
 {
     public class TokenizeRules
     {
+        private static readonly char[] TokenSeparators = { '.', ',', ':', '(', ')', '[', ']', '{', '}', '\\', '/', '`', '\'', '"' };
+
+        // note this is used both in CustomQueryParser (for parsing user input) and CustomTokenizer (for parsing document)
         public bool IsTokenChar(char c)
         {
-            return !System.Char.IsWhiteSpace(c) && !this.IsPhraseChar(c);
+            return !System.Char.IsWhiteSpace(c) && !TokenSeparators.Contains(c);
         }

         public bool IsPhraseChar(char c)


- fixed a bug in the double version of the method "Range"

--- XORShiftRNG.cs
+++ XORShiftRNG.cs
@@ -132,7 +132,7 @@
     {
         if (min > max) throw new ArgumentOutOfRangeException("min", min, "'min' must not be larger than 'max'");

-        return min + (int) ((MAX_UINT_DIVISION_EXCLUSIVE * (double) NextRandomBits()) * (max - min));
+        return min + (double) ((MAX_UINT_DIVISION_EXCLUSIVE * (double) NextRandomBits()) * (max - min));
     }

     /// <summary>


Refactor Instruction

Refactor Instruction

--- src/garply/Instruction.cs
+++ src/garply/Instruction.cs
@@ -28,34 +28,15 @@

         public static Instruction Read(Stream stream)
         {
-            Opcode opcode;
-            var b = stream.ReadByte();
+            var opcode = ReadOpcode(stream);
+            var operandData = ReadOperandData(stream, opcode);
+            var operand = GetOperand(opcode, operandData);
+            return new Instruction(opcode, operand);
+        }

-            switch (b)
-            {
-                case -1:
-                    throw new InvalidOperationException("End of stream");
-                case MarkerByte1:
-                case MarkerByte2:
-                case MarkerByte3:
-                case MarkerByte4:
-                case MarkerByte5:
-                    opcode = (Opcode)(b << 8);
-                    b = stream.ReadByte();
-                    if (b == -1) throw new InvalidOperationException("End of stream");
-                    opcode |= (Opcode)b;
-                    break;
-                default:
-                    opcode = (Opcode)b;
-                    break;
-            }
-
-            var operandSize = opcode.GetSize();
-            var operandData = Buffer.Get(operandSize);
-            if (stream.Read(operandData, 0, operandSize) != operandSize) throw new InvalidOperationException("End of stream");
-
+        private static Value GetOperand(Opcode opcode, byte[] operandData)
+        {
             Value operand;
-
             switch (opcode)
             {
                 case Opcode.Nop:
@@ -97,11 +78,48 @@
                     var index = operandData[0];
                     operand = new Value(index);
                     break;
+                case Opcode.AssignVariable:
+                    throw new NotImplementedException();
                 default:
                     throw new ArgumentOutOfRangeException("opcode");
             }

-            return new Instruction(opcode, operand);
+            return operand;
+        }
+
+        private static byte[] ReadOperandData(Stream stream, Opcode opcode)
+        {
+            var operandSize = opcode.GetSize();
+            var operandData = Buffer.Get(operandSize);
+            if (stream.Read(operandData, 0, operandSize) != operandSize) throw new InvalidOperationException("End of stream");
+            return operandData;
+        }
+
+        private static Opcode ReadOpcode(Stream stream)
+        {
+            Opcode opcode;
+            var b = stream.ReadByte();
+
+            switch (b)
+            {
+                case -1:
+                    throw new InvalidOperationException("End of stream");
+                case MarkerByte1:
+                case MarkerByte2:
+                case MarkerByte3:
+                case MarkerByte4:
+                case MarkerByte5:
+                    opcode = (Opcode)(b << 8);
+                    b = stream.ReadByte();
+                    if (b == -1) throw new InvalidOperationException("End of stream");
+                    opcode |= (Opcode)b;
+                    break;
+                default:
+                    opcode = (Opcode)b;
+                    break;
+            }
+
+            return opcode;
         }

         public void Write(BinaryWriter writer)


Added updating the AzureRM.Netcore.psd1. Also, allows all required modules listed to be updated to the same version.


AIWolfGame.cs: Convert private properties into fields.

--- AIWolfServer/AIWolfGame.cs
+++ AIWolfServer/AIWolfGame.cs
@@ -26,7 +26,10 @@
 #endif
     public class AIWolfGame
     {
-        string logFileName;
+        GameSettingToSend gameSetting;
+        IGameServer gameServer;
+        GameData gameData;
+        Dictionary<Agent, string> agentNameMap = new Dictionary<Agent, string>();

 #if JHELP
         /// <summary>
@@ -39,10 +42,6 @@
 #endif
         public Random Rand { get; set; } = new Random();

-        GameSettingToSend GameSetting { get; }
-        IGameServer GameServer { get; }
-        GameData GameData { get; set; }
-
 #if JHELP
         /// <summary>
         /// コンソールにログを表示するか否か
@@ -65,23 +64,14 @@
 #endif
         public FileGameLogger GameLogger { get; set; }

-        Dictionary<Agent, string> AgentNameMap { get; set; }
-
-        string LogFileName
-        {
-            get => logFileName;
-            set => GameLogger = new FileGameLogger(logFileName = value);
-        }
-
-        int Day => GameData.Day;
-        List<Agent> AgentList => GameData.AgentList;
+        int Day => gameData.Day;
+        List<Agent> AgentList => gameData.AgentList;
         List<Agent> OrderedAgentList => AgentList.OrderBy(x => x.AgentIdx).ToList();
         List<Agent> AliveAgentList => AgentList.Where(a => StatusOf(a) == Status.ALIVE).ToList();
         List<Agent> AliveHumanList => AliveAgentList.Where(a => RoleOf(a).GetSpecies() == Species.HUMAN).ToList();
         List<Agent> AliveWolfList => AliveAgentList.Where(a => RoleOf(a) == Role.WEREWOLF).ToList();
         bool GameFinished => GetWinner() != Team.UNC;

-
 #if JHELP
         /// <summary>
         /// AIWolfGameクラスの新しいインスタンスを初期化する
@@ -97,8 +87,8 @@
 #endif
         public AIWolfGame(GameSettingToSend gameSetting, IGameServer gameServer)
         {
-            GameSetting = gameSetting;
-            GameServer = gameServer;
+            this.gameSetting = gameSetting;
+            this.gameServer = gameServer;
         }

 #if JHELP
@@ -112,74 +102,54 @@
 #endif
         void Init()
         {
-            GameData = new GameData(GameSetting);
-            AgentNameMap = new Dictionary<Agent, string>();
-            GameServer.GameData = GameData;
-
-            List<Agent> agentList = GameServer.ConnectedAgentList;
-
-            if (agentList.Count != GameSetting.PlayerNum)
-            {
-                throw new Exception("Player num is " + GameSetting.PlayerNum + " but connected agent is " + agentList.Count);
-            }
-            agentList = agentList.Shuffle().ToList();
-
-            Dictionary<Role, List<Agent>> requestRoleMap = new Dictionary<Role, List<Agent>>();
-            foreach (Role role in Enum.GetValues(typeof(Role)))
-            {
-                if (role != Role.UNC)
-                {
-                    requestRoleMap[role] = new List<Agent>();
-                }
-            }
-            List<Agent> noRequestAgentList = new List<Agent>();
-            foreach (Agent agent in agentList)
-            {
-                Role requestedRole = GameServer.RequestRequestRole(agent);
-                if (requestedRole != Role.UNC)
-                {
-                    if (requestRoleMap[requestedRole].Count < GameSetting.RoleNumMap[requestedRole])
-                    {
-                        requestRoleMap[requestedRole].Add(agent);
+            gameData = new GameData(gameSetting);
+            gameServer.GameData = gameData;
+            agentNameMap.Clear();
+
+            var agentList = gameServer.ConnectedAgentList.Shuffle();
+
+            if (agentList.Count != gameSetting.PlayerNum)
+            {
+                throw new Exception($"Player num is {gameSetting.PlayerNum} but connected agent is {agentList.Count}.");
+            }
+
+            // 希望役職を優先して配役する
+            var vacantMap = gameSetting.RoleNumMap.Where(p => p.Value > 0).ToDictionary(p => p.Key, p => p.Value);
+            var noRequestAgentQueue = new Queue<Agent>();
+            foreach (var agent in agentList)
+            {
+                var requestedRole = gameServer.RequestRequestRole(agent);
+                if (vacantMap.ContainsKey(requestedRole))
+                {
+                    if (vacantMap[requestedRole] > 0)
+                    {
+                        gameData.AddAgent(agent, Status.ALIVE, requestedRole);
+                        vacantMap[requestedRole]--;
                     }
                     else
                     {
-                        noRequestAgentList.Add(agent);
+                        noRequestAgentQueue.Enqueue(agent);
                     }
                 }
                 else
                 {
-                    noRequestAgentList.Add(agent);
-                }
-            }
-
-            foreach (Role role in Enum.GetValues(typeof(Role)))
-            {
-                if (role == Role.UNC)
-                {
-                    continue;
-                }
-                List<Agent> requestedAgentList = requestRoleMap[role];
-                for (int i = 0; i < GameSetting.RoleNumMap[role]; i++)
-                {
-                    if (requestedAgentList.Count == 0)
-                    {
-                        GameData.AddAgent(noRequestAgentList[0], Status.ALIVE, role);
-                        noRequestAgentList.RemoveAt(0);
-                    }
-                    else
-                    {
-                        GameData.AddAgent(requestedAgentList[0], Status.ALIVE, role);
-                        requestedAgentList.RemoveAt(0);
-                    }
-                }
-            }
-
-            GameServer.GameSetting = GameSetting;
-            foreach (Agent agent in agentList)
-            {
-                GameServer.Init(agent);
-                AgentNameMap[agent] = GameServer.RequestName(agent);
+                    noRequestAgentQueue.Enqueue(agent);
+                }
+            }
+
+            foreach (var pair in vacantMap.Where(p => p.Value > 0))
+            {
+                for (var i = 0; i < pair.Value; i++)
+                {
+                    gameData.AddAgent(noRequestAgentQueue.Dequeue(), Status.ALIVE, pair.Key);
+                }
+            }
+
+            gameServer.GameSetting = gameSetting;
+            foreach (var agent in agentList)
+            {
+                gameServer.Init(agent);
+                agentNameMap[agent] = gameServer.RequestName(agent);
             }
         }

@@ -188,49 +158,38 @@
         /// </summary>
         public void Start()
         {
-            try
-            {
-                Init();
-
-                while (!GameFinished)
-                {
-                    ConsoleLog();
-                    // Day phase.
-                    DayStart();
-                    if (Day == 0)
-                    {
-                        if (GameSetting.TalkOnFirstDay)
-                        {
-                            Whisper();
-                            Talk();
-                        }
-                    }
-                    else
-                    {
+            Init();
+
+            while (!GameFinished)
+            {
+                ConsoleLog();
+                // Day phase.
+                DayStart();
+                if (Day == 0)
+                {
+                    if (gameSetting.TalkOnFirstDay)
+                    {
+                        Whisper();
                         Talk();
                     }
-                    // Night phase.
-                    Night();
-                    if (GameLogger != null)
-                    {
-                        GameLogger.Flush();
-                    }
-                }
-                ConsoleLog();
-                Finish();
-
-                if (ShowConsoleLog)
-                {
-                    Console.WriteLine("Winner:" + GetWinner());
-                }
-            }
-            catch (LostClientException e)
-            {
+                }
+                else // Day > 0
+                {
+                    Talk();
+                }
+                // Night phase.
+                Night();
                 if (GameLogger != null)
                 {
-                    GameLogger.Log("Lost Connection of " + e.Agent);
-                }
-                throw e;
+                    GameLogger.Flush();
+                }
+            }
+            ConsoleLog();
+            Finish();
+
+            if (ShowConsoleLog)
+            {
+                Console.WriteLine("Winner:" + GetWinner());
             }
         }

@@ -241,17 +200,17 @@
         {
             if (GameLogger != null)
             {
-                foreach (Agent agent in OrderedAgentList)
-                {
-                    GameLogger.Log($"{Day},status,{agent.AgentIdx},{RoleOf(agent)},{StatusOf(agent)},{AgentNameMap[agent]}");
+                foreach (var agent in OrderedAgentList)
+                {
+                    GameLogger.Log($"{Day},status,{agent.AgentIdx},{RoleOf(agent)},{StatusOf(agent)},{agentNameMap[agent]}");
                 }
                 GameLogger.Log($"{Day},result,{AliveHumanList.Count},{AliveWolfList.Count},{GetWinner()}");
                 GameLogger.Close();
             }

-            foreach (Agent agent in AgentList)
-            {
-                GameServer.Finish(agent);
+            foreach (var agent in AgentList)
+            {
+                gameServer.Finish(agent);
             }
         }

@@ -261,10 +220,10 @@
         /// <returns>The team which wins.</returns>
         Team GetWinner()
         {
-            int humanSide = 0;
-            int wolfSide = 0;
-            int otherSide = 0;
-            foreach (Agent agent in AliveAgentList)
+            var humanSide = 0;
+            var wolfSide = 0;
+            var otherSide = 0;
+            foreach (var agent in AliveAgentList)
             {
                 switch (RoleOf(agent))
                 {
@@ -305,37 +264,37 @@
                 return;
             }

-            GameData yesterday = GameData.DayBefore;
+            var yesterday = gameData.DayBefore;

             Console.WriteLine("=============================================");
             if (yesterday != null)
             {
                 Console.WriteLine($"Day {yesterday.Day:00}");
                 Console.WriteLine("========talk========");
-                foreach (Talk talk in yesterday.TalkList)
+                foreach (var talk in yesterday.TalkList)
                 {
                     Console.WriteLine(talk);
                 }
                 Console.WriteLine("========Whisper========");
-                foreach (Whisper whisper in yesterday.WhisperList)
+                foreach (var whisper in yesterday.WhisperList)
                 {
                     Console.WriteLine(whisper);
                 }

                 Console.WriteLine("========Actions========");
-                foreach (Vote vote in yesterday.VoteList)
+                foreach (var vote in yesterday.VoteList)
                 {
                     Console.WriteLine($"Vote:{vote.Agent}->{vote.Target}");
                 }

-                foreach (Vote vote in yesterday.AttackVoteList)
+                foreach (var vote in yesterday.AttackVoteList)
                 {
                     Console.WriteLine($"AttackVote:{vote.Agent}->{vote.Target}");
                 }

                 Console.WriteLine($"{yesterday.Executed} executed");

-                Judge divine = yesterday.Divine;
+                var divine = yesterday.Divine;
                 if (divine != null)
                 {
                     Console.WriteLine($"{divine.Agent} divine {divine.Target}. Result is {divine.Result}");
@@ -357,9 +316,9 @@
                 }
             }
             Console.WriteLine("======");
-            foreach (Agent agent in OrderedAgentList)
-            {
-                Console.Write($"{agent}\t{AgentNameMap[agent]}\t{StatusOf(agent)}\t{RoleOf(agent)}");
+            foreach (var agent in OrderedAgentList)
+            {
+                Console.Write($"{agent}\t{agentNameMap[agent]}\t{StatusOf(agent)}\t{RoleOf(agent)}");
                 if (yesterday != null)
                 {
                     if (agent == yesterday.Executed)
@@ -370,12 +329,12 @@
                     {
                         Console.Write("\tattacked");
                     }
-                    Judge divine = yesterday.Divine;
+                    var divine = yesterday.Divine;
                     if (divine != null && agent == divine.Target)
                     {
                         Console.Write("\tdivined");
                     }
-                    Guard guard = yesterday.Guard;
+                    var guard = yesterday.Guard;
                     if (guard != null && agent == guard.Target)
                     {
                         Console.Write("\tguarded");
@@ -388,7 +347,7 @@
                 Console.WriteLine();
             }
             Console.Write($"Human:{AliveHumanList.Count}\nWerewolf:{AliveWolfList.Count}\n");
-            if (GameSetting.RoleNumMap[Role.FOX] != 0)
+            if (gameSetting.RoleNumMap[Role.FOX] != 0)
             {
                 Console.Write($"Others:{AliveAgentList.Count(a => RoleOf(a).GetTeam() == Team.OTHERS)}\n");
             }
@@ -397,12 +356,12 @@

         void Night()
         {
-            foreach (Agent agent in AliveAgentList)
-            {
-                GameServer.DayFinish(agent);
-            }
-
-            if (!GameSetting.TalkOnFirstDay && Day == 0)
+            foreach (var agent in AliveAgentList)
+            {
+                gameServer.DayFinish(agent);
+            }
+
+            if (!gameSetting.TalkOnFirstDay && Day == 0)
             {
                 Whisper();
             }
@@ -411,10 +370,10 @@
             List<Agent> candidates = null;
             if (Day != 0)
             {
-                for (int i = 0; i <= GameSetting.MaxRevote; i++)
+                for (var i = 0; i <= gameSetting.MaxRevote; i++)
                 {
                     Vote();
-                    candidates = GetVotedCandidates(GameData.VoteList);
+                    candidates = GetVotedCandidates(gameData.VoteList);
                     if (candidates.Count == 1)
                     {
                         executed = candidates[0];
@@ -423,14 +382,14 @@
                 }

                 // In case of multiple candidates.
-                if (executed == null && !GameSetting.EnableNoExecution)
+                if (executed == null && !gameSetting.EnableNoExecution)
                 {
                     executed = candidates.Shuffle().First();
                 }

                 if (executed != null)
                 {
-                    GameData.Executed = executed;
+                    gameData.Executed = executed;
                     if (GameLogger != null)
                     {
                         GameLogger.Log($"{Day},execute,{executed.AgentIdx},{RoleOf(executed)}");
@@ -446,16 +405,16 @@
                 Guard();

                 Agent attacked = null;
-                if (!(AliveWolfList.Count == 1 && RoleOf(GameData.Executed) == Role.WEREWOLF))
-                {
-                    for (int i = 0; i <= GameSetting.MaxAttackRevote; i++)
-                    {
-                        if (i > 0 && GameSetting.WhisperBeforeRevote)
+                if (!(AliveWolfList.Count == 1 && RoleOf(gameData.Executed) == Role.WEREWOLF))
+                {
+                    for (var i = 0; i <= gameSetting.MaxAttackRevote; i++)
+                    {
+                        if (i > 0 && gameSetting.WhisperBeforeRevote)
                         {
                             Whisper();
                         }
                         AttackVote();
-                        candidates = GetAttackVotedCandidates(GameData.AttackVoteList.Where(v => v.Agent != executed).ToList());
+                        candidates = GetAttackVotedCandidates(gameData.AttackVoteList.Where(v => v.Agent != executed).ToList());
                         if (candidates.Count == 1)
                         {
                             attacked = candidates[0];
@@ -464,19 +423,19 @@
                     }

                     // In case of multiple candidates.
-                    if (attacked == null && !GameSetting.EnableNoAttack)
+                    if (attacked == null && !gameSetting.EnableNoAttack)
                     {
                         attacked = candidates.Shuffle().First();
                     }

-                    GameData.Attacked = attacked;
-
-                    bool guarded = false;
-                    if (GameData.Guard != null)
-                    {
-                        if (GameData.Guard.Target == attacked && attacked != null)
-                        {
-                            if (GameData.Executed == null || GameData.Executed != GameData.Guard.Agent)
+                    gameData.Attacked = attacked;
+
+                    var guarded = false;
+                    if (gameData.Guard != null)
+                    {
+                        if (gameData.Guard.Target == attacked && attacked != null)
+                        {
+                            if (gameData.Executed == null || gameData.Executed != gameData.Guard.Agent)
                             {
                                 guarded = true;
                             }
@@ -484,8 +443,8 @@
                     }
                     if (!guarded && attacked != null && RoleOf(attacked) != Role.FOX)
                     {
-                        GameData.AttackedDead = attacked;
-                        GameData.AddLastDeadAgent(attacked);
+                        gameData.AttackedDead = attacked;
+                        gameData.AddLastDeadAgent(attacked);
                         if (GameLogger != null)
                         {
                             GameLogger.Log($"{Day},attack,{attacked.AgentIdx},true");
@@ -504,118 +463,99 @@
                         {
                             GameLogger.Log($"{Day},attack,-1,false");
                         }
-
-                    }
-
-                }
-
-            }
-
-            GameData = GameData.NextDay;
-            GameServer.GameData = GameData;
+                    }
+                }
+            }
+            gameData = gameData.NextDay;
+            gameServer.GameData = gameData;
         }

         List<Agent> GetVotedCandidates(List<Vote> voteList)
         {
-            Dictionary<Agent, int> counter = new Dictionary<Agent, int>();
-            foreach (Vote vote in voteList)
-            {
-                if (StatusOf(vote.Target) == Status.ALIVE)
-                {
-                    if (counter.ContainsKey(vote.Target))
-                    {
-                        counter[vote.Target]++;
+            var counter = new Dictionary<Agent, int>();
+            foreach (var vote in voteList.Where(v => StatusOf(v.Target) == Status.ALIVE))
+            {
+                if (counter.ContainsKey(vote.Target))
+                {
+                    counter[vote.Target]++;
+                }
+                else
+                {
+                    counter[vote.Target] = 1;
+                }
+            }
+            var max = counter.Count == 0 ? 0 : counter.Max(p => p.Value);
+            return counter.Keys.Where(a => counter[a] == max).ToList();
+        }
+
+        List<Agent> GetAttackVotedCandidates(List<Vote> voteList)
+        {
+            var counter = new Dictionary<Agent, int>();
+            foreach (var vote in voteList.Where(v => StatusOf(v.Target) == Status.ALIVE && RoleOf(v.Target) != Role.WEREWOLF))
+            {
+                if (counter.ContainsKey(vote.Target))
+                {
+                    counter[vote.Target]++;
+                }
+                else
+                {
+                    counter[vote.Target] = 1;
+                }
+            }
+            if (!gameSetting.EnableNoAttack)
+            {
+                foreach (var agent in AliveHumanList)
+                {
+                    if (counter.ContainsKey(agent))
+                    {
+                        counter[agent]++;
                     }
                     else
                     {
-                        counter[vote.Target] = 1;
-                    }
-                }
-            }
-            int max = 0;
-            if (counter.Count > 0)
-            {
-                max = counter.OrderBy(p => p.Value).Last().Value;
-            }
+                        counter[agent] = 1;
+                    }
+                }
+            }
+            var max = counter.Count == 0 ? 0 : counter.Max(p => p.Value);
             return counter.Keys.Where(a => counter[a] == max).ToList();
         }

-        List<Agent> GetAttackVotedCandidates(List<Vote> voteList)
-        {
-            Dictionary<Agent, int> counter = new Dictionary<Agent, int>();
-            foreach (Vote vote in voteList)
-            {
-                if (StatusOf(vote.Target) == Status.ALIVE && RoleOf(vote.Target) != Role.WEREWOLF)
-                {
-                    if (counter.ContainsKey(vote.Target))
-                    {
-                        counter[vote.Target]++;
+        void DayStart()
+        {
+            foreach (var agent in OrderedAgentList)
+            {
+                gameServer.DayStart(agent);
+                if (GameLogger != null)
+                {
+                    GameLogger.Log($"{Day},status,{agent.AgentIdx},{RoleOf(agent)},{StatusOf(agent)},{agentNameMap[agent]}");
+                }
+            }
+        }
+
+        void Talk()
+        {
+            foreach (var agent in AliveAgentList)
+            {
+                gameData.RemainTalkMap[agent] = gameSetting.MaxTalk;
+            }
+
+            var skipCounter = new Dictionary<Agent, int>();
+            for (var turn = 0; turn < gameSetting.MaxTalkTurn; turn++)
+            {
+                var talkList = new List<Talk>();
+                foreach (var agent in AliveAgentList.Shuffle())
+                {
+                    var text = Utterance.OVER;
+                    if (gameData.RemainTalkMap[agent] > 0)
+                    {
+                        text = gameServer.RequestTalk(agent);
+                    }
+                    if (text == null || text.Length == 0)
+                    {
+                        text = Utterance.SKIP;
                     }
                     else
                     {
-                        counter[vote.Target] = 1;
-                    }
-                }
-            }
-            if (!GameSetting.EnableNoAttack)
-            {
-                foreach (Agent agent in AliveHumanList)
-                {
-                    if (counter.ContainsKey(agent))
-                    {
-                        counter[agent]++;
-                    }
-                    else
-                    {
-                        counter[agent] = 1;
-                    }
-                }
-            }
-
-            int max = counter.OrderBy(p => p.Value).Last().Value;
-            return counter.Keys.Where(a => counter[a] == max).ToList();
-        }
-
-        void DayStart()
-        {
-            if (GameLogger != null)
-            {
-                foreach (Agent agent in OrderedAgentList)
-                {
-                    GameLogger.Log($"{Day},status,{agent.AgentIdx},{RoleOf(agent)},{StatusOf(agent)},{AgentNameMap[agent]}");
-                }
-            }
-
-            foreach (Agent agent in AliveAgentList)
-            {
-                GameServer.DayStart(agent);
-            }
-        }
-
-        void Talk()
-        {
-            foreach (Agent agent in AliveAgentList)
-            {
-                GameData.RemainTalkMap[agent] = GameSetting.MaxTalk;
-            }
-
-            Dictionary<Agent, int> skipCounter = new Dictionary<Agent, int>();
-            for (int turn = 0; turn < GameSetting.MaxTalkTurn; turn++)
-            {
-                List<Talk> talkList = new List<Talk>();
-                foreach (Agent agent in AliveAgentList.Shuffle())
-                {
-                    string text = Utterance.OVER;
-                    if (GameData.RemainTalkMap[agent] > 0)
-                    {
-                        text = GameServer.RequestTalk(agent);
-                    }
-                    if (text == null || text.Length == 0)
-                    {
-                        text = Utterance.SKIP;
-                    }
-                    else
-                    {
                         text = StripText(text);
                     }
                     if (text == Utterance.SKIP)
@@ -628,21 +568,21 @@
                         {
                             skipCounter[agent] = 1;
                         }
-                        if (skipCounter[agent] > GameSetting.MaxSkip)
+                        if (skipCounter[agent] > gameSetting.MaxSkip)
                         {
                             text = Utterance.OVER;
                         }
                     }
-                    talkList.Add(new Talk(GameData.NextTalkIdx, Day, turn, agent, text));
+                    talkList.Add(new Talk(gameData.NextTalkIdx, Day, turn, agent, text));
                     if (text != Utterance.OVER && text != Utterance.SKIP)
                     {
                         skipCounter[agent] = 0;
                     }
                 }
-                bool continueTalk = false;
-                foreach (Talk talk in talkList)
-                {
-                    GameData.AddTalk(talk.Agent, talk);
+                var continueTalk = false;
+                foreach (var talk in talkList)
+                {
+                    gameData.AddTalk(talk.Agent, talk);
                     if (GameLogger != null)
                     {
                         GameLogger.Log($"{Day},talk,{talk.Idx},{talk.Turn},{talk.Agent.AgentIdx},{talk.Text}");
@@ -666,21 +606,21 @@
             {
                 return;
             }
-            foreach (Agent agent in AliveWolfList)
-            {
-                GameData.RemainWhisperMap[agent] = GameSetting.MaxWhisper;
-            }
-
-            Dictionary<Agent, int> skipCounter = new Dictionary<Agent, int>();
-            for (int turn = 0; turn < GameSetting.MaxWhisperTurn; turn++)
-            {
-                List<Whisper> whisperList = new List<Whisper>();
-                foreach (Agent agent in AliveWolfList.Shuffle())
-                {
-                    string text = Utterance.OVER;
-                    if (GameData.RemainWhisperMap[agent] > 0)
-                    {
-                        text = GameServer.RequestWhisper(agent);
+            foreach (var agent in AliveWolfList)
+            {
+                gameData.RemainWhisperMap[agent] = gameSetting.MaxWhisper;
+            }
+
+            var skipCounter = new Dictionary<Agent, int>();
+            for (var turn = 0; turn < gameSetting.MaxWhisperTurn; turn++)
+            {
+                var whisperList = new List<Whisper>();
+                foreach (var agent in AliveWolfList.Shuffle())
+                {
+                    var text = Utterance.OVER;
+                    if (gameData.RemainWhisperMap[agent] > 0)
+                    {
+                        text = gameServer.RequestWhisper(agent);
                     }
                     if (text == null || text.Length == 0)
                     {
@@ -700,21 +640,21 @@
                         {
                             skipCounter[agent] = 1;
                         }
-                        if (skipCounter[agent] > GameSetting.MaxSkip)
+                        if (skipCounter[agent] > gameSetting.MaxSkip)
                         {
                             text = Utterance.OVER;
                         }
                     }
-                    whisperList.Add(new Whisper(GameData.NextWhisperIdx, Day, turn, agent, text));
+                    whisperList.Add(new Whisper(gameData.NextWhisperIdx, Day, turn, agent, text));
                     if (text != Utterance.OVER && text != Utterance.SKIP)
                     {
                         skipCounter[agent] = 0;
                     }
                 }
-                bool continueWhisper = false;
-                foreach (Whisper whisper in whisperList)
-                {
-                    GameData.AddWhisper(whisper.Agent, whisper);
+                var continueWhisper = false;
+                foreach (var whisper in whisperList)
+                {
+                    gameData.AddWhisper(whisper.Agent, whisper);
                     if (GameLogger != null)
                     {
                         GameLogger.Log($"{Day},whisper,{whisper.Idx},{whisper.Turn},{ whisper.Agent.AgentIdx},{whisper.Text}");
@@ -733,43 +673,43 @@

         void Vote()
         {
-            GameData.VoteList.Clear();
-            foreach (Agent agent in AliveAgentList)
-            {
-                Agent target = GameServer.RequestVote(agent);
+            gameData.VoteList.Clear();
+            foreach (var agent in AliveAgentList)
+            {
+                var target = gameServer.RequestVote(agent);
                 if (target == null || StatusOf(target) == Status.DEAD || agent == target)
                 {
                     target = AliveAgentList.Where(a => a != agent).Shuffle().First();
                 }
-                Vote vote = new Vote(Day, agent, target);
-                GameData.VoteList.Add(vote);
+                var vote = new Vote(Day, agent, target);
+                gameData.VoteList.Add(vote);
                 if (GameLogger != null)
                 {
                     GameLogger.Log($"{Day},vote,{agent.AgentIdx},{target.AgentIdx}");
                 }
             }
-            GameData.LatestVoteList = new List<Vote>(GameData.VoteList);
+            gameData.LatestVoteList = new List<Vote>(gameData.VoteList);
         }

         void Divine()
         {
-            foreach (Agent agent in AliveAgentList.Where(a => RoleOf(a) == Role.SEER))
-            {
-                Agent target = GameServer.RequestDivineTarget(agent);
-                Role targetRole = RoleOf(target);
+            foreach (var agent in AliveAgentList.Where(a => RoleOf(a) == Role.SEER))
+            {
+                var target = gameServer.RequestDivineTarget(agent);
+                var targetRole = RoleOf(target);
                 if (target == null || StatusOf(target) == Status.DEAD || targetRole == Role.UNC)
                 {
                     // Do nothing.
                 }
                 else
                 {
-                    Judge divine = new Judge(Day, agent, target, targetRole.GetSpecies());
-                    GameData.Divine = divine;
+                    var divine = new Judge(Day, agent, target, targetRole.GetSpecies());
+                    gameData.Divine = divine;

                     if (targetRole == Role.FOX)
                     {
-                        GameData.AddLastDeadAgent(target);
-                        GameData.CursedFox = target;
+                        gameData.AddLastDeadAgent(target);
+                        gameData.CursedFox = target;
                     }

                     if (GameLogger != null)
@@ -782,21 +722,21 @@

         void Guard()
         {
-            foreach (Agent agent in AliveAgentList.Where(a => RoleOf(a) == Role.BODYGUARD))
-            {
-                if (agent == GameData.Executed)
+            foreach (var agent in AliveAgentList.Where(a => RoleOf(a) == Role.BODYGUARD))
+            {
+                if (agent == gameData.Executed)
                 {
                     continue;
                 }
-                Agent target = GameServer.RequestGuardTarget(agent);
+                var target = gameServer.RequestGuardTarget(agent);
                 if (target == null || agent == target)
                 {
                     // Do nothing.
                 }
                 else
                 {
-                    Guard guard = new Guard(Day, agent, target);
-                    GameData.Guard = guard;
+                    var guard = new Guard(Day, agent, target);
+                    gameData.Guard = guard;

                     if (GameLogger != null)
                     {
@@ -806,23 +746,23 @@
             }
         }

-        Role RoleOf(Agent agent) => agent == null ? Role.UNC : GameData.RoleMap[agent];
-        Status StatusOf(Agent agent) => agent == null ? Status.UNC : GameData.StatusMap[agent];
+        Role RoleOf(Agent agent) => agent == null ? Role.UNC : gameData.RoleMap[agent];
+        Status StatusOf(Agent agent) => agent == null ? Status.UNC : gameData.StatusMap[agent];

         void AttackVote()
         {
-            GameData.AttackVoteList.Clear();
-            foreach (Agent agent in AliveWolfList)
-            {
-                Agent target = GameServer.RequestAttackTarget(agent);
+            gameData.AttackVoteList.Clear();
+            foreach (var agent in AliveWolfList)
+            {
+                var target = gameServer.RequestAttackTarget(agent);
                 if (target == null || StatusOf(target) == Status.DEAD || RoleOf(target) == Role.WEREWOLF)
                 {
                     // Do nothing.
                 }
                 else
                 {
-                    Vote attackVote = new Vote(Day, agent, target);
-                    GameData.AttackVoteList.Add(attackVote);
+                    var attackVote = new Vote(Day, agent, target);
+                    gameData.AttackVoteList.Add(attackVote);

                     if (GameLogger != null)
                     {
@@ -830,7 +770,7 @@
                     }
                 }
             }
-            GameData.LatestAttackVoteList = new List<Vote>(GameData.AttackVoteList);
+            gameData.LatestAttackVoteList = new List<Vote>(gameData.AttackVoteList);
         }

         static readonly Regex regexStripText = new Regex(@"^Agent\[.+?\] (.+)");


Changed App.cs.

Changed App.cs.

--- App2Night/App2Night/App.cs
+++ App2Night/App2Night/App.cs
@@ -56,15 +56,15 @@
             RegisterInterfaces();

             base.OnStart();
-            //SetUpMasterDetailPage<NavigationViewModel>();
-            //AddSiteToDetailPages(new MasterDetailData(typeof(DashboardViewModel), "Dashboard"));
-            //AddSiteToDetailPages(new MasterDetailData(typeof(PartyPickerViewModel), "Pick a party"));
-            //AddSiteToDetailPages(new MasterDetailData(typeof(CreatePartyViewModel), "Create"));
-            //AddSiteToDetailPages(new MasterDetailData(typeof(HistoryViewModel), "History"));
-            //AddSiteToDetailPages(new MasterDetailData(typeof(SettingViewModel), "Setting"));
-            //AddSiteToDetailPages(new MasterDetailData(typeof(AboutViewModel), "About"));
+            SetUpMasterDetailPage<NavigationViewModel>();
+            AddSiteToDetailPages(new MasterDetailData(typeof(DashboardViewModel), "Dashboard"));
+            AddSiteToDetailPages(new MasterDetailData(typeof(PartyPickerViewModel), "Pick a party"));
+            AddSiteToDetailPages(new MasterDetailData(typeof(CreatePartyViewModel), "Create"));
+            AddSiteToDetailPages(new MasterDetailData(typeof(HistoryViewModel), "History"));
+            AddSiteToDetailPages(new MasterDetailData(typeof(SettingViewModel), "Setting"));
+            AddSiteToDetailPages(new MasterDetailData(typeof(AboutViewModel), "About"));

-            SetUpMainPage<LoginViewModel>();
+            //SetUpMainPage<LoginViewModel>();

             //Task.Run(async () => { await StartupSync(); });


(DatOpener): check archive length first.

--- ArcFormats/Malie/ArcLIB.cs
+++ ArcFormats/Malie/ArcLIB.cs
@@ -140,12 +140,13 @@

         public override ArcFile TryOpen (ArcView file)
         {
+            if (file.MaxOffset <= 0x10)
+                return null;
             var header = new byte[0x10];
             foreach (var key in KnownKeys.Values)
             {
                 var encryption = new Camellia (key);
-                if (0x10 != ReadEncrypted (file.View, encryption, 0, header, 0, 0x10))
-                    continue;
+                ReadEncrypted (file.View, encryption, 0, header, 0, 0x10);
                 LibIndexReader reader;
                 if (Binary.AsciiEqual (header, 0, "LIBP"))
                     reader = new LibPReader (file, encryption, header);


Changed framerate renderer to approximately match the display time and fixed re-running the animation after its done


Smooth writing text

Smooth writing text

--- Assets/Scripts/Tutorial.cs
+++ Assets/Scripts/Tutorial.cs
@@ -104,19 +104,35 @@
                 }
                 nextText.SetActive(false);
                 pos = word.Length;
-                tutorialText.GetComponentInChildren<Text>().text = word + " ";
+                //tutorialText.GetComponentInChildren<Text>().text = word + " ";
+                tutorialText.GetComponentInChildren<Text>().text ="";
             } else {
                 pos += currLengt;
-                tutorialText.GetComponentInChildren<Text>().text += word + " ";
-            }
-
-            for (int i = 0; i < currLengt * 6; ++i) {
-                yield return null;
-            }
+                //tutorialText.GetComponentInChildren<Text>().text += word + " ";
+            }
+
+            // Smoth writing
+            for (int i = 0; i < currLengt - 1; ++i) {
+                tutorialText.GetComponentInChildren<Text>().text += word[i];
+                for (int j = 0; j < 6; ++j) {
+                    yield return null;
+                }
+
+            }
+            tutorialText.GetComponentInChildren<Text>().text += " ";
+

         }
         // End of writing
+        // Before end give player option to read
+        nextText.SetActive(true);
+        // While player doest tap on screen show message
+        while (!Input.GetMouseButtonDown(0)) {
+            yield return null;
+        }
+        nextText.SetActive(false);
+
         tutorialText.SetActive(false);
         movement.gameRunning = true;
         clickPosition.SetActive(true);


Rotate the cursor towards its origin ray.


echo when ToggleComm is on

echo when ToggleComm is on

--- Assets/udpMonitorScript.cs
+++ Assets/udpMonitorScript.cs
@@ -31,7 +31,13 @@

 		while (ToggleComm.isOn) {
 			try {
+				IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
+				byte[] data = client.Receive(ref anyIP);
+				string text = Encoding.ASCII.GetString(data);

+				if (text.Length > 0) {
+					client.Send(data, data.Length, anyIP); // echo
+				}
 			}
 			catch (Exception err) {


tests are not runned async anymore.

tests are not runned async anymore.

--- BuildScript/BuildScript.cs
+++ BuildScript/BuildScript.cs
@@ -81,8 +81,8 @@

 	    var flubuTests = context.CreateTarget("test")
 		    .SetDescription("Runs all tests in solution.")
-		    .AddCoreTaskAsync(x => x.ExecuteDotnetTask("test").WithArguments("Flubu.Tests\\Flubu.Tests.csproj"))
-		    .AddCoreTaskAsync(x => x.ExecuteDotnetTask("test").WithArguments("FlubuCore.WebApi.Tests\\FlubuCore.WebApi.Tests.csproj"));
+		    .AddCoreTask(x => x.ExecuteDotnetTask("test").WithArguments("Flubu.Tests\\Flubu.Tests.csproj"))
+		    .AddCoreTask(x => x.ExecuteDotnetTask("test").WithArguments("FlubuCore.WebApi.Tests\\FlubuCore.WebApi.Tests.csproj"));

 		var nugetPublish = context.CreateTarget("nuget.publish")
             .Do(PublishNuGetPackage).


Fix crazyhouse Pawn.IsValidMove error

Fix crazyhouse Pawn.IsValidMove error

--- ChessDotNet/Pieces/Pawn.cs
+++ ChessDotNet/Pieces/Pawn.cs
@@ -115,6 +115,8 @@
                     || (origin.Rank != 4 && Owner == Player.Black))
                     return false;
                 Move latestMove = _moves[_moves.Count - 1];
+                if (latestMove.NewPosition == null)
+                    return false;
                 if (latestMove.Player != ChessUtilities.GetOpponentOf(Owner))
                     return false;
                 if (!(game.GetPieceAt(latestMove.NewPosition) is Pawn))


Remove velocity inheritance from assault rifle projectile.


Improve detection of EditMode

Improve detection of EditMode

--- Components/ModelFactory.cs
+++ Components/ModelFactory.cs
@@ -10,6 +10,8 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Web;
+using DotNetNuke.Services.Personalization;
 using Satrabel.OpenContent.Components.Dnn;
 using Satrabel.OpenContent.Components.Handlebars;
 using Satrabel.OpenContent.Components.Manifest;
@@ -512,7 +514,6 @@
         }

         private bool? _isEditable;
-
         private bool IsEditable
         {
             get
@@ -521,6 +522,18 @@
                 //role lookup on every property access (instead caching the result)
                 if (!_isEditable.HasValue)
                 {
+                    //first check some weird Dnn issue
+                    if (HttpContext.Current != null && HttpContext.Current.Request.IsAuthenticated)
+                    {
+                        var personalization = (PersonalizationInfo)HttpContext.Current.Items["Personalization"];
+                        if (personalization != null && personalization.UserId == -1)
+                        {
+                            //this should never happen.
+                            //Let us make sure that the wrong value is no longer cached
+                            HttpContext.Current.Items.Remove("Personalization");
+                        }
+                    }
+
                     bool blnPreview = (PortalSettings.UserMode == PortalSettings.Mode.View);
                     if (Globals.IsHostTab(PortalSettings.ActiveTab.TabID))
                     {


Rewrite folder write permission check to hopefully make it more reliable

--- Core/Utils/WindowsUtils.cs
+++ Core/Utils/WindowsUtils.cs
@@ -1,6 +1,5 @@
 using System.Diagnostics;
 using System.IO;
-using System.Linq;
 using System.Security.AccessControl;
 using System.Security.Principal;

@@ -8,23 +7,15 @@
     static class WindowsUtils{
         public static bool CheckFolderPermission(string path, FileSystemRights right){
             try{
-                AuthorizationRuleCollection rules = Directory.GetAccessControl(path).GetAccessRules(true, true, typeof(SecurityIdentifier));
-                WindowsIdentity identity = WindowsIdentity.GetCurrent();
+                AuthorizationRuleCollection collection = Directory.GetAccessControl(path).GetAccessRules(true, true, typeof(NTAccount));

-                if (identity.Groups == null){
-                    return false;
-                }
-
-                bool accessAllow = false, accessDeny = false;
-
-                foreach(FileSystemAccessRule rule in rules.Cast<FileSystemAccessRule>().Where(rule => identity.Groups.Contains(rule.IdentityReference) && (right & rule.FileSystemRights) == right)){
-                    switch(rule.AccessControlType){
-                        case AccessControlType.Allow: accessAllow = true; break;
-                        case AccessControlType.Deny: accessDeny = true; break;
+                foreach(FileSystemAccessRule rule in collection){
+                    if ((rule.FileSystemRights & right) == right){
+                        return true;
                     }
                 }

-                return accessAllow && !accessDeny;
+                return false;
             }
             catch{
                 return false;


protect play video

protect play video

--- CorePlugin/OgvComponent.cs
+++ CorePlugin/OgvComponent.cs
@@ -188,21 +188,29 @@

 		public void Play()
 		{
-			if (State != MediaState.Stopped)
-				return;
-
-			if(!CanRunOnThisArchitecture)
-				Log.Editor.WriteWarning("Can't play video on this architecture sorry ");
-
-			WaitForAndDisposeAudioThread();
-
-			if (_theoraVideo == null || _theoraVideo.Disposed)
-				Initialize();
-
-			State = MediaState.Playing;
-			_audioThread = Task.Factory.StartNew(DecodeAudio);
-
-			_startTime = (float)Time.GameTimer.TotalMilliseconds;
+			try
+			{
+				if (State != MediaState.Stopped)
+					return;
+
+				if(!CanRunOnThisArchitecture)
+					Log.Editor.WriteWarning("Can't play video on this architecture sorry ");
+
+				WaitForAndDisposeAudioThread();
+
+				if (_theoraVideo == null || _theoraVideo.Disposed)
+					Initialize();
+
+				State = MediaState.Playing;
+				_audioThread = Task.Factory.StartNew(DecodeAudio);
+
+				_startTime = (float)Time.GameTimer.TotalMilliseconds;
+			}
+			catch(Exception exception)
+			{
+				Log.Game.WriteWarning("Video component failed with error {0}",Log.Exception(exception) );
+
+			}
 		}

 		public void Stop()


Fix typo in ROL that made it call OR.

Fix typo in ROL that made it call OR.

--- DaNES.Emulation/Cpu6502.cs
+++ DaNES.Emulation/Cpu6502.cs
@@ -475,7 +475,7 @@
 			Carry = (value & 128) != 0;
 			return SetZN((byte)((value << 1) | (old_carry ? 1 : 0)));
 		}
-		void ROL(ushort address) => Ram.Write(address, ROR(Ram.Read(address)));
+		void ROL(ushort address) => Ram.Write(address, ROL(Ram.Read(address)));
 		void ROL_A() => Accumulator = ROL(Accumulator);

 		void Push(ushort value) => Push(ToBytes(value));


Add code to sample the mini-fluxgates and pump and probe PDs every shot. It works in debug mode, but is otherwise untested!

--- EDMBlockHead/Acquisitor.cs
+++ EDMBlockHead/Acquisitor.cs
@@ -38,8 +38,10 @@
 		ArrayList switchedChannels;
 		ScannedAnalogInputCollection inputs;
 		Task inputTask;
+        Task singlePointInputTask;
  		AnalogMultiChannelReader inputReader;
-		ScanMaster.Controller scanMaster;
+        AnalogMultiChannelReader singlePointInputReader;
+        ScanMaster.Controller scanMaster;
 		EDMPhaseLock.MainForm phaseLock;
         EDMHardwareControl.Controller hardwareController;

@@ -155,6 +157,27 @@
 					// keep an eye on what the phase lock is doing
                     p.SinglePointData.Add("PhaseLockFrequency", phaseLock.OutputFrequency);
                     p.SinglePointData.Add("PhaseLockError", phaseLock.PhaseError);
+                    // scan the analog inputs
+                    double[,] spd;
+                    // fake some data if we're in debug mode
+                    if (Environs.Debug)
+                    {
+                        spd = new double[4,1];
+                        spd[0, 0] = 1;
+                        spd[1, 0] = 2;
+                        spd[2, 0] = 3;
+                        spd[3, 0] = 4;
+                    }
+                    else
+                    {
+                        singlePointInputTask.Start();
+                        spd = singlePointInputReader.ReadMultiSample(1);
+                        singlePointInputTask.Stop();
+                    }
+                    p.SinglePointData.Add("ProbePD", spd[0, 0]);
+                    p.SinglePointData.Add("PumpPD", spd[1, 0]);
+                    p.SinglePointData.Add("MiniFlux1", spd[2, 0]);
+                    p.SinglePointData.Add("MiniFlux2", spd[3, 0]);

                     // randomise the Ramsey phase
                     // TODO: enable this once we know what we want to do.
@@ -348,6 +371,37 @@
             inputs.Channels.Add(battery);
         }

+        private void ConfigureSinglePointAnalogInputs()
+        {
+            // here we configure the scan of analog inputs that happens after each shot.
+            singlePointInputTask = new Task("Blockhead single point inputs");
+
+            AddChannelToSinglePointTask("probePD");
+            AddChannelToSinglePointTask("pumpPD");
+            AddChannelToSinglePointTask("miniFlux1");
+            AddChannelToSinglePointTask("miniFlux2");
+
+            singlePointInputTask.Timing.ConfigureSampleClock(
+                    "",
+                    1000,
+                    SampleClockActiveEdge.Rising,
+                    SampleQuantityMode.FiniteSamples,
+                    1
+                 );
+
+            singlePointInputTask.Triggers.StartTrigger.ConfigureNone();
+
+            if (!Environs.Debug) singlePointInputTask.Control(TaskAction.Verify);
+            singlePointInputReader = new AnalogMultiChannelReader(singlePointInputTask.Stream);
+
+        }
+
+        private void AddChannelToSinglePointTask(string chan)
+        {
+            AnalogInputChannel aic = ((AnalogInputChannel)Environs.Hardware.AnalogInputChannels[chan]);
+            aic.AddToTask(singlePointInputTask, 0, 10);
+        }
+
 		// configure hardware and start the pattern output
 		private void AcquisitionStarting()
 		{
@@ -381,8 +435,9 @@
                 );

             if (!Environs.Debug) inputTask.Control(TaskAction.Verify);
-            inputReader = new AnalogMultiChannelReader(inputTask.Stream);
-
+            inputReader = new AnalogMultiChannelReader(inputTask.Stream);
+
+            ConfigureSinglePointAnalogInputs();
 		}

 		// If you want to store any information in the BlockConfig this is the place to do it.
@@ -461,6 +516,7 @@
 		{
 			foreach( SwitchedChannel s in switchedChannels) s.AcquisitionFinishing();
 			inputTask.Dispose();
+            singlePointInputTask.Dispose();
 		}

 		private bool CheckIfStopping()


Hide prescale panel when in menu.

Hide prescale panel when in menu.

--- EasyScale/PrescalePanel.cs
+++ EasyScale/PrescalePanel.cs
@@ -112,7 +112,7 @@

         private void OnGUI()
         {
-            if (Game.IsSimulating || !Mod.ModEnabled) return;
+            if (StatMaster.isSimulating || StatMaster.inMenu || !Mod.ModEnabled) return;
             if (!Animating)
                 WindowRect.position = Minimized
                     ? MinimizedPosition


Update component menu entries

Update component menu entries

--- Editor/ComponentCreator.cs
+++ Editor/ComponentCreator.cs
@@ -15,43 +15,43 @@

     public static class ComponentCreator {

-        [MenuItem("Assets/Create/ATP/AnimationPathTools/Animation Path")]
+        [MenuItem("Assets/Create/AirTime Productions/AnimationPath Animator/Animation Path")]
         private static void CreatePathAsset() {
             ScriptableObjectUtility.CreateAsset<PathData>("AnimationPath");
         }

-        [MenuItem("Assets/Create/ATP/AnimationPathTools/Animator Settings")]
+        [MenuItem("Assets/Create/AirTime Productions/AnimationPath Animator/Animator Settings")]
         private static void CreateAnimatorSettingsAsset() {
             ScriptableObjectUtility.CreateAsset<AnimatorSettings>("AnimatorSettings");
         }

-        [MenuItem("Assets/Create/ATP/AnimationPathTools/AnimatorEvents Settings")]
+        [MenuItem("Assets/Create/AirTime Productions/AnimationPath Animator/AnimatorEvents Settings")]
         private static void CreateAPEventsReflectionSettingsAsset() {
             ScriptableObjectUtility.CreateAsset<AnimatorEventsSettings>("AnimatorEventsSettings");
         }

-        [MenuItem("Component/ATP/AnimationPathTools/AnimationPathAnimator")]
+        [MenuItem("Component/AirTime Productions/AnimationPath Animator/AnimationPathAnimator")]
         private static void AddAnimationPathAnimatorComponent() {
             if (Selection.activeGameObject != null) {
                 Selection.activeGameObject.AddComponent(typeof(AnimationPathAnimator));
             }
         }

-        [MenuItem("Component/ATP/AnimationPathTools/AnimatorEvents")]
+        [MenuItem("Component/AirTime Productions/AnimationPath Animator/AnimatorEvents")]
         private static void AddAnimatorEventsComponent() {
             if (Selection.activeGameObject != null) {
                 Selection.activeGameObject.AddComponent(typeof(AnimatorEvents));
             }
         }

-        [MenuItem("Component/ATP/AnimationPathTools/AnimatorSynchronizer")]
+        [MenuItem("Component/AirTime Productions/AnimationPath Animator/AnimatorSynchronizer")]
         private static void AddAnimatorSynchronizerComponent() {
             if (Selection.activeGameObject != null) {
                 Selection.activeGameObject.AddComponent(typeof(AnimatorSynchronizer));
             }
         }

-        [MenuItem("Component/ATP/AnimationPathTools/AudioSynchronizer")]
+        [MenuItem("Component/AirTime Productions/AnimationPath Animator/AudioSynchronizer")]
         private static void AddAudioSynchronizerComponent() {
             if (Selection.activeGameObject != null) {
                 Selection.activeGameObject.AddComponent(typeof(AudioSynchronizer));


Fix bug in live mode consolidator updates with Tick resolution

This PR fixes issue #796

--- Engine/AlgorithmManager.cs
+++ Engine/AlgorithmManager.cs
@@ -480,7 +480,8 @@
                                 var algorithmTimeSpan = resolutionTimeSpan == TimeSpan.FromTicks(0)
                                     ? TimeSpan.FromTicks(0)
                                     : TimeSpan.FromSeconds(1);
-                                if (algorithm.UtcTime.RoundDown(algorithmTimeSpan) == dataPoint.EndTime.RoundUp(resolutionTimeSpan).ConvertToUtc(update.Target.ExchangeTimeZone))
+                                if (update.Target.Resolution == Resolution.Tick ||
+                                    algorithm.UtcTime.RoundDown(algorithmTimeSpan) == dataPoint.EndTime.RoundUp(resolutionTimeSpan).ConvertToUtc(update.Target.ExchangeTimeZone))
                                 {
                                     consolidator.Update(dataPoint);
                                 }


Indeterminate progress state

Indeterminate progress state

--- Errlock/MainWindow.xaml.cs
+++ Errlock/MainWindow.xaml.cs
@@ -43,11 +43,16 @@
             module.NewNotice +=
                 (sender, e) => { App.Logger.Log(e.Notice.Text, LoggerMessageType.Warn); };

-            this.TaskbarItemInfo.ProgressState = TaskbarItemProgressState.Normal;
+            this.ModuleProgress.IsIndeterminate = !module.IsSupportProgressReporting;
+            this.TaskbarItemInfo.ProgressState = module.IsSupportProgressReporting
+                ? TaskbarItemProgressState.Normal
+                : TaskbarItemProgressState.Indeterminate;
+
             module.Progress.ProgressChanged += (sender, i) => {
                 this.ModuleProgress.Value = i;
                 this.TaskbarItemInfo.ProgressValue = (double)i / 100;
             };
+
             ModuleProgress.Visibility = Visibility.Visible;
             var scanResult = await Task.Factory.StartNew(() => {
                 try {