MSCO 2.9.1: fixes without MSCLoader, admin teleport, MSCO branding
- Own JSON reader (MiniJson) instead of Newtonsoft.Json - the server browser failed with "Could not load System.Runtime.Serialization" once MSCLoader was gone - Mouse cursor visible in admin menu/chat/console (PlayerInMenu) - Intro "Press any key" screen replaced by an MSCO loading screen; hook PlayMakerFSM.Awake too - Join links while the game runs: picked up from MSCO\join.txt (written by the launcher) - Admin menu: TELEPORT tab (home, shop, repair shop, inspection, villages, events, Satsuma) - Window title/icon "MSCO - My Summer Car Online", MSCO logo in the main menu - In-game UI restyled like the keymaster website (rounded cards, pills, glow, slim scrollbars) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+166
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace MSCO
|
||||
{
|
||||
/// <summary>
|
||||
/// Kleiner eigener JSON-Leser (ohne Newtonsoft.Json - das braucht System.Runtime.Serialization, das ohne MSCLoader im
|
||||
/// Spiel fehlt). Ergebnis: Dictionary<string, object> (Objekt, Schlüssel ohne Groß-/Kleinschreibung),
|
||||
/// List<object>, string, double, bool oder null.
|
||||
/// </summary>
|
||||
public static class MiniJson
|
||||
{
|
||||
public static object Parse(string json)
|
||||
{
|
||||
if (json == null) throw new FormatException("No JSON");
|
||||
int i = 0;
|
||||
object value = ReadValue(json, ref i);
|
||||
SkipWhitespace(json, ref i);
|
||||
if (i < json.Length) throw new FormatException("Unexpected text at " + i);
|
||||
return value;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Zugriff
|
||||
|
||||
public static string Str(Dictionary<string, object> o, string key, string fallback = null)
|
||||
{
|
||||
object v;
|
||||
if (o == null || !o.TryGetValue(key, out v) || v == null) return fallback;
|
||||
if (v is double) return ((double)v).ToString(CultureInfo.InvariantCulture);
|
||||
return v.ToString();
|
||||
}
|
||||
|
||||
public static int Int(Dictionary<string, object> o, string key, int fallback = 0)
|
||||
{
|
||||
object v;
|
||||
if (o == null || !o.TryGetValue(key, out v)) return fallback;
|
||||
if (v is double) return (int)(double)v;
|
||||
int parsed;
|
||||
return v is string && int.TryParse((string)v, NumberStyles.Integer, CultureInfo.InvariantCulture, out parsed) ? parsed : fallback;
|
||||
}
|
||||
|
||||
public static bool Bool(Dictionary<string, object> o, string key, bool fallback = false)
|
||||
{
|
||||
object v;
|
||||
if (o == null || !o.TryGetValue(key, out v)) return fallback;
|
||||
return v is bool ? (bool)v : fallback;
|
||||
}
|
||||
|
||||
public static List<string> Strings(Dictionary<string, object> o, string key)
|
||||
{
|
||||
var result = new List<string>();
|
||||
object v;
|
||||
if (o == null || !o.TryGetValue(key, out v)) return result;
|
||||
var list = v as List<object>;
|
||||
if (list != null) foreach (object item in list) if (item != null) result.Add(item.ToString());
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Lesen
|
||||
|
||||
static object ReadValue(string s, ref int i)
|
||||
{
|
||||
SkipWhitespace(s, ref i);
|
||||
if (i >= s.Length) throw new FormatException("Unexpected end of JSON");
|
||||
char c = s[i];
|
||||
if (c == '{') return ReadObject(s, ref i);
|
||||
if (c == '[') return ReadArray(s, ref i);
|
||||
if (c == '"') return ReadString(s, ref i);
|
||||
if (c == '-' || (c >= '0' && c <= '9')) return ReadNumber(s, ref i);
|
||||
if (Word(s, ref i, "true")) return true;
|
||||
if (Word(s, ref i, "false")) return false;
|
||||
if (Word(s, ref i, "null")) return null;
|
||||
throw new FormatException("Unexpected '" + c + "' at " + i);
|
||||
}
|
||||
|
||||
static Dictionary<string, object> ReadObject(string s, ref int i)
|
||||
{
|
||||
var o = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
i++; // {
|
||||
SkipWhitespace(s, ref i);
|
||||
if (i < s.Length && s[i] == '}') { i++; return o; }
|
||||
while (true)
|
||||
{
|
||||
SkipWhitespace(s, ref i);
|
||||
if (i >= s.Length || s[i] != '"') throw new FormatException("Expected a name at " + i);
|
||||
string key = ReadString(s, ref i);
|
||||
SkipWhitespace(s, ref i);
|
||||
if (i >= s.Length || s[i] != ':') throw new FormatException("Expected ':' at " + i);
|
||||
i++;
|
||||
o[key] = ReadValue(s, ref i);
|
||||
SkipWhitespace(s, ref i);
|
||||
if (i >= s.Length) throw new FormatException("Unexpected end of JSON");
|
||||
if (s[i] == ',') { i++; continue; }
|
||||
if (s[i] == '}') { i++; return o; }
|
||||
throw new FormatException("Expected ',' or '}' at " + i);
|
||||
}
|
||||
}
|
||||
|
||||
static List<object> ReadArray(string s, ref int i)
|
||||
{
|
||||
var list = new List<object>();
|
||||
i++; // [
|
||||
SkipWhitespace(s, ref i);
|
||||
if (i < s.Length && s[i] == ']') { i++; return list; }
|
||||
while (true)
|
||||
{
|
||||
list.Add(ReadValue(s, ref i));
|
||||
SkipWhitespace(s, ref i);
|
||||
if (i >= s.Length) throw new FormatException("Unexpected end of JSON");
|
||||
if (s[i] == ',') { i++; continue; }
|
||||
if (s[i] == ']') { i++; return list; }
|
||||
throw new FormatException("Expected ',' or ']' at " + i);
|
||||
}
|
||||
}
|
||||
|
||||
static string ReadString(string s, ref int i)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
i++; // "
|
||||
while (i < s.Length)
|
||||
{
|
||||
char c = s[i++];
|
||||
if (c == '"') return sb.ToString();
|
||||
if (c != '\\') { sb.Append(c); continue; }
|
||||
if (i >= s.Length) break;
|
||||
char e = s[i++];
|
||||
switch (e)
|
||||
{
|
||||
case 'b': sb.Append('\b'); break;
|
||||
case 'f': sb.Append('\f'); break;
|
||||
case 'n': sb.Append('\n'); break;
|
||||
case 'r': sb.Append('\r'); break;
|
||||
case 't': sb.Append('\t'); break;
|
||||
case 'u':
|
||||
if (i + 4 > s.Length) throw new FormatException("Bad \\u escape");
|
||||
sb.Append((char)int.Parse(s.Substring(i, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture));
|
||||
i += 4;
|
||||
break;
|
||||
default: sb.Append(e); break; // \" \\ \/
|
||||
}
|
||||
}
|
||||
throw new FormatException("Unterminated string");
|
||||
}
|
||||
|
||||
static double ReadNumber(string s, ref int i)
|
||||
{
|
||||
int start = i;
|
||||
while (i < s.Length && "+-0123456789.eE".IndexOf(s[i]) >= 0) i++;
|
||||
return double.Parse(s.Substring(start, i - start), NumberStyles.Float, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
static bool Word(string s, ref int i, string word)
|
||||
{
|
||||
if (string.CompareOrdinal(s, i, word, 0, word.Length) != 0) return false;
|
||||
i += word.Length;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SkipWhitespace(string s, ref int i)
|
||||
{
|
||||
while (i < s.Length && char.IsWhiteSpace(s[i])) i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user