mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-10-15 16:03:37 -04:00
Removed NioTSO client and server
- NioTSO client isn't needed because we're using RayLib - Added FreeSO's API server to handle most backend operations
This commit is contained in:
parent
f12ba1502b
commit
22191ce648
591 changed files with 53264 additions and 3362 deletions
103
server/tso.common/Rendering/Emoji/EmojiCache.cs
Executable file
103
server/tso.common/Rendering/Emoji/EmojiCache.cs
Executable file
|
@ -0,0 +1,103 @@
|
|||
using FSO.Common.Utils;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace FSO.Common.Rendering.Emoji
|
||||
{
|
||||
public class EmojiCache
|
||||
{
|
||||
public string Source = "https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/";
|
||||
public int DefaultRes = 24;
|
||||
public int Width = 32;
|
||||
|
||||
public int NextIndex = 0;
|
||||
public List<string> Emojis = new List<string>();
|
||||
public Dictionary<string, int> EmojiToIndex = new Dictionary<string, int>();
|
||||
public RenderTarget2D EmojiTex;
|
||||
public SpriteBatch EmojiBatch;
|
||||
public HashSet<int> IncompleteSpaces = new HashSet<int>();
|
||||
public HashSet<int> ErrorSpaces = new HashSet<int>();
|
||||
private GraphicsDevice GD;
|
||||
private bool needClear = true;
|
||||
|
||||
public EmojiCache(GraphicsDevice gd)
|
||||
{
|
||||
GD = gd;
|
||||
EmojiBatch = new SpriteBatch(gd);
|
||||
|
||||
EmojiTex = new RenderTarget2D(gd, Width * DefaultRes, Width * DefaultRes, false, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
|
||||
}
|
||||
|
||||
public void ExpandIfNeeded()
|
||||
{
|
||||
//todo
|
||||
}
|
||||
|
||||
public Rectangle GetEmoji(string emojiID) {
|
||||
|
||||
int index;
|
||||
if (EmojiToIndex.TryGetValue(emojiID, out index))
|
||||
{
|
||||
return RectForIndex(index);
|
||||
} else
|
||||
{
|
||||
index = NextIndex++;
|
||||
ExpandIfNeeded();
|
||||
lock (IncompleteSpaces) IncompleteSpaces.Add(index);
|
||||
var client = new WebClient();
|
||||
client.DownloadDataCompleted += (object sender, DownloadDataCompletedEventArgs e) =>
|
||||
{
|
||||
if (e.Cancelled || e.Error != null || e.Result == null)
|
||||
{
|
||||
lock (ErrorSpaces) ErrorSpaces.Add(index);
|
||||
} else
|
||||
{
|
||||
GameThread.NextUpdate(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var mem = new MemoryStream(e.Result))
|
||||
{
|
||||
var tex = Texture2D.FromStream(GD, mem);
|
||||
|
||||
var decimated = TextureUtils.Decimate(tex, GD, 72 / DefaultRes, true);
|
||||
//blit this into our emoji buffer
|
||||
GD.SetRenderTarget(EmojiTex);
|
||||
if (needClear)
|
||||
{
|
||||
GD.Clear(Color.TransparentBlack);
|
||||
needClear = false;
|
||||
}
|
||||
EmojiBatch.Begin(blendState: BlendState.NonPremultiplied, sortMode: SpriteSortMode.Immediate);
|
||||
EmojiBatch.Draw(decimated, RectForIndex(index), Color.White);
|
||||
EmojiBatch.End();
|
||||
GD.SetRenderTarget(null);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
lock (ErrorSpaces) ErrorSpaces.Add(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
lock (IncompleteSpaces) IncompleteSpaces.Remove(index);
|
||||
};
|
||||
client.DownloadDataAsync(new Uri((emojiID[0] == '!')?(emojiID.Substring(1)):(Source + emojiID + ".png")));
|
||||
Emojis.Add(emojiID);
|
||||
EmojiToIndex[emojiID] = index;
|
||||
return RectForIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
private Rectangle RectForIndex(int index)
|
||||
{
|
||||
return new Rectangle((index % Width) * DefaultRes, (index / Width) * DefaultRes, DefaultRes, DefaultRes);
|
||||
}
|
||||
}
|
||||
}
|
95
server/tso.common/Rendering/Emoji/EmojiDictionary.cs
Executable file
95
server/tso.common/Rendering/Emoji/EmojiDictionary.cs
Executable file
|
@ -0,0 +1,95 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace FSO.Common.Rendering.Emoji
|
||||
{
|
||||
public class EmojiDictionary
|
||||
{
|
||||
public Dictionary<string, string> NameToEmojis = new Dictionary<string, string>();
|
||||
public Dictionary<string, List<string>> KeywordToCandidates = new Dictionary<string, List<string>>();
|
||||
public Dictionary<string, List<string>> CandidatesToKeywords = new Dictionary<string, List<string>>();
|
||||
|
||||
public EmojiDictionary()
|
||||
{
|
||||
JObject emojis;
|
||||
using (var emojiDict = new StreamReader(
|
||||
new FileStream(Path.Combine(FSOEnvironment.ContentDir, "UI/emojis.json"), FileMode.Open, FileAccess.Read, FileShare.Read)))
|
||||
{
|
||||
emojis = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(emojiDict.ReadToEnd());
|
||||
}
|
||||
|
||||
foreach (var token in emojis)
|
||||
{
|
||||
var charValue = token.Value.Value<string>("char");
|
||||
var twemojiID = ToCodePoint(charValue);
|
||||
NameToEmojis[token.Key] = twemojiID;
|
||||
var keys = token.Value.Value<JArray>("keywords");
|
||||
foreach (var key in keys)
|
||||
AddKeyword(key.Value<string>(), token.Key);
|
||||
}
|
||||
|
||||
using (var emojiDict = new StreamReader(
|
||||
new FileStream(Path.Combine(FSOEnvironment.ContentDir, "UI/customemojis.json"), FileMode.Open, FileAccess.Read, FileShare.Read)))
|
||||
{
|
||||
emojis = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(emojiDict.ReadToEnd());
|
||||
}
|
||||
|
||||
foreach (var token in emojis)
|
||||
{
|
||||
NameToEmojis[token.Key] = "!" + token.Value.Value<string>("url");
|
||||
var keys = token.Value.Value<JArray>("keywords");
|
||||
foreach (var key in keys)
|
||||
AddKeyword(key.Value<string>(), token.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddKeyword(string keyword, string candidate)
|
||||
{
|
||||
List<string> cand;
|
||||
if (!KeywordToCandidates.TryGetValue(keyword, out cand))
|
||||
{
|
||||
cand = new List<string>();
|
||||
KeywordToCandidates[keyword] = cand;
|
||||
}
|
||||
cand.Add(candidate);
|
||||
|
||||
if (!CandidatesToKeywords.TryGetValue(candidate, out cand))
|
||||
{
|
||||
cand = new List<string>();
|
||||
CandidatesToKeywords[candidate] = cand;
|
||||
}
|
||||
cand.Add(keyword);
|
||||
}
|
||||
|
||||
public string ToCodePoint(string str)
|
||||
{
|
||||
var cs = str.ToCharArray();
|
||||
var i = 0;
|
||||
var c = 0;
|
||||
var p = 0;
|
||||
var r = new List<string>();
|
||||
var zeroWidth = str.Any(x => x == '\x200D');
|
||||
while (i < cs.Length)
|
||||
{
|
||||
c = cs[i++];
|
||||
if (c == 0xfe0f && !zeroWidth) continue; //"as image", just ignore this
|
||||
if (p > 0)
|
||||
{
|
||||
r.Add((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).ToString("x"));
|
||||
p = 0;
|
||||
}
|
||||
else if (0xD800 <= c && c <= 0xDBFF)
|
||||
{
|
||||
p = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.Add(c.ToString("x"));
|
||||
}
|
||||
}
|
||||
return string.Join("-", r);
|
||||
}
|
||||
}
|
||||
}
|
232
server/tso.common/Rendering/Emoji/EmojiProvider.cs
Executable file
232
server/tso.common/Rendering/Emoji/EmojiProvider.cs
Executable file
|
@ -0,0 +1,232 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FSO.Common.Rendering.Emoji
|
||||
{
|
||||
public class EmojiProvider
|
||||
{
|
||||
public EmojiDictionary Dict;
|
||||
public EmojiCache Cache;
|
||||
public Random DictRand = new Random();
|
||||
|
||||
public Dictionary<string, string> TranslateShortcuts = new Dictionary<string, string>()
|
||||
{
|
||||
{ "i", "eye" },
|
||||
{ "you", "point_right" },
|
||||
{ "your", "point_right" },
|
||||
{ "you're", "point_right" },
|
||||
{ "me", "relieved: :point_left" },
|
||||
{ "i'm", "relieved: :point_left" },
|
||||
{ "us", "couple" },
|
||||
{ "we", "couple" },
|
||||
{ "our", "couple" },
|
||||
{ "what", "woman_shrugging" },
|
||||
{ "be", "b" },
|
||||
{ "to", "two" },
|
||||
{ "and", "symbols" },
|
||||
{ "that", "point_up" },
|
||||
{ "for", "four" },
|
||||
{ "not", "exclamation" },
|
||||
{ "this", "point_up" },
|
||||
{ "but", "exclamation" },
|
||||
{ "his", "man" },
|
||||
{ "her", "woman" },
|
||||
{ "him", "man" },
|
||||
{ "he", "man" },
|
||||
{ "she", "woman" },
|
||||
{ "from", "postbox" },
|
||||
{ "they", "family_man_woman_girl_boy" },
|
||||
{ "them", "family_man_woman_girl_boy" },
|
||||
{ "or", "thinking" },
|
||||
{ "an", "a" },
|
||||
{ "will", "thinking" },
|
||||
{ "my", "relieved: :point_left" },
|
||||
{ "all", "rainbow_flag" },
|
||||
{ "would", "tree" },
|
||||
{ "so", "woman_shrugging" },
|
||||
{ "out", "outbox_tray" },
|
||||
{ "if", "thinking" },
|
||||
{ "about", "arrows_counterclockwise" },
|
||||
{ "who", "thinking: :family_man_woman_girl_boy" },
|
||||
{ "get", "gift" },
|
||||
{ "which", "woman_shrugging" },
|
||||
{ "go", "door" },
|
||||
{ "when", "watch" },
|
||||
{ "make", "toolbox" },
|
||||
{ "know", "brain" },
|
||||
{ "take", "takeout_box" },
|
||||
{ "into", "arrow_heading_down" },
|
||||
{ "year", "calendar" },
|
||||
{ "because", "woman_shrugging" },
|
||||
{ "hmm", "thinking" },
|
||||
{ "yo", "wave" },
|
||||
{ "hey", "wave" },
|
||||
{ "sup", "wave" },
|
||||
};
|
||||
|
||||
public EmojiProvider(GraphicsDevice gd)
|
||||
{
|
||||
Dict = new EmojiDictionary();
|
||||
Cache = new EmojiCache(gd);
|
||||
}
|
||||
|
||||
public string EmojiFromName(string name)
|
||||
{
|
||||
string result;
|
||||
if (Dict.NameToEmojis.TryGetValue(name, out result))
|
||||
return result;
|
||||
return null;
|
||||
}
|
||||
|
||||
private string StripPunctuation(string word, out string punctuation)
|
||||
{
|
||||
for (int i=word.Length-1; i>=0; i--)
|
||||
{
|
||||
if (!char.IsPunctuation(word[i]))
|
||||
{
|
||||
punctuation = word.Substring(i + 1);
|
||||
return word.Substring(0, i + 1);
|
||||
}
|
||||
}
|
||||
punctuation = "";
|
||||
return word;
|
||||
}
|
||||
|
||||
public string SearchForWordHit(string word)
|
||||
{
|
||||
string direct;
|
||||
if (TranslateShortcuts.TryGetValue(word, out direct))
|
||||
{
|
||||
return ":" + direct + ":";
|
||||
}
|
||||
|
||||
if (Dict.NameToEmojis.TryGetValue(word, out direct))
|
||||
{
|
||||
return ":" + word + ":";
|
||||
}
|
||||
|
||||
List<string> options;
|
||||
if (Dict.KeywordToCandidates.TryGetValue(word, out options))
|
||||
{
|
||||
return ":" + options[DictRand.Next(options.Count)] + ":";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string TranslateWordToEmoji(string word)
|
||||
{
|
||||
string punctuation;
|
||||
var lower = StripPunctuation(word.ToLowerInvariant(), out punctuation);
|
||||
string result;
|
||||
result = SearchForWordHit(lower);
|
||||
if (result != null) return result + ' ' + punctuation;
|
||||
if (lower.EndsWith("s"))
|
||||
{
|
||||
result = SearchForWordHit(lower.Substring(0, lower.Length-1));
|
||||
if (result != null) return result + ' ' + punctuation;
|
||||
}
|
||||
if (lower.EndsWith("ing"))
|
||||
{
|
||||
result = SearchForWordHit(lower.Substring(0, lower.Length - 3));
|
||||
if (result != null) return result + ' ' + punctuation;
|
||||
}
|
||||
return word.Substring(0, lower.Length) + punctuation;
|
||||
}
|
||||
|
||||
public Tuple<Texture2D, Rectangle> GetEmoji(string id)
|
||||
{
|
||||
var rect = Cache.GetEmoji(id);
|
||||
return new Tuple<Texture2D, Rectangle>(Cache.EmojiTex, rect);
|
||||
}
|
||||
|
||||
public string EmojiToBB(string input)
|
||||
{
|
||||
//search through the string for emojis to turn to BBcode
|
||||
int index = 0;
|
||||
int lastColon = -1;
|
||||
var result = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
var nColon = input.IndexOf(':', index);
|
||||
if (nColon == -1) break;
|
||||
if (lastColon == -1) result.Append(input.Substring(index, nColon - index)); //add up to the colon
|
||||
else
|
||||
{
|
||||
//is the string between the two colons an emoji?
|
||||
var emoji = EmojiFromName(input.Substring(lastColon + 1, nColon - (lastColon + 1)));
|
||||
if (emoji == null)
|
||||
{
|
||||
result.Append(":"+input.Substring(index, nColon - index)); //add up to the colon (include the last colon we skipped)
|
||||
} else
|
||||
{
|
||||
result.Append("[emoji=" + emoji + "] ");
|
||||
lastColon = -1;
|
||||
index = nColon + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
index = nColon + 1;
|
||||
lastColon = nColon;
|
||||
}
|
||||
result.Append(((lastColon == -1) ? "" : ":") + input.Substring(index));
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
public string EmojiTranslate(string input)
|
||||
{
|
||||
//search for replacement candidates for each word in input
|
||||
var words = input.Split(' ');
|
||||
|
||||
for (int i=0; i<words.Length; i++)
|
||||
{
|
||||
var word = words[i];
|
||||
if (word == "") continue;
|
||||
if (word.Length > 2 && word.StartsWith(":") && word.EndsWith(":"))
|
||||
{
|
||||
//is this already an emoji? if so, skip it
|
||||
var existing = EmojiFromName(word.Substring(1, word.Length-2));
|
||||
if (existing == null) continue;
|
||||
}
|
||||
words[i] = TranslateWordToEmoji(word);
|
||||
}
|
||||
return String.Join(" ", words);
|
||||
}
|
||||
|
||||
public string EmojiOnly(string input, int mode)
|
||||
{
|
||||
if (mode == 2) return EmojiTranslate(input);
|
||||
//search through the string for emojis to keep
|
||||
int index = 0;
|
||||
int lastColon = -1;
|
||||
var result = new StringBuilder();
|
||||
while (true)
|
||||
{
|
||||
var nColon = input.IndexOf(':', index);
|
||||
if (nColon == -1) break;
|
||||
else
|
||||
{
|
||||
//is the string between the two colons an emoji?
|
||||
var name = input.Substring(lastColon + 1, nColon - (lastColon + 1));
|
||||
var emoji = EmojiFromName(name);
|
||||
if (emoji == null)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Append(":" + name + ": ");
|
||||
lastColon = -1;
|
||||
index = nColon + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
index = nColon + 1;
|
||||
lastColon = nColon;
|
||||
}
|
||||
//result.Append(((lastColon == -1) ? "" : ":"));
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue