<commit_before>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using UnityEngine;
using Color = UnityEngine.Color;

namespace Rs317.Sharp
{
	public sealed class RsUnityWebGLClient : RsUnityClient
	{
		private MonoBehaviour ClientMonoBehaviour { get; }

		public RsUnityWebGLClient(ClientConfiguration config, UnityRsGraphics graphicsObject, [NotNull] MonoBehaviour clientMonoBehaviour) 
			: base(config, graphicsObject, new WebGLRunnableStarterStrategy(), new DefaultRsSocketFactory(new WebGLSocketThreadRunnableStarterStrategy()))
		{
			if (config == null) throw new ArgumentNullException(nameof(config));

			ClientMonoBehaviour = clientMonoBehaviour ?? throw new ArgumentNullException(nameof(clientMonoBehaviour));

			//Only need to override this for WebGL.
			Sprite.ExternalLoadImageHook += ExternalLoadImageHook;
		}

		private LoadedImagePixels ExternalLoadImageHook(byte[] arg)
		{
			//LoadImage will replace with with incoming image size.
			Texture2D tex = new Texture2D(2, 2, TextureFormat.RGB24, false);
			ImageConversion.LoadImage(tex, arg);
			tex = FlipTexture(tex);
			int[] pixels = tex.GetPixels32().Select(ColorUtils.ColorToRGB).ToArray();

			return new LoadedImagePixels(tex.height, tex.width, pixels);
		}

		Texture2D FlipTexture(Texture2D original)
		{
			Texture2D flipped = new Texture2D(original.width, original.height);

			int xN = original.width;
			int yN = original.height;

			for(int i = 0; i < xN; i++)
			{
				for(int j = 0; j < yN; j++)
				{
					flipped.SetPixel(i, yN - j - 1, original.GetPixel(i, j));
				}
			}
			flipped.Apply();

			return flipped;
		}

		protected override IRSGraphicsProvider<UnityRsGraphics> CreateGraphicsProvider()
		{
			return new UnityRsGraphicsProvider(GraphicsObject);
		}

		protected override BaseRsImageProducer<UnityRsGraphics> CreateNewImageProducer(int xSize, int ySize, string producerName)
		{
			return new UnityRsImageProducer(xSize, ySize, producerName, gameGraphics);
		}

		public override void createClientFrame(int width, int height)
		{
			this.width = width;
			this.height = height;

			signlink.applet = this;
			gameGraphics = CreateGraphicsProvider();
			fullGameScreen = CreateNewImageProducer(this.width, height, nameof(fullGameScreen));

			run();
		}

		private IEnumerator RunnableRunCoroutine(IRunnable runnable)
		{
			yield return new WaitForEndOfFrame();

			//Hope for the best, how it doesn't run infinitely or Unity will break.
			runnable.run();
		}

		protected override void StartOnDemandFetcher(Archive archiveVersions)
		{
			//Webgl requires a non-blocking archive loading system.
			/*onDemandFetcher = new OnDemandFetcher();
			onDemandFetcher.start(archiveVersions, this);*/
			WebGLOnDemandFetcher fetcher = new WebGLOnDemandFetcher();
			onDemandFetcher = fetcher;
			fetcher.Initialize(archiveVersions, this);
			ClientMonoBehaviour.StartCoroutine(fetcher.RunCoroutine());
		}

		protected override void StartFlameDrawing()
		{
			Debug.Log($"Starting flames drawing.");
			shouldDrawFlames = true;
			currentlyDrawingFlames = true;
			ClientMonoBehaviour.StartCoroutine(DrawFlamesCoroutine());
		}

		public override void run()
		{
			if(!shouldDrawFlames)
			{
				//If it's webgl, we need to implement it on the main thread
				//as a coroutine. Otherwise WebGL will just not work due to
				//threading limitations.
				ClientMonoBehaviour.StartCoroutine(AppletRunCoroutine());
			}
		}

		private WaitForSeconds flamesWaitable = new WaitForSeconds(0.025f);

		private IEnumerator DrawFlamesCoroutine()
		{
			Debug.Log($"Starting flame drawing.");
			drawingFlames = true;

			while(currentlyDrawingFlames)
			{
				flameCycle++;
				calcFlamesPosition();
				calcFlamesPosition();
				doFlamesDrawing();

				yield return flamesWaitable;
			}

			drawingFlames = false;
		}

		public override void startUp()
		{
			if (!RsUnityPlatform.isWebGLBuild)
				base.startUp();
			else
				ClientMonoBehaviour.StartCoroutine(StartupCoroutine());
		}

		public IEnumerator StartupCoroutine()
		{
			if(!wasClientStartupCalled)
				wasClientStartupCalled = true;
			else
				throw new InvalidOperationException($"Failed. Cannot call startup on Client multiple times.");<commit_msg>Implement WebGL stop flaming (fixes deadlock)<commit_after>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using UnityEngine;
using Color = UnityEngine.Color;

namespace Rs317.Sharp
{
	public sealed class RsUnityWebGLClient : RsUnityClient
	{
		private MonoBehaviour ClientMonoBehaviour { get; }

		public RsUnityWebGLClient(ClientConfiguration config, UnityRsGraphics graphicsObject, [NotNull] MonoBehaviour clientMonoBehaviour) 
			: base(config, graphicsObject, new WebGLRunnableStarterStrategy(), new DefaultRsSocketFactory(new WebGLSocketThreadRunnableStarterStrategy()))
		{
			if (config == null) throw new ArgumentNullException(nameof(config));

			ClientMonoBehaviour = clientMonoBehaviour ?? throw new ArgumentNullException(nameof(clientMonoBehaviour));

			//Only need to override this for WebGL.
			Sprite.ExternalLoadImageHook += ExternalLoadImageHook;
		}

		private LoadedImagePixels ExternalLoadImageHook(byte[] arg)
		{
			//LoadImage will replace with with incoming image size.
			Texture2D tex = new Texture2D(2, 2, TextureFormat.RGB24, false);
			ImageConversion.LoadImage(tex, arg);
			tex = FlipTexture(tex);
			int[] pixels = tex.GetPixels32().Select(ColorUtils.ColorToRGB).ToArray();

			return new LoadedImagePixels(tex.height, tex.width, pixels);
		}

		Texture2D FlipTexture(Texture2D original)
		{
			Texture2D flipped = new Texture2D(original.width, original.height);

			int xN = original.width;
			int yN = original.height;

			for(int i = 0; i < xN; i++)
			{
				for(int j = 0; j < yN; j++)
				{
					flipped.SetPixel(i, yN - j - 1, original.GetPixel(i, j));
				}
			}
			flipped.Apply();

			return flipped;
		}

		protected override IRSGraphicsProvider<UnityRsGraphics> CreateGraphicsProvider()
		{
			return new UnityRsGraphicsProvider(GraphicsObject);
		}

		protected override BaseRsImageProducer<UnityRsGraphics> CreateNewImageProducer(int xSize, int ySize, string producerName)
		{
			return new UnityRsImageProducer(xSize, ySize, producerName, gameGraphics);
		}

		public override void createClientFrame(int width, int height)
		{
			this.width = width;
			this.height = height;

			signlink.applet = this;
			gameGraphics = CreateGraphicsProvider();
			fullGameScreen = CreateNewImageProducer(this.width, height, nameof(fullGameScreen));

			run();
		}

		private IEnumerator RunnableRunCoroutine(IRunnable runnable)
		{
			yield return new WaitForEndOfFrame();

			//Hope for the best, how it doesn't run infinitely or Unity will break.
			runnable.run();
		}

		protected override void StartOnDemandFetcher(Archive archiveVersions)
		{
			//Webgl requires a non-blocking archive loading system.
			/*onDemandFetcher = new OnDemandFetcher();
			onDemandFetcher.start(archiveVersions, this);*/
			WebGLOnDemandFetcher fetcher = new WebGLOnDemandFetcher();
			onDemandFetcher = fetcher;
			fetcher.Initialize(archiveVersions, this);
			ClientMonoBehaviour.StartCoroutine(fetcher.RunCoroutine());
		}

		protected override void StartFlameDrawing()
		{
			Debug.Log($"Starting flames drawing.");
			shouldDrawFlames = true;
			currentlyDrawingFlames = true;
			ClientMonoBehaviour.StartCoroutine(DrawFlamesCoroutine());
		}

		public override void run()
		{
			if(!shouldDrawFlames)
			{
				//If it's webgl, we need to implement it on the main thread
				//as a coroutine. Otherwise WebGL will just not work due to
				//threading limitations.
				ClientMonoBehaviour.StartCoroutine(AppletRunCoroutine());
			}
		}

		private WaitForSeconds flamesWaitable = new WaitForSeconds(0.025f);

		private IEnumerator DrawFlamesCoroutine()
		{
			Debug.Log($"Starting flame drawing.");
			drawingFlames = true;

			while(currentlyDrawingFlames)
			{
				flameCycle++;
				calcFlamesPosition();
				calcFlamesPosition();
				doFlamesDrawing();

				yield return flamesWaitable;
			}

			drawingFlames = false;
		}

		protected override void StopDrawingFlames()
		{
			currentlyDrawingFlames = false;
		}

		public override void startUp()
		{
			if (!RsUnityPlatform.isWebGLBuild)
				base.startUp();
			else
				ClientMonoBehaviour.StartCoroutine(StartupCoroutine());
		}

		public IEnumerator StartupCoroutine()
		{
			if(!wasClientStartupCalled)
				wasClientStartupCalled = true;
			else
				throw new InvalidOperationException($"Failed. Cannot call startup on Client multiple times.");
{'fraction_non_alphanumeric': 0.09252990295644324, 'fraction_numerical': 0.004965019183028662, 'mean_word_length': 4.447449293177628, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2362944', 'n_tokens_mistral': 3216, 'n_tokens_neox': 2690, 'n_words': 646}