Changeset 402 for binary-improvements2


Ignore:
Timestamp:
Jan 27, 2023, 7:28:00 PM (22 months ago)
Author:
alloc
Message:
  • Major refactoring
  • Using Utf8Json for (de)serialization
  • Moving APIs to REST
  • Removing dependencies from WebServer and MapRenderer to ServerFixes
Location:
binary-improvements2
Files:
4 added
5 deleted
56 edited
1 copied
15 moved

Legend:

Unmodified
Added
Removed
  • binary-improvements2/7dtd-binaries/README.txt

    r378 r402  
    22- Assembly-CSharp.dll
    33- Assembly-CSharp-firstpass.dll
     4- com.rlabrecque.steamworks.net.dll
    45- LogLibrary.dll
    56- mscorlib.dll
     
    910- UnityEngine.dll
    1011- UnityEngine.ImageConversionModule.dll
     12- Utf8Json.dll
  • binary-improvements2/7dtd-server-fixes/7dtd-server-fixes.csproj

    r392 r402  
    8989  <ItemGroup>
    9090    <Compile Include="src\AssemblyInfo.cs" />
    91     <Compile Include="src\FileCache\InvalidateCachesCmd.cs" />
    92     <Compile Include="src\JSON\JsonManualBuilder.cs" />
    93     <Compile Include="src\LiveData\Animals.cs" />
    94     <Compile Include="src\LiveData\Hostiles.cs" />
    9591    <Compile Include="src\PersistentData\PersistentContainer.cs" />
    9692    <Compile Include="src\PersistentData\InvItem.cs" />
     
    9894    <Compile Include="src\PersistentData\Players.cs" />
    9995    <Compile Include="src\PersistentData\Player.cs" />
    100     <Compile Include="src\JSON\JsonNode.cs" />
    101     <Compile Include="src\JSON\JsonArray.cs" />
    102     <Compile Include="src\JSON\JsonObject.cs" />
    103     <Compile Include="src\JSON\JsonNumber.cs" />
    104     <Compile Include="src\JSON\JsonString.cs" />
    105     <Compile Include="src\JSON\JsonBoolean.cs" />
    106     <Compile Include="src\JSON\Parser.cs" />
    107     <Compile Include="src\JSON\JsonNull.cs" />
    108     <Compile Include="src\JSON\MalformedJSONException.cs" />
    109     <Compile Include="src\FileCache\AbstractCache.cs" />
    110     <Compile Include="src\FileCache\DirectAccess.cs" />
    111     <Compile Include="src\FileCache\SimpleCache.cs" />
    112     <Compile Include="src\FileCache\MapTileCache.cs" />
    11396    <Compile Include="src\ModApi.cs" />
    114     <Compile Include="src\AllocsUtils.cs" />
    11597    <Compile Include="src\LandClaimList.cs" />
    11698    <Compile Include="src\PersistentData\Attributes.cs" />
    117     <Compile Include="src\JSON\JsonValue.cs" />
    118     <Compile Include="src\LiveData\EntityFilterList.cs" />
    11999  </ItemGroup>
    120100  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
     
    122102    <Folder Include="src\" />
    123103    <Folder Include="src\PersistentData\" />
    124     <Folder Include="src\FileCache\" />
    125104  </ItemGroup>
    126105  <ItemGroup>
  • binary-improvements2/7dtd-server-fixes/ModInfo.xml

    r391 r402  
    11<?xml version="1.0" encoding="UTF-8" ?>
    22<xml>
    3         <ModInfo>
    4                 <Name value="Server extensions" />
    5                 <Description value="Common functions" />
    6                 <Author value="The Fun Pimps LLC" />
    7                 <Version value="1" />
    8                 <Website value="" />
    9         </ModInfo>
     3        <Name value="TFP_ServerExtensions" />
     4        <DisplayName value="Server Extensions (base)" />
     5        <Description value="Common functions for other mods" />
     6        <Author value="The Fun Pimps LLC" />
     7        <Version value="21.0" />
     8        <Website value="" />
    109</xml>
  • binary-improvements2/7dtd-server-fixes/src/ModApi.cs

    r391 r402  
    3030                        }
    3131
    32                         Log.Out ("Player connected" +
    33                                  ", entityid=" + _cInfo.entityId +
    34                                  ", name=" + _cInfo.playerName +
    35                                  ", pltfmid=" + (_cInfo.PlatformId?.CombinedString ?? "<unknown>") +
    36                                  ", crossid=" + (_cInfo.CrossplatformId?.CombinedString ?? "<unknown/none>") +
    37                                  ", steamOwner=" + (owner ?? "<unknown/none>") +
    38                                  ", ip=" + _cInfo.ip
     32                        Log.Out (
     33                                $"Player connected, entityid={_cInfo.entityId}, name={_cInfo.playerName}, pltfmid={_cInfo.PlatformId?.CombinedString ?? "<unknown>"}, crossid={_cInfo.CrossplatformId?.CombinedString ?? "<unknown/none>"}, steamOwner={owner ?? "<unknown/none>"}, ip={_cInfo.ip}"
    3934                        );
    4035                }
     
    6661
    6762                        if (_cInfo != null) {
    68                                 Log.Out ("Sent chat hook reply to {0}", _cInfo.InternalId);
     63                                Log.Out ($"Sent chat hook reply to {_cInfo.InternalId}");
    6964                                _cInfo.SendPackage (NetPackageManager.GetPackage<NetPackageChat> ().Setup (EChatType.Whisper, -1, testChatAnswer, "", false, null));
    7065                        } else {
    71                                 Log.Error ("ChatHookExample: Argument _cInfo null on message: {0}", _msg);
     66                                Log.Error ($"ChatHookExample: Argument _cInfo null on message: {_msg}");
    7267                        }
    7368
  • binary-improvements2/7dtd-server-fixes/src/PersistentData/Inventory.cs

    r351 r402  
    6767
    6868                        if (_count > maxAllowed) {
    69                                 Log.Out ("Player with ID " + _playerId + " has stack for \"" + name + "\" greater than allowed (" +
    70                                          _count + " > " + maxAllowed + ")");
     69                                Log.Out ($"Player with ID {_playerId} has stack for \"{name}\" greater than allowed ({_count} > {maxAllowed})");
    7170                        }
    7271
     
    8079                        item.icon = itemClass.GetIconName ();
    8180
    82                         item.iconcolor = AllocsUtils.ColorToHex (itemClass.GetIconTint ());
     81                        item.iconcolor = itemClass.GetIconTint ().ToHexCode ();
    8382
    8483                        return item;
  • binary-improvements2/7dtd-server-fixes/src/PersistentData/PersistentContainer.cs

    r391 r402  
    2222
    2323                public void Save () {
    24                         Stream stream = File.Open (GameIO.GetSaveGameDir () + "/AllocsPeristentData.bin", FileMode.Create);
     24                        Stream stream = File.Open ($"{GameIO.GetSaveGameDir ()}/AllocsPeristentData.bin", FileMode.Create);
    2525                        BinaryFormatter bFormatter = new BinaryFormatter ();
    2626                        bFormatter.Serialize (stream, this);
     
    2929
    3030                public static bool Load () {
    31                         if (!File.Exists (GameIO.GetSaveGameDir () + "/AllocsPeristentData.bin")) {
     31                        if (!File.Exists ($"{GameIO.GetSaveGameDir ()}/AllocsPeristentData.bin")) {
    3232                                return false;
    3333                        }
    3434
    3535                        try {
    36                                 Stream stream = File.Open (GameIO.GetSaveGameDir () + "/AllocsPeristentData.bin", FileMode.Open);
     36                                Stream stream = File.Open ($"{GameIO.GetSaveGameDir ()}/AllocsPeristentData.bin", FileMode.Open);
    3737                                BinaryFormatter bFormatter = new BinaryFormatter ();
    3838                                PersistentContainer obj = (PersistentContainer) bFormatter.Deserialize (stream);
  • binary-improvements2/7dtd-server-fixes/src/PersistentData/Player.cs

    r369 r402  
    117117                        }
    118118
    119                         Log.Out ("Player set to offline: " + platformId);
     119                        Log.Out ($"Player set to offline: {platformId}");
    120120                        lastOnline = DateTime.Now;
    121121                        try {
     
    133133
    134134                public void SetOnline (ClientInfo _ci) {
    135                         Log.Out ("Player set to online: " + platformId);
     135                        Log.Out ($"Player set to online: {platformId}");
    136136                        clientInfo = _ci;
    137137            entityId = _ci.entityId;
  • binary-improvements2/7dtd-server-fixes/src/PersistentData/Players.cs

    r391 r402  
    2222                                }
    2323
    24                                 Log.Out ("Created new player entry for ID: " + _platformId);
     24                                Log.Out ($"Created new player entry for ID: {_platformId}");
    2525                                Player p = new Player (_platformId);
    2626                                Dict.Add (_platformId, p);
  • binary-improvements2/CommandExtensions/CommandExtensions.csproj

    r392 r402  
    6767  </ItemGroup>
    6868  <ItemGroup>
     69    <Compile Include="src\Commands\TestLogSpam.cs" />
    6970    <Compile Include="src\ModApi.cs" />
    7071    <Compile Include="src\AssemblyInfo.cs" />
  • binary-improvements2/CommandExtensions/ModInfo.xml

    r391 r402  
    11<?xml version="1.0" encoding="UTF-8" ?>
    22<xml>
    3         <ModInfo>
    4                 <Name value="Command extensions" />
    5                 <Description value="Additional commands for server operation" />
    6                 <Author value="The Fun Pimps LLC" />
    7                 <Version value="1" />
    8                 <Website value="" />
    9         </ModInfo>
     3        <Name value="TFP_CommandExtensions" />
     4        <DisplayName value="Server Command Extensions" />
     5        <Description value="Additional commands for server operation" />
     6        <Author value="The Fun Pimps LLC" />
     7        <Version value="21.0" />
     8        <Website value="" />
    109</xml>
  • binary-improvements2/CommandExtensions/src/ChatHelpers.cs

    r391 r402  
    1010                        }
    1111
    12                         _receiver.SendPackage (NetPackageManager.GetPackage<NetPackageChat> ().Setup (EChatType.Whisper, -1, _message, senderName + " (PM)", false, null));
     12                        _receiver.SendPackage (NetPackageManager.GetPackage<NetPackageChat> ().Setup (EChatType.Whisper, -1, _message,
     13                                $"{senderName} (PM)", false, null));
    1314                        string receiverName = _receiver.playerName;
    14                         SdtdConsole.Instance.Output (
    15                                 $"Message to player {(receiverName != null ? "\"" + receiverName + "\"" : "unknownName")} sent with sender \"{senderName}\"");
     15                        receiverName = receiverName != null ? $"\"{receiverName}\"" : "unknownName";
     16                        SdtdConsole.Instance.Output ($"Message to player {receiverName} sent with sender \"{senderName}\"");
    1617                }
    1718        }
  • binary-improvements2/CommandExtensions/src/Commands/Give.cs

    r391 r402  
    2727                public override void Execute (List<string> _params, CommandSenderInfo _senderInfo) {
    2828                        if (_params.Count != 3 && _params.Count != 4) {
    29                                 SdtdConsole.Instance.Output ("Wrong number of arguments, expected 3 or 4, found " + _params.Count +
    30                                                              ".");
     29                                SdtdConsole.Instance.Output ($"Wrong number of arguments, expected 3 or 4, found {_params.Count}.");
    3130                                return;
    3231                        }
  • binary-improvements2/CommandExtensions/src/Commands/ListItems.cs

    r391 r402  
    3939                                }
    4040
    41                                 SdtdConsole.Instance.Output ("    " + s);
     41                                SdtdConsole.Instance.Output ($"    {s}");
    4242                                listed++;
    4343                        }
    4444
    45                         SdtdConsole.Instance.Output ("Listed " + listed + " matching items.");
     45                        SdtdConsole.Instance.Output ($"Listed {listed} matching items.");
    4646                }
    4747        }
  • binary-improvements2/CommandExtensions/src/Commands/ListLandProtection.cs

    r391 r402  
    6060                                                userIdFilter = ci.InternalId;
    6161                                        } else {
    62                                                 SdtdConsole.Instance.Output ("Player name or entity id \"" + _params [0] + "\" not found.");
     62                                                SdtdConsole.Instance.Output ($"Player name or entity id \"{_params [0]}\" not found.");
    6363                                                return;
    6464                                        }
     
    8282                                        } catch (Exception e) {
    8383                                                SdtdConsole.Instance.Output ("Error getting current player's position");
    84                                                 Log.Out ("Error in ListLandProtection.Run: " + e);
     84                                                Log.Out ($"Error in ListLandProtection.Run: {e}");
    8585                                                return;
    8686                                        }
     
    114114                                foreach (Vector3i v in claimPositions) {
    115115                                        if (parseableOutput) {
    116                                                 SdtdConsole.Instance.Output ("LandProtectionOf: id=" + claimOwner.PlatformId +
    117                                                                              ", playerName=" + claimOwner.Name + ", location=" + v);
     116                                                SdtdConsole.Instance.Output (
     117                                                        $"LandProtectionOf: id={claimOwner.PlatformId}, playerName={claimOwner.Name}, location={v}");
    118118                                        } else {
    119                                                 SdtdConsole.Instance.Output ("   (" + v + ")");
     119                                                SdtdConsole.Instance.Output ($"   ({v})");
    120120                                        }
    121121                                }
     
    123123
    124124                        if (userIdFilter == null) {
    125                                 SdtdConsole.Instance.Output ("Total of " + ppl.m_lpBlockMap.Count + " keystones in the game");
     125                                SdtdConsole.Instance.Output ($"Total of {ppl.m_lpBlockMap.Count} keystones in the game");
    126126                        }
    127127                }
  • binary-improvements2/CommandExtensions/src/Commands/RemoveLandProtection.cs

    r391 r402  
    5050                                GameManager.Instance.SetBlocksRPC (changes);
    5151
    52                                 SdtdConsole.Instance.Output ("Tried to remove #" + changes.Count +
    53                                                              " land protection blocks for player \"" + _id + "\". Note " +
    54                                                              "that only blocks in chunks that are currently loaded (close to any player) could be removed. " +
    55                                                              "Please check for remaining blocks by running:");
    56                                 SdtdConsole.Instance.Output ("  listlandprotection " + _id);
     52                                SdtdConsole.Instance.Output (
     53                                        $"Tried to remove #{changes.Count} land protection blocks for player \"{_id}\". Note that only blocks in chunks that are currently loaded (close to any player) could be removed. Please check for remaining blocks by running:");
     54                                SdtdConsole.Instance.Output ($"  listlandprotection {_id}");
    5755                        } catch (Exception e) {
    58                                 Log.Out ("Error in RemoveLandProtection.removeById: " + e);
     56                                Log.Out ($"Error in RemoveLandProtection.removeById: {e}");
    5957                        }
    6058                }
     
    8785                        GameManager.Instance.SetBlocksRPC (changes);
    8886
    89                         SdtdConsole.Instance.Output ("Land protection block at (" + v + ") removed");
     87                        SdtdConsole.Instance.Output ($"Land protection block at ({v}) removed");
    9088                }
    9189
     
    128126                                        } catch (Exception e) {
    129127                                                SdtdConsole.Instance.Output ("Error removing claims");
    130                                                 Log.Out ("Error in RemoveLandProtection.Run: " + e);
     128                                                Log.Out ($"Error in RemoveLandProtection.Run: {e}");
    131129                                        }
    132130                                } catch (Exception e) {
    133131                                        SdtdConsole.Instance.Output ("Error getting current player's position");
    134                                         Log.Out ("Error in RemoveLandProtection.Run: " + e);
     132                                        Log.Out ($"Error in RemoveLandProtection.Run: {e}");
    135133                                }
    136134                        } else if (_params.Count == 1) {
  • binary-improvements2/CommandExtensions/src/Commands/ShowInventory.cs

    r391 r402  
    4747
    4848                        if (tag == null) {
    49                                 SdtdConsole.Instance.Output ("Belt of player " + p.Name + ":");
     49                                SdtdConsole.Instance.Output ($"Belt of player {p.Name}:");
    5050                        }
    5151
     
    5656
    5757                        if (tag == null) {
    58                                 SdtdConsole.Instance.Output ("Bagpack of player " + p.Name + ":");
     58                                SdtdConsole.Instance.Output ($"Bagpack of player {p.Name}:");
    5959                        }
    6060
     
    6565
    6666                        if (tag == null) {
    67                                 SdtdConsole.Instance.Output ("Equipment of player " + p.Name + ":");
     67                                SdtdConsole.Instance.Output ($"Equipment of player {p.Name}:");
    6868                        }
    6969
     
    7171
    7272                        if (tag != null) {
    73                                 SdtdConsole.Instance.Output ("tracker_item id=" + p.EntityID + ", tag=" + tag +
    74                                                              ", SHOWINVENTORY DONE");
     73                                SdtdConsole.Instance.Output ($"tracker_item id={p.EntityID}, tag={tag}, SHOWINVENTORY DONE");
    7574                        }
    7675                }
     
    9493                                        // Tag defined -> parseable output
    9594                                        string partsMsg = DoParts (_inv [i].parts, 1, "");
    96                                         string msg = "tracker_item id=" + _entityId + ", tag=" + _tag + ", location=" + _location +
    97                                                      ", slot=" + i + ", item=" + _inv [i].itemName + ", qnty=" + _inv [i].count +
    98                                                      ", quality=" + _inv [i].quality + ", parts=(" + partsMsg + ")";
     95                                        string msg =
     96                                                $"tracker_item id={_entityId}, tag={_tag}, location={_location}, slot={i}, item={_inv [i].itemName}, qnty={_inv [i].count}, quality={_inv [i].quality}, parts=({partsMsg})";
    9997                                        SdtdConsole.Instance.Output (msg);
    10098                                }
     
    140138                                        // Tag defined -> parseable output
    141139                                        string partsMsg = DoParts (_items [slotindices [i]].parts, 1, "");
    142                                         string msg = "tracker_item id=" + _entityId + ", tag=" + _tag + ", location=" + _location +
    143                                                      ", slot=" + _slotname + ", item=" + item.itemName + ", qnty=1, quality=" +
    144                                                      item.quality + ", parts=(" + partsMsg + ")";
     140                                        string msg =
     141                                                $"tracker_item id={_entityId}, tag={_tag}, location={_location}, slot={_slotname}, item={item.itemName}, qnty=1, quality={item.quality}, parts=({partsMsg})";
    145142                                        SdtdConsole.Instance.Output (msg);
    146143                                }
     
    176173                                        }
    177174
    178                                         _currentMessage += _parts [i].itemName + "@" + _parts [i].quality;
     175                                        _currentMessage += $"{_parts [i].itemName}@{_parts [i].quality}";
    179176                                        _currentMessage = DoParts (_parts [i].parts, _indent + 1, _currentMessage);
    180177                                }
  • binary-improvements2/MapRendering/MapRendering.csproj

    r392 r402  
    8383      <Private>False</Private>
    8484    </Reference>
     85    <Reference Include="Utf8Json, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
     86      <HintPath>..\7dtd-binaries\Utf8Json.dll</HintPath>
     87      <Private>False</Private>
     88    </Reference>
    8589  </ItemGroup>
    8690  <ItemGroup>
     
    8892    <Compile Include="src\MapRenderBlockBuffer.cs" />
    8993    <Compile Include="src\MapRenderer.cs" />
     94    <Compile Include="src\MapTileCache.cs" />
    9095    <Compile Include="src\ModApi.cs" />
    9196    <Compile Include="src\AssemblyInfo.cs" />
     
    95100  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
    96101  <ItemGroup>
    97     <ProjectReference Include="..\7dtd-server-fixes\7dtd-server-fixes.csproj">
    98       <Project>{81DA7F87-1A66-4920-AADA-6EAF1971F8D0}</Project>
    99       <Name>7dtd-server-fixes</Name>
    100       <Private>False</Private>
    101     </ProjectReference>
    102   </ItemGroup>
    103   <ItemGroup>
    104102    <None Include="ModInfo.xml">
    105103      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    106104    </None>
    107105  </ItemGroup>
     106  <ItemGroup>
     107    <ProjectReference Include="..\WebServer\WebServer.csproj">
     108      <Project>{01b5f981-b9fd-4364-8f9e-9127130d2542}</Project>
     109      <Name>WebServer</Name>
     110      <Private>False</Private>
     111    </ProjectReference>
     112  </ItemGroup>
    108113</Project>
  • binary-improvements2/MapRendering/ModInfo.xml

    r391 r402  
    11<?xml version="1.0" encoding="UTF-8" ?>
    22<xml>
    3         <ModInfo>
    4                 <Name value="TFP_MapRendering" />
    5                 <Description value="Render the game map to image map tiles as it is uncovered" />
    6                 <Author value="The Fun Pimps LLC" />
    7                 <Version value="1" />
    8                 <Website value="" />
    9         </ModInfo>
     3        <Name value="TFP_MapRendering" />
     4        <DisplayName value="Map Renderer" />
     5        <Description value="Render the game map to image map tiles as it is uncovered" />
     6        <Author value="The Fun Pimps LLC" />
     7        <Version value="21.0" />
     8        <Website value="" />
    109</xml>
  • binary-improvements2/MapRendering/src/Commands/EnableRendering.cs

    r391 r402  
    1515                public override void Execute (List<string> _params, CommandSenderInfo _senderInfo) {
    1616                        if (_params.Count != 1) {
    17                                 SdtdConsole.Instance.Output ("Current state: " + MapRenderer.renderingEnabled);
     17                                SdtdConsole.Instance.Output ($"Current state: {MapRenderer.renderingEnabled}");
    1818                                return;
    1919                        }
    2020
    2121                        MapRenderer.renderingEnabled = _params [0].Equals ("1");
    22                         SdtdConsole.Instance.Output ("Set live map rendering to " + _params [0].Equals ("1"));
     22                        SdtdConsole.Instance.Output ($"Set live map rendering to {_params [0].Equals ("1")}");
    2323                }
    2424        }
  • binary-improvements2/MapRendering/src/MapRenderBlockBuffer.cs

    r391 r402  
    11using System;
    22using System.IO;
    3 using AllocsFixes.FileCache;
    43using Unity.Collections;
    54using UnityEngine;
     
    2120                        zoomLevel = _level;
    2221                        cache = _cache;
    23                         folderBase = Constants.MapDirectory + "/" + zoomLevel + "/";
     22                        folderBase = $"{Constants.MapDirectory}/{zoomLevel}/";
    2423
    2524                        {
     
    5251                                saveTextureToFile ();
    5352                        } catch (Exception e) {
    54                                 Log.Warning ("Exception in MapRenderBlockBuffer.SaveBlock(): " + e);
     53                                Log.Warning ($"Exception in MapRenderBlockBuffer.SaveBlock(): {e}");
    5554                        }
    5655                        Profiler.EndSample ();
     
    6463                                        string folder;
    6564                                        if (currentBlockMapPos.x != _block.x) {
    66                                                 folder = folderBase + _block.x + '/';
     65                                                folder = $"{folderBase}{_block.x}/";
    6766
    6867                                                Profiler.BeginSample ("LoadBlock.Directory");
     
    7372                                        }
    7473
    75                                         string fileName = folder + _block.y + ".png";
     74                                        string fileName = $"{folder}{_block.y}.png";
    7675                                        Profiler.EndSample ();
    7776                                       
     
    105104                public Color32[] GetHalfScaled () {
    106105                        Profiler.BeginSample ("HalfScaled.ResizeBuffer");
    107                         zoomBuffer.Resize (Constants.MapBlockSize, Constants.MapBlockSize);
     106                        zoomBuffer.Reinitialize (Constants.MapBlockSize, Constants.MapBlockSize);
    108107                        Profiler.EndSample ();
    109108
     
    156155                        Profiler.BeginSample ("HalfScaledNative.ResizeBuffer");
    157156                        if (zoomBuffer.format != blockMap.format || zoomBuffer.height != Constants.MapBlockSize / 2 || zoomBuffer.width != Constants.MapBlockSize / 2) {
    158                                 zoomBuffer.Resize (Constants.MapBlockSize / 2, Constants.MapBlockSize / 2, blockMap.format, false);
     157                                zoomBuffer.Reinitialize (Constants.MapBlockSize / 2, Constants.MapBlockSize / 2, blockMap.format, false);
    159158                        }
    160159                        Profiler.EndSample ();
     
    206205
    207206                        if (array != null) {
    208                                 Log.Error ("Map image tile " + _fileName + " has been corrupted, recreating tile");
     207                                Log.Error ($"Map image tile {_fileName} has been corrupted, recreating tile");
    209208                        }
    210209
    211210                        if (blockMap.format != Constants.DefaultTextureFormat || blockMap.height != Constants.MapBlockSize ||
    212211                            blockMap.width != Constants.MapBlockSize) {
    213                                 blockMap.Resize (Constants.MapBlockSize, Constants.MapBlockSize, Constants.DefaultTextureFormat,
     212                                blockMap.Reinitialize (Constants.MapBlockSize, Constants.MapBlockSize, Constants.DefaultTextureFormat,
    214213                                        false);
    215214                        }
  • binary-improvements2/MapRendering/src/MapRenderer.cs

    r391 r402  
    55using System.Text;
    66using System.Threading;
    7 using AllocsFixes.FileCache;
    8 using AllocsFixes.JSON;
    97using UnityEngine;
    108using UnityEngine.Profiling;
     9using Utf8Json;
     10using Webserver.FileCache;
    1111using Object = UnityEngine.Object;
    1212
     
    2727
    2828                private MapRenderer () {
    29                         Constants.MapDirectory = GameIO.GetSaveGameDir () + "/map";
    30 
    31                         lock (lockObject) {
    32                                 if (!LoadMapInfo ()) {
    33                                         WriteMapInfo ();
    34                                 }
     29                        Constants.MapDirectory = $"{GameIO.GetSaveGameDir ()}/map";
     30
     31                        if (!LoadMapInfo ()) {
     32                                WriteMapInfo ();
    3533                        }
    3634
     
    4745                public static MapRenderer Instance => instance ??= new MapRenderer ();
    4846
    49                 public static MapTileCache GetTileCache () {
     47                public static AbstractCache GetTileCache () {
    5048                        return Instance.cache;
    5149                }
     
    9593                                                }
    9694                                        } catch (Exception e) {
    97                                                 Log.Out ("Exception in MapRendering.RenderSingleChunk(): " + e);
     95                                                Log.Out ($"Exception in MapRendering.RenderSingleChunk(): {e}");
    9896                                        }
    9997                                }, _chunk);
     
    161159                                                        }
    162160                                                } catch (Exception e) {
    163                                                         Log.Out ("Exception: " + e);
     161                                                        Log.Out ($"Exception: {e}");
    164162                                                }
    165163                                        }
     
    177175                        if (fullMapTexture != null) {
    178176                                byte[] array = fullMapTexture.EncodeToPNG ();
    179                                 File.WriteAllBytes (Constants.MapDirectory + "/map.png", array);
     177                                File.WriteAllBytes ($"{Constants.MapDirectory}/map.png", array);
    180178                                Object.Destroy (fullMapTexture);
    181179                        }
     
    183181                        renderingFullMap = false;
    184182
    185                         Log.Out ("Generating map took: " + microStopwatch.ElapsedMilliseconds + " ms");
    186                         Log.Out ("World extent: " + minPos + " - " + maxPos);
     183                        Log.Out ($"Generating map took: {microStopwatch.ElapsedMilliseconds} ms");
     184                        Log.Out ($"World extent: {minPos} - {maxPos}");
    187185                }
    188186
     
    307305
    308306                private void WriteMapInfo () {
    309                         JsonObject mapInfo = new JsonObject ();
    310                         mapInfo.Add ("blockSize", new JsonNumber (Constants.MapBlockSize));
    311                         mapInfo.Add ("maxZoom", new JsonNumber (Constants.Zoomlevels - 1));
     307                        JsonWriter writer = new JsonWriter ();
     308                        writer.WriteBeginObject ();
     309                       
     310                        writer.WriteString ("blockSize");
     311                        writer.WriteNameSeparator ();
     312                        writer.WriteInt32 (Constants.MapBlockSize);
     313                       
     314                        writer.WriteValueSeparator ();
     315                        writer.WriteString ("maxZoom");
     316                        writer.WriteNameSeparator ();
     317                        writer.WriteInt32 (Constants.Zoomlevels - 1);
     318                       
     319                        writer.WriteEndObject ();
    312320
    313321                        Directory.CreateDirectory (Constants.MapDirectory);
    314                         File.WriteAllText (Constants.MapDirectory + "/mapinfo.json", mapInfo.ToString (), Encoding.UTF8);
     322                        File.WriteAllBytes ($"{Constants.MapDirectory}/mapinfo.json", writer.ToUtf8ByteArray ());
    315323                }
    316324
    317325                private bool LoadMapInfo () {
    318                         if (!File.Exists (Constants.MapDirectory + "/mapinfo.json")) {
     326                        if (!File.Exists ($"{Constants.MapDirectory}/mapinfo.json")) {
    319327                                return false;
    320328                        }
    321329
    322                         string json = File.ReadAllText (Constants.MapDirectory + "/mapinfo.json", Encoding.UTF8);
     330                        string json = File.ReadAllText ($"{Constants.MapDirectory}/mapinfo.json", Encoding.UTF8);
    323331                        try {
    324                                 JsonNode node = Parser.Parse (json);
    325                                 if (node is JsonObject jo) {
    326                                         if (jo.ContainsKey ("blockSize")) {
    327                                                 Constants.MapBlockSize = ((JsonNumber) jo ["blockSize"]).GetInt ();
    328                                         }
    329 
    330                                         if (jo.ContainsKey ("maxZoom")) {
    331                                                 Constants.Zoomlevels = ((JsonNumber) jo ["maxZoom"]).GetInt () + 1;
    332                                         }
    333 
    334                                         return true;
    335                                 }
    336                         } catch (MalformedJsonException e) {
    337                                 Log.Out ("Exception in LoadMapInfo: " + e);
    338                         } catch (InvalidCastException e) {
    339                                 Log.Out ("Exception in LoadMapInfo: " + e);
     332                                IDictionary<string,object> inputJson = JsonSerializer.Deserialize<IDictionary<string, object>> (json);
     333
     334                                if (inputJson.TryGetValue ("blockSize", out object fieldNode) && fieldNode is double value) {
     335                                        Constants.MapBlockSize = (int)value;
     336                                }
     337
     338                                if (inputJson.TryGetValue ("maxZoom", out fieldNode) && fieldNode is double value2) {
     339                                        Constants.Zoomlevels = (int)value2 + 1;
     340                                }
     341
     342                                return true;
     343                        } catch (Exception e) {
     344                                Log.Out ($"Exception in LoadMapInfo: {e}");
    340345                        }
    341346
  • binary-improvements2/MapRendering/src/MapTileCache.cs

    r399 r402  
    11using System;
     2using System.Diagnostics.CodeAnalysis;
    23using System.IO;
    34using UnityEngine;
    45using UnityEngine.Profiling;
     6using Webserver.FileCache;
    57using Object = UnityEngine.Object;
    68
    7 namespace AllocsFixes.FileCache {
     9namespace MapRendering {
    810        // Special "cache" for map tile folder as both map rendering and webserver access files in there.
    911        // Only map rendering tiles are cached. Writing is done by WriteThrough.
     
    2527                }
    2628
     29                // SetZoomCount only called before processing happens in MapRenderer.ctor, no locking required
     30                [SuppressMessage ("ReSharper", "InconsistentlySynchronizedField")]
    2731                public void SetZoomCount (int _count) {
    2832                        cache = new CurrentZoomFile[_count];
     
    5559                                }
    5660                        } catch (Exception e) {
    57                                 Log.Warning ("Error in MapTileCache.LoadTile: " + e);
     61                                Log.Warning ($"Error in MapTileCache.LoadTile: {e}");
    5862                        }
    5963
     
    8185                                }
    8286                        } catch (Exception e) {
    83                                 Log.Warning ("Error in MapTileCache.SaveTile: " + e);
     87                                Log.Warning ($"Error in MapTileCache.SaveTile: {e}");
    8488                        }
    8589                }
     
    9296                                }
    9397                        } catch (Exception e) {
    94                                 Log.Warning ("Error in MapTileCache.ResetTile: " + e);
     98                                Log.Warning ($"Error in MapTileCache.ResetTile: {e}");
    9599                        }
    96100                }
     
    108112                                }
    109113                        } catch (Exception e) {
    110                                 Log.Warning ("Error in MapTileCache.GetFileContent: " + e);
     114                                Log.Warning ($"Error in MapTileCache.GetFileContent: {e}");
    111115                        }
    112116
     
    119123
    120124                private static byte[] ReadAllBytes (string _path) {
    121                         using (FileStream fileStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096)) {
    122                                 int bytesRead = 0;
    123                                 int bytesLeft = (int) fileStream.Length;
    124                                 byte[] result = new byte[bytesLeft];
    125                                 while (bytesLeft > 0) {
    126                                         int readThisTime = fileStream.Read (result, bytesRead, bytesLeft);
    127                                         if (readThisTime == 0) {
    128                                                 throw new IOException ("Unexpected end of stream");
    129                                         }
    130 
    131                                         bytesRead += readThisTime;
    132                                         bytesLeft -= readThisTime;
     125                        using FileStream fileStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096);
     126                       
     127                        int bytesRead = 0;
     128                        int bytesLeft = (int) fileStream.Length;
     129                        byte[] result = new byte[bytesLeft];
     130                        while (bytesLeft > 0) {
     131                                int readThisTime = fileStream.Read (result, bytesRead, bytesLeft);
     132                                if (readThisTime == 0) {
     133                                        throw new IOException ("Unexpected end of stream");
    133134                                }
    134135
    135                                 return result;
     136                                bytesRead += readThisTime;
     137                                bytesLeft -= readThisTime;
    136138                        }
     139
     140                        return result;
    137141                }
    138142
  • binary-improvements2/MapRendering/src/ModApi.cs

    r391 r402  
    11using JetBrains.Annotations;
     2using Webserver;
     3using Webserver.UrlHandlers;
    24
    35namespace MapRendering {
     
    79                        ModEvents.GameShutdown.RegisterHandler (GameShutdown);
    810                        ModEvents.CalcChunkColorsDone.RegisterHandler (CalcChunkColorsDone);
     11
     12                        Web.ServerInitialized += _web => {
     13                                _web.RegisterPathHandler ("/map/", new StaticHandler (
     14                                        $"{GameIO.GetSaveGameDir ()}/map",
     15                                        MapRenderer.GetTileCache (),
     16                                        false,
     17                                        "web.map")
     18                                );
     19                        };
    920                }
    1021
  • binary-improvements2/MarkersMod/MarkersMod.csproj

    r392 r402  
    5959      <Private>False</Private>
    6060    </Reference>
     61    <Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
     62      <HintPath>..\7dtd-binaries\UnityEngine.CoreModule.dll</HintPath>
     63      <Private>False</Private>
     64    </Reference>
     65    <Reference Include="Utf8Json, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
     66      <HintPath>..\7dtd-binaries\Utf8Json.dll</HintPath>
     67      <Private>False</Private>
     68    </Reference>
    6169  </ItemGroup>
    6270  <ItemGroup>
     
    7280  </ItemGroup>
    7381  <ItemGroup>
    74     <ProjectReference Include="..\7dtd-server-fixes\7dtd-server-fixes.csproj">
    75       <Project>{81da7f87-1a66-4920-aada-6eaf1971f8d0}</Project>
    76       <Name>7dtd-server-fixes</Name>
    77       <Private>False</Private>
    78     </ProjectReference>
    7982    <ProjectReference Include="..\WebServer\WebServer.csproj">
    8083      <Project>{01b5f981-b9fd-4364-8f9e-9127130d2542}</Project>
  • binary-improvements2/MarkersMod/ModInfo.xml

    r390 r402  
    11<?xml version="1.0" encoding="UTF-8" ?>
    22<xml>
    3         <ModInfo>
    4                 <Name value="Markers" />
    5                 <Description value="Allows placing custom markers on the web map" />
    6                 <Author value="Catalysm and Alloc" />
    7                 <Version value="1" />
    8                 <Website value="" />
    9         </ModInfo>
     3        <Name value="TFP_MarkersExample" />
     4        <DisplayName value="Markers (Example Web Mod)" />
     5        <Description value="Allows placing custom markers on the web map" />
     6        <Author value="Catalysm and Alloc" />
     7        <Version value="21.0" />
     8        <Website value="" />
    109</xml>
  • binary-improvements2/MarkersMod/src/Markers.cs

    r391 r402  
    11using System.Collections.Generic;
    22using System.Net;
    3 using AllocsFixes.JSON;
     3using JetBrains.Annotations;
     4using Utf8Json;
    45using Webserver;
    56using Webserver.WebAPI;
    67
    78namespace Examples {
     9        [UsedImplicitly]
    810        public class Markers : AbsRestApi {
    911                private const int numRandomMarkers = 5;
     
    1113                private readonly Dictionary<string, (int, int)> markers = new Dictionary<string, (int, int)> ();
    1214
    13                 private static readonly JsonArray emptyResult = new JsonArray ();
    14                
    1515                public Markers () {
    1616                        GameRandom random = GameRandomManager.Instance.CreateGameRandom ();
     
    2424                }
    2525
     26                private static readonly byte[] jsonKeyId = JsonWriter.GetEncodedPropertyNameWithBeginObject ("id");
     27                private static readonly byte[] jsonKeyLat = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("lat");
     28                private static readonly byte[] jsonKeyLng = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("lng");
     29
    2630                protected override void HandleRestGet (RequestContext _context) {
    2731                        string id = _context.RequestPath;
    2832                       
     33                        PrepareEnvelopedResult (out JsonWriter writer);
     34                       
    2935                        if (string.IsNullOrEmpty (id)) {
    30                                 JsonArray result = new JsonArray ();
     36                                writer.WriteBeginArray ();
    3137
     38                                bool first = true;
    3239                                foreach ((string markerId, (int, int) coordinates) in markers) {
    33                                         JsonObject marker = new JsonObject ();
    34                                         marker.Add ("id", new JsonString (markerId));
    35                                         marker.Add ("lat", new JsonNumber (coordinates.Item1));
    36                                         marker.Add ("lng", new JsonNumber (coordinates.Item2));
    37                                         result.Add (marker);
     40                                        if (!first) {
     41                                                writer.WriteValueSeparator ();
     42                                        }
     43                                       
     44                                        first = false;
     45                                       
     46                                        writeMarkerJson (ref writer, markerId, coordinates);
    3847                                }
    39                                
    40                                 SendEnvelopedResult (_context, result);
     48
     49                                writer.WriteEndArray ();
     50                                SendEnvelopedResult (_context, ref writer);
    4151                                return;
    4252                        }
    4353
    4454                        if (!markers.TryGetValue (id, out (int, int) location)) {
    45                                 SendEnvelopedResult (_context, emptyResult, HttpStatusCode.NotFound);
     55                                writer.WriteRaw (JsonEmptyData);
     56                                SendEnvelopedResult (_context, ref writer, HttpStatusCode.NotFound);
    4657                                return;
    4758                        }
    4859
    4960                        {
    50                                 JsonArray result = new JsonArray ();
    51                                 JsonObject marker = new JsonObject ();
    52                                 marker.Add ("id", new JsonString (id));
    53                                 marker.Add ("lat", new JsonNumber (location.Item1));
    54                                 marker.Add ("lng", new JsonNumber (location.Item2));
    55                                 result.Add (marker);
    56                                 SendEnvelopedResult (_context, result);
     61                                writer.WriteBeginArray ();
     62                               
     63                                writeMarkerJson (ref writer, id, location);
     64                               
     65                                writer.WriteEndArray ();
     66                                SendEnvelopedResult (_context, ref writer);
    5767                        }
    5868                }
    5969
    60                 protected override void HandleRestPost (RequestContext _context, JsonNode _jsonBody) {
    61                         if (!(_jsonBody is JsonObject bodyObject)) {
    62                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, _jsonBody, "BODY_NOT_OBJECT");
     70                private void writeMarkerJson (ref JsonWriter _writer, string _markerId, (int, int) _coordinates) {
     71                        _writer.WriteRaw (jsonKeyId);
     72                        _writer.WriteString (_markerId);
     73                        _writer.WriteRaw (jsonKeyLat);
     74                        _writer.WriteInt32 (_coordinates.Item1);
     75                        _writer.WriteRaw (jsonKeyLng);
     76                        _writer.WriteInt32 (_coordinates.Item2);
     77                        _writer.WriteEndObject ();
     78                }
     79
     80                protected override void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
     81                        if (!TryGetJsonField (_jsonInput, "lat", out int lat)) {
     82                                SendErrorResult (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_OR_INVALID_LAT");
    6383                                return;
    6484                        }
    6585
    66                         if (!TryGetJsonField (bodyObject, "lat", out int lat)) {
    67                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, _jsonBody, "NO_OR_INVALID_LAT");
    68                                 return;
    69                         }
    70 
    71                         if (!TryGetJsonField (bodyObject, "lng", out int lng)) {
    72                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, _jsonBody, "NO_OR_INVALID_LNG");
     86                        if (!TryGetJsonField (_jsonInput, "lng", out int lng)) {
     87                                SendErrorResult (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_OR_INVALID_LNG");
    7388                                return;
    7489                        }
     
    7792                        markers.Add (newId, (lat, lng));
    7893
    79                         JsonString result = new JsonString (newId);
    80                         SendEnvelopedResult (_context, result, HttpStatusCode.Created);
     94                        PrepareEnvelopedResult (out JsonWriter writer);
     95                        writer.WriteString (newId);
     96                        SendEnvelopedResult (_context, ref writer, HttpStatusCode.Created);
    8197                }
    8298
    83                 protected override void HandleRestPut (RequestContext _context, JsonNode _jsonBody) {
    84                         if (!(_jsonBody is JsonObject bodyObject)) {
    85                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, _jsonBody, "BODY_NOT_OBJECT");
     99                protected override void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
     100                        if (!TryGetJsonField (_jsonInput, "lat", out int lat)) {
     101                                SendErrorResult (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_OR_INVALID_LAT");
    86102                                return;
    87103                        }
    88104
    89                         if (!TryGetJsonField (bodyObject, "lat", out int lat)) {
    90                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, _jsonBody, "NO_OR_INVALID_LAT");
    91                                 return;
    92                         }
    93 
    94                         if (!TryGetJsonField (bodyObject, "lng", out int lng)) {
    95                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, _jsonBody, "NO_OR_INVALID_LNG");
     105                        if (!TryGetJsonField (_jsonInput, "lng", out int lng)) {
     106                                SendErrorResult (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_OR_INVALID_LNG");
    96107                                return;
    97108                        }
     
    100111
    101112                        if (!markers.TryGetValue (id, out _)) {
    102                                 SendEnvelopedResult (_context, null, HttpStatusCode.NotFound, _jsonBody, "ID_NOT_FOUND");
     113                                SendErrorResult (_context, HttpStatusCode.NotFound, _jsonInputData, "ID_NOT_FOUND");
    103114                                return;
    104115                        }
     
    106117                        markers [id] = (lat, lng);
    107118
    108                         JsonObject result = new JsonObject ();
    109                         result.Add ("id", new JsonString (id));
    110                         result.Add ("lat", new JsonNumber (lat));
    111                         result.Add ("lng", new JsonNumber (lng));
    112                         SendEnvelopedResult (_context, result);
     119                        PrepareEnvelopedResult (out JsonWriter writer);
     120                        writer.WriteRaw (jsonKeyId);
     121                        writer.WriteString (id);
     122                        writer.WriteRaw (jsonKeyLat);
     123                        writer.WriteInt32 (lat);
     124                        writer.WriteRaw (jsonKeyLng);
     125                        writer.WriteInt32 (lng);
     126                        writer.WriteEndObject ();
     127                        SendEnvelopedResult (_context, ref writer);
    113128                }
    114129
     
    116131                        string id = _context.RequestPath;
    117132
    118                         SendEnvelopedResult (_context, null, markers.Remove (id) ? HttpStatusCode.NoContent : HttpStatusCode.NotFound);
     133                        PrepareEnvelopedResult (out JsonWriter writer);
     134                        writer.WriteRaw (JsonEmptyData);
     135                        SendEnvelopedResult (_context, ref writer, markers.Remove (id) ? HttpStatusCode.NoContent : HttpStatusCode.NotFound);
    119136                }
    120137        }
  • binary-improvements2/MarkersMod/src/ModApi.cs

    r391 r402  
     1using JetBrains.Annotations;
     2
    13namespace Examples {
     4        [UsedImplicitly]
    25        public class ModApi : IModApi {
    36                public void InitMod (Mod _modInstance) {
  • binary-improvements2/WebServer/ModInfo.xml

    r391 r402  
    11<?xml version="1.0" encoding="UTF-8" ?>
    22<xml>
    3         <ModInfo>
    4                 <Name value="TFP WebServer" />
    5                 <Description value="WebServer implementation" />
    6                 <Author value="The Fun Pimps LLC" />
    7                 <Version value="1" />
    8                 <Website value="" />
    9         </ModInfo>
     3        <Name value="TFP_WebServer" />
     4        <DisplayName value="Web Dashboard" />
     5        <Description value="Integrated Webserver for the Web Dashboard and server APIs" />
     6        <Author value="The Fun Pimps LLC" />
     7        <Version value="21.0" />
     8        <Website value="" />
    109</xml>
  • binary-improvements2/WebServer/WebServer.csproj

    r392 r402  
    1111    <AssemblyName>WebServer</AssemblyName>
    1212    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    13     <LangVersion>8</LangVersion>
     13    <LangVersion>9</LangVersion>
    1414  </PropertyGroup>
    1515  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     
    4545    <Reference Include="Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
    4646      <HintPath>..\7dtd-binaries\Assembly-CSharp-firstpass.dll</HintPath>
     47      <Private>False</Private>
     48    </Reference>
     49    <Reference Include="com.rlabrecque.steamworks.net, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
     50      <HintPath>..\7dtd-binaries\com.rlabrecque.steamworks.net.dll</HintPath>
    4751      <Private>False</Private>
    4852    </Reference>
     
    8387      <Private>False</Private>
    8488    </Reference>
     89    <Reference Include="Utf8Json, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
     90      <HintPath>..\7dtd-binaries\Utf8Json.dll</HintPath>
     91      <Private>False</Private>
     92    </Reference>
    8593  </ItemGroup>
    8694  <ItemGroup>
     95    <Compile Include="src\FileCache\AbstractCache.cs" />
     96    <Compile Include="src\FileCache\DirectAccess.cs" />
     97    <Compile Include="src\FileCache\InvalidateCachesCmd.cs" />
     98    <Compile Include="src\FileCache\SimpleCache.cs" />
     99    <Compile Include="src\LiveData\Animals.cs" />
     100    <Compile Include="src\LiveData\EntityFilterList.cs" />
     101    <Compile Include="src\LiveData\Hostiles.cs" />
    87102    <Compile Include="src\ModApi.cs" />
    88103    <Compile Include="src\UrlHandlers\ApiHandler.cs" />
     
    90105    <Compile Include="src\WebAPI\AbsRestApi.cs" />
    91106    <Compile Include="src\WebAPI\AbsWebAPI.cs" />
    92     <Compile Include="src\WebAPI\ExecuteConsoleCommand.cs" />
    93     <Compile Include="src\WebAPI\GetAllowedCommands.cs" />
    94     <Compile Include="src\WebAPI\GetAnimalsLocation.cs" />
    95     <Compile Include="src\WebAPI\GetHostileLocation.cs" />
    96     <Compile Include="src\WebAPI\GetLandClaims.cs" />
    97     <Compile Include="src\WebAPI\GetLog.cs" />
    98     <Compile Include="src\WebAPI\GetPlayerInventories.cs" />
    99     <Compile Include="src\WebAPI\GetPlayerInventory.cs" />
    100     <Compile Include="src\WebAPI\GetPlayerList.cs" />
    101     <Compile Include="src\WebAPI\GetPlayersLocation.cs" />
    102     <Compile Include="src\WebAPI\GetPlayersOnline.cs" />
    103     <Compile Include="src\WebAPI\GetServerInfo.cs" />
    104     <Compile Include="src\WebAPI\GetStats.cs" />
    105     <Compile Include="src\WebAPI\GetWebMods.cs" />
    106     <Compile Include="src\WebAPI\GetWebUIUpdates.cs" />
     107    <Compile Include="src\WebAPI\APIs\Animal.cs" />
     108    <Compile Include="src\WebAPI\APIs\Command.cs" />
     109    <Compile Include="src\WebAPI\APIs\GetLandClaims.cs" />
     110    <Compile Include="src\WebAPI\APIs\GetPlayerInventories.cs" />
     111    <Compile Include="src\WebAPI\APIs\GetPlayerInventory.cs" />
     112    <Compile Include="src\WebAPI\APIs\GetPlayerList.cs" />
     113    <Compile Include="src\WebAPI\APIs\GetPlayersLocation.cs" />
     114    <Compile Include="src\WebAPI\APIs\GetPlayersOnline.cs" />
     115    <Compile Include="src\WebAPI\APIs\Hostile.cs" />
     116    <Compile Include="src\WebAPI\APIs\Log.cs" />
     117    <Compile Include="src\WebAPI\APIs\ServerInfo.cs" />
     118    <Compile Include="src\WebAPI\APIs\ServerStats.cs" />
     119    <Compile Include="src\WebAPI\APIs\WebMods.cs" />
     120    <Compile Include="src\WebAPI\APIs\WebUiUpdates.cs" />
     121    <Compile Include="src\WebAPI\JsonCommons.cs" />
    107122    <Compile Include="src\WebAPI\Null.cs" />
    108123    <Compile Include="src\AssemblyInfo.cs" />
     
    145160  </ItemGroup>
    146161  <ItemGroup>
    147     <ProjectReference Include="..\7dtd-server-fixes\7dtd-server-fixes.csproj">
    148       <Project>{81da7f87-1a66-4920-aada-6eaf1971f8d0}</Project>
    149       <Name>7dtd-server-fixes</Name>
    150       <Private>False</Private>
    151     </ProjectReference>
    152     <ProjectReference Include="..\MapRendering\MapRendering.csproj">
    153       <Project>{a1847b5f-7bfc-4bcd-94aa-a6c9fb7e7c54}</Project>
    154       <Name>MapRendering</Name>
    155       <Private>False</Private>
    156     </ProjectReference>
    157162    <ProjectReference Include="..\SpaceWizards.HttpListener\SpaceWizards.HttpListener.csproj">
    158163      <Project>{1c5368e1-a4cf-4580-86bb-dffb20ab682c}</Project>
  • binary-improvements2/WebServer/src/Commands/EnableOpenIDDebug.cs

    r391 r402  
    1515                public override void Execute (List<string> _params, CommandSenderInfo _senderInfo) {
    1616                        if (_params.Count != 1) {
    17                                 SdtdConsole.Instance.Output ("Current state: " + OpenID.debugOpenId);
     17                                SdtdConsole.Instance.Output ($"Current state: {OpenID.debugOpenId}");
    1818                                return;
    1919                        }
    2020
    2121                        OpenID.debugOpenId = _params [0].Equals ("1");
    22                         SdtdConsole.Instance.Output ("Set OpenID debugging to " + _params [0].Equals ("1"));
     22                        SdtdConsole.Instance.Output ($"Set OpenID debugging to {_params [0].Equals ("1")}");
    2323                }
    2424        }
  • binary-improvements2/WebServer/src/Commands/WebTokens.cs

    r391 r402  
    3333                                        ExecuteList ();
    3434                                } else {
    35                                         SdtdConsole.Instance.Output ("Invalid sub command \"" + _params [0] + "\".");
     35                                        SdtdConsole.Instance.Output ($"Invalid sub command \"{_params [0]}\".");
    3636                                }
    3737                        } else {
     
    4242                private void ExecuteAdd (List<string> _params) {
    4343                        if (_params.Count != 4) {
    44                                 SdtdConsole.Instance.Output ("Wrong number of arguments, expected 4, found " + _params.Count + ".");
     44                                SdtdConsole.Instance.Output ($"Wrong number of arguments, expected 4, found {_params.Count}.");
    4545                                return;
    4646                        }
     
    7979                private void ExecuteRemove (List<string> _params) {
    8080                        if (_params.Count != 2) {
    81                                 SdtdConsole.Instance.Output ("Wrong number of arguments, expected 2, found " + _params.Count + ".");
     81                                SdtdConsole.Instance.Output ($"Wrong number of arguments, expected 2, found {_params.Count}.");
    8282                                return;
    8383                        }
  • binary-improvements2/WebServer/src/ConnectionHandler.cs

    r391 r402  
    22using System.Collections.Generic;
    33using System.Net;
    4 using Platform.Steam;
    54
    65namespace Webserver {
     
    1918
    2019                        if (!Equals (con.Endpoint, _ip)) {
    21                                 // Fixed: Allow different clients from same NAT network
    22 //                              connections.Remove (_sessionId);
     20                                connections.Remove (_sessionId);
    2321                                return null;
    2422                        }
     
    3331                }
    3432
    35                 public WebConnection LogIn (ulong _steamId, IPAddress _ip) {
     33                public WebConnection LogIn (PlatformUserIdentifierAbs _userId, IPAddress _ip) {
    3634                        string sessionId = Guid.NewGuid ().ToString ();
    37                         PlatformUserIdentifierAbs userId = new UserIdentifierSteam (_steamId);
    38                         WebConnection con = new WebConnection (sessionId, _ip, userId);
     35                        WebConnection con = new WebConnection (sessionId, _ip, _userId);
    3936                        connections.Add (sessionId, con);
    4037                        return con;
  • binary-improvements2/WebServer/src/FileCache/AbstractCache.cs

    r392 r402  
    11using System.Collections.Generic;
    22
    3 namespace AllocsFixes.FileCache {
     3namespace Webserver.FileCache {
    44        public abstract class AbstractCache {
    55                public abstract byte[] GetFileContent (string _filename);
    6                 public abstract (int, int) Invalidate ();
     6                public abstract (int filesDropped, int bytesDropped) Invalidate ();
    77
    88                protected AbstractCache () {
     
    1616                       
    1717                        foreach (AbstractCache cache in caches) {
    18                                 (int, int) returned = cache.Invalidate ();
    19                                 filesDropped += returned.Item1;
    20                                 bytesDropped += returned.Item2;
     18                                (int files, int bytes) = cache.Invalidate ();
     19                                filesDropped += files;
     20                                bytesDropped += bytes;
    2121                        }
    2222
  • binary-improvements2/WebServer/src/FileCache/DirectAccess.cs

    r392 r402  
    22using System.IO;
    33
    4 namespace AllocsFixes.FileCache {
     4namespace Webserver.FileCache {
    55        // Not caching at all, simply reading from disk on each request
    66        public class DirectAccess : AbstractCache {
     
    99                                return File.Exists (_filename) ? File.ReadAllBytes (_filename) : null;
    1010                        } catch (Exception e) {
    11                                 Log.Out ("Error in DirectAccess.GetFileContent: " + e);
     11                                Log.Out ($"Error in DirectAccess.GetFileContent: {e}");
    1212                        }
    1313
  • binary-improvements2/WebServer/src/FileCache/InvalidateCachesCmd.cs

    r397 r402  
    22using JetBrains.Annotations;
    33
    4 namespace AllocsFixes.FileCache {
     4namespace Webserver.FileCache {
    55        [UsedImplicitly]
    66        public class InvalidateCachesCmd : ConsoleCmdAbstract {
  • binary-improvements2/WebServer/src/FileCache/SimpleCache.cs

    r392 r402  
    33using System.IO;
    44
    5 namespace AllocsFixes.FileCache {
     5namespace Webserver.FileCache {
    66        // Caching all files, useful for completely static folders only
    77        public class SimpleCache : AbstractCache {
     
    2424                                }
    2525                        } catch (Exception e) {
    26                                 Log.Out ("Error in SimpleCache.GetFileContent: " + e);
     26                                Log.Out ($"Error in SimpleCache.GetFileContent: {e}");
    2727                        }
    2828
  • binary-improvements2/WebServer/src/LiveData/Animals.cs

    r326 r402  
    1 namespace AllocsFixes.LiveData {
     1namespace Webserver.LiveData {
    22        public class Animals : EntityFilterList<EntityAnimal> {
    33                public static readonly Animals Instance = new Animals ();
    44
    55                protected override EntityAnimal predicate (Entity _e) {
    6                         EntityAnimal ea = _e as EntityAnimal;
    7                         if (ea != null && ea.IsAlive ()) {
     6                        if (_e is EntityAnimal ea && ea.IsAlive ()) {
    87                                return ea;
    98                        }
  • binary-improvements2/WebServer/src/LiveData/EntityFilterList.cs

    r325 r402  
    22using System.Collections.Generic;
    33
    4 namespace AllocsFixes.LiveData {
     4namespace Webserver.LiveData {
    55        public abstract class EntityFilterList<T> where T : Entity {
    66                public void Get (List<T> _list) {
  • binary-improvements2/WebServer/src/LiveData/Hostiles.cs

    r326 r402  
    1 namespace AllocsFixes.LiveData {
     1namespace Webserver.LiveData {
    22        public class Hostiles : EntityFilterList<EntityEnemy> {
    33                public static readonly Hostiles Instance = new Hostiles ();
    44
    55                protected override EntityEnemy predicate (Entity _e) {
    6                         EntityEnemy enemy = _e as EntityEnemy;
    7                         if (enemy != null && enemy.IsAlive ()) {
     6                        if (_e is EntityEnemy enemy && enemy.IsAlive ()) {
    87                                return enemy;
    98                        }
  • binary-improvements2/WebServer/src/MimeType.cs

    r391 r402  
    574574
    575575                        if (!_extension.StartsWith (".")) {
    576                                 _extension = "." + _extension;
     576                                _extension = $".{_extension}";
    577577                        }
    578578
  • binary-improvements2/WebServer/src/OpenID.cs

    r399 r402  
    1919
    2020                private static readonly X509Certificate2 caCert =
    21                         new X509Certificate2 (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) +
    22                                               "/steam-rootca.cer");
     21                        new X509Certificate2 ($"{Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location)}/steam-rootca.cer");
    2322
    2423                private static readonly X509Certificate2 caIntermediateCert =
    25                         new X509Certificate2 (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) +
    26                                               "/steam-intermediate.cer");
     24                        new X509Certificate2 ($"{Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location)}/steam-intermediate.cer");
    2725
    2826                private const bool verboseSsl = false;
     
    7472                                foreach (X509ChainElement chainEl in privateChain.ChainElements) {
    7573                                        if (verboseSsl) {
    76                                                 Log.Out ("Validating cert: " + chainEl.Certificate.Subject);
     74                                                Log.Out ($"Validating cert: {chainEl.Certificate.Subject}");
    7775                                        }
    7876
     
    8078                                        foreach (X509ChainStatus chainStatus in chainEl.ChainElementStatus) {
    8179                                                if (verboseSsl) {
    82                                                         Log.Out ("   Status: " + chainStatus.Status);
     80                                                        Log.Out ($"   Status: {chainStatus.Status}");
    8381                                                }
    8482
     
    9492
    9593                                                // This status is an error, print information
    96                                                 Log.Warning ("[OpenID] Steam certificate error: " + chainEl.Certificate.Subject + " ### Error: " +
    97                                                              chainStatus.Status);
     94                                                Log.Warning ($"[OpenID] Steam certificate error: {chainEl.Certificate.Subject} ### Error: {chainStatus.Status}");
    9895                                                privateChain.Reset ();
    9996                                                return false;
     
    104101                                        if (chainStatus.Status != X509ChainStatusFlags.NoError &&
    105102                                            chainStatus.Status != X509ChainStatusFlags.UntrustedRoot) {
    106                                                 Log.Warning ("[OpenID] Steam certificate error: " + chainStatus.Status);
     103                                                Log.Warning ($"[OpenID] Steam certificate error: {chainStatus.Status}");
    107104                                                privateChain.Reset ();
    108105                                                return false;
     
    130127                        };
    131128
    132                         return STEAM_LOGIN + '?' + buildUrlParams (queryParams);
     129                        return $"{STEAM_LOGIN}?{buildUrlParams (queryParams)}";
    133130                }
    134131
     
    141138
    142139                        if (mode == "error") {
    143                                 Log.Warning ("[OpenID] Steam OpenID login error: " + getValue (_req, "openid.error"));
     140                                Log.Warning ($"[OpenID] Steam OpenID login error: {getValue (_req, "openid.error")}");
    144141                                if (debugOpenId) {
    145142                                        PrintOpenIdResponse (_req);
     
    174171                        string[] signeds = getValue (_req, "openid.signed").Split (',');
    175172                        foreach (string s in signeds) {
    176                                 queryParams ["openid." + s] = getValue (_req, "openid." + s);
     173                                string name = $"openid.{s}";
     174                                queryParams [name] = getValue (_req, name);
    177175                        }
    178176
     
    201199                        }
    202200
    203                         Log.Warning ("[OpenID] Steam OpenID login failed: {0}", responseString);
     201                        Log.Warning ($"[OpenID] Steam OpenID login failed: {responseString}");
    204202                        return 0;
    205203                }
     
    209207                        int i = 0;
    210208                        foreach ((string argName, string argValue) in _queryParams) {
    211                                 paramsArr [i++] = argName + "=" + Uri.EscapeDataString (argValue);
     209                                paramsArr [i++] = $"{argName}={Uri.EscapeDataString (argValue)}";
    212210                        }
    213211
     
    218216                        NameValueCollection nvc = _req.QueryString;
    219217                        if (nvc [_name] == null) {
    220                                 throw new MissingMemberException ("[OpenID] OpenID parameter \"" + _name + "\" missing");
     218                                throw new MissingMemberException ($"[OpenID] OpenID parameter \"{_name}\" missing");
    221219                        }
    222220
     
    227225                        NameValueCollection nvc = _req.QueryString;
    228226                        for (int i = 0; i < nvc.Count; i++) {
    229                                 Log.Out ("   " + nvc.GetKey (i) + " = " + nvc [i]);
     227                                Log.Out ($"   {nvc.GetKey (i)} = {nvc [i]}");
    230228                        }
    231229                }
  • binary-improvements2/WebServer/src/SSE/AbsEvent.cs

    r399 r402  
    44using System.Net.Sockets;
    55using System.Text;
    6 using AllocsFixes.JSON;
    76using Webserver.UrlHandlers;
    87using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
     
    2019                private readonly List<HttpListenerResponse> openStreams = new List<HttpListenerResponse> ();
    2120
    22                 private readonly BlockingQueue<(string _eventName, object _data)> sendQueue =
    23                         new BlockingQueue<(string _eventName, object _data)> ();
     21                private readonly BlockingQueue<(string _eventName, string _data)> sendQueue =
     22                        new BlockingQueue<(string _eventName, string _data)> ();
    2423
    2524                private int currentlyOpen;
     
    4241                }
    4342
    44                 protected void SendData (string _eventName, object _data) {
     43                protected void SendData (string _eventName, string _data) {
    4544                        sendQueue.Enqueue ((_eventName, _data));
    4645                        Parent.SignalSendQueue ();
    4746                }
    4847
    49 
    5048                public void ProcessSendQueue () {
    5149                        while (sendQueue.HasData ()) {
    52                                 (string eventName, object data) = sendQueue.Dequeue ();
     50                                (string eventName, string data) = sendQueue.Dequeue ();
    5351                               
    5452                                stringBuilder.Append ("event: ");
    5553                                stringBuilder.AppendLine (eventName);
    5654                                stringBuilder.Append ("data: ");
    57                                
    58                                 switch (data) {
    59                                         case string dataString:
    60                                                 stringBuilder.AppendLine (dataString);
    61                                                 break;
    62                                         case JsonNode dataJson:
    63                                                 dataJson.ToString (stringBuilder);
    64                                                 stringBuilder.AppendLine ("");
    65                                                 break;
    66                                         default:
    67                                                 logError ("Data is neither string nor JSON.", false);
    68                                                 continue;
    69                                 }
     55                                stringBuilder.AppendLine (data);
    7056                               
    7157                                stringBuilder.AppendLine ("");
     58
    7259                                string output = stringBuilder.ToString ();
    7360                                stringBuilder.Clear ();
     
    11198                                                if (e.InnerException is SocketException se) {
    11299                                                        if (se.SocketErrorCode != SocketError.ConnectionAborted && se.SocketErrorCode != SocketError.Shutdown) {
    113                                                                 logError ($"SocketError ({se.SocketErrorCode}) while trying to write", true);
     100                                                                logError ($"SocketError ({se.SocketErrorCode.ToStringCached ()}) while trying to write", true);
    114101                                                        }
    115102                                                } else {
  • binary-improvements2/WebServer/src/SSE/EventLog.cs

    r391 r402  
    11using System;
    2 using AllocsFixes.JSON;
    32using JetBrains.Annotations;
    43using UnityEngine;
     4using Utf8Json;
    55using Webserver.UrlHandlers;
    66
     
    1212                }
    1313
     14                private static readonly byte[] jsonMsgKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("msg");
     15                private static readonly byte[] jsonTypeKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("type");
     16                private static readonly byte[] jsonTraceKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("trace");
     17                private static readonly byte[] jsonIsotimeKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("isotime");
     18                private static readonly byte[] jsonUptimeKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("uptime");
     19
    1420                private void LogCallback (string _formattedMsg, string _plainMsg, string _trace, LogType _type, DateTime _timestamp, long _uptime) {
    1521                        string isotime = _timestamp.ToString ("o");
    1622                        string uptime = _uptime.ToString ();
    1723
    18                         JsonObject data = new JsonObject ();
    19                         data.Add ("msg", new JsonString (_plainMsg));
    20                         data.Add ("type", new JsonString (_type.ToStringCached ()));
    21                         data.Add ("trace", new JsonString (_trace));
    22                         data.Add ("isotime", new JsonString (isotime));
    23                         data.Add ("uptime", new JsonString (uptime));
    24 
    25                         SendData ("logLine", data);
     24                        JsonWriter writer = new JsonWriter ();
     25                       
     26                        writer.WriteRaw (jsonMsgKey);
     27                        writer.WriteString (_plainMsg);
     28                       
     29                        writer.WriteRaw (jsonTypeKey);
     30                        writer.WriteString (_type.ToStringCached ());
     31                       
     32                        writer.WriteRaw (jsonTraceKey);
     33                        writer.WriteString (_trace);
     34                       
     35                        writer.WriteRaw (jsonIsotimeKey);
     36                        writer.WriteString (isotime);
     37                       
     38                        writer.WriteRaw (jsonUptimeKey);
     39                        writer.WriteString (uptime);
     40                       
     41                        writer.WriteEndObject ();
     42                       
     43                        SendData ("logLine", writer.ToString ());
    2644                }
    2745        }
  • binary-improvements2/WebServer/src/UrlHandlers/ApiHandler.cs

    r399 r402  
    4545                private void addApi (AbsWebAPI _api) {
    4646                        apis.Add (_api.Name, _api);
    47                         WebPermissions.Instance.AddKnownModule ("webapi." + _api.Name, _api.DefaultPermissionLevel ());
     47                        WebPermissions.Instance.AddKnownModule ($"webapi.{_api.Name}", _api.DefaultPermissionLevel ());
    4848                }
    4949
     
    9292
    9393                private bool IsAuthorizedForApi (string _apiName, int _permissionLevel) {
    94                         return WebPermissions.Instance.ModuleAllowedWithLevel ("webapi." + _apiName, _permissionLevel);
     94                        return WebPermissions.Instance.ModuleAllowedWithLevel ($"webapi.{_apiName}", _permissionLevel);
    9595                }
    9696        }
  • binary-improvements2/WebServer/src/UrlHandlers/ItemIconHandler.cs

    r399 r402  
    33using System.IO;
    44using System.Net;
    5 using AllocsFixes;
    65using UnityEngine;
    76using Object = UnityEngine.Object;
     
    4544                                _context.Response.StatusCode = (int) HttpStatusCode.NotFound;
    4645                                if (logMissingFiles) {
    47                                         Log.Out ("[Web] IconHandler: FileNotFound: \"" + _context.RequestPath + "\" ");
     46                                        Log.Out ($"[Web] IconHandler: FileNotFound: \"{_context.RequestPath}\" ");
    4847                                }
    4948                        }
     49                }
     50
     51                private class LoadingStats {
     52                        public int Files;
     53                        public int Tints;
     54                        public readonly MicroStopwatch MswTotal = new MicroStopwatch (false);
     55                        public readonly MicroStopwatch MswLoading = new MicroStopwatch (false);
     56                        public readonly MicroStopwatch MswEncoding = new MicroStopwatch (false);
     57                        public readonly MicroStopwatch MswTinting = new MicroStopwatch (false);
    5058                }
    5159
     
    5765                                }
    5866
    59                                 MicroStopwatch microStopwatch = new MicroStopwatch ();
     67                                LoadingStats stats = new LoadingStats ();
     68                                stats?.MswTotal.Start ();
    6069
    6170                                // Get list of used tints for all items
     
    7281
    7382                                        string name = ic.GetIconName ();
    74                                         if (!tintedIcons.ContainsKey (name)) {
    75                                                 tintedIcons.Add (name, new List<Color> ());
     83                                        if (!tintedIcons.TryGetValue (name, out List<Color> tintsList)) {
     84                                                tintsList = new List<Color> ();
     85                                                tintedIcons.Add (name, tintsList);
    7686                                        }
    7787
    78                                         List<Color> list = tintedIcons [name];
    79                                         list.Add (tintColor);
     88                                        tintsList.Add (tintColor);
    8089                                }
    8190
    8291                                try {
    83                                         loadIconsFromFolder (GameIO.GetGameDir ("Data/ItemIcons"), tintedIcons);
     92                                        loadIconsFromFolder (GameIO.GetGameDir ("Data/ItemIcons"), tintedIcons, stats);
    8493                                } catch (Exception e) {
    8594                                        Log.Error ("[Web] Failed loading icons from base game");
     
    9099                                foreach (Mod mod in ModManager.GetLoadedMods ()) {
    91100                                        try {
    92                                                 string modIconsPath = mod.Path + "/ItemIcons";
    93                                                 loadIconsFromFolder (modIconsPath, tintedIcons);
     101                                                string modIconsPath = $"{mod.Path}/ItemIcons";
     102                                                loadIconsFromFolder (modIconsPath, tintedIcons, stats);
    94103                                        } catch (Exception e) {
    95                                                 Log.Error ("[Web] Failed loading icons from mod " + mod.ModInfo.Name.Value);
     104                                                Log.Error ($"[Web] Failed loading icons from mod {mod.Name}");
    96105                                                Log.Exception (e);
    97106                                        }
    98107                                }
     108                               
     109                                loaded = true;
    99110
    100                                 loaded = true;
    101                                 Log.Out ("[Web] IconHandler: Icons loaded - {0} ms", microStopwatch.ElapsedMilliseconds);
     111                                if (stats == null) {
     112                                        Log.Out ($"[Web] IconHandler: Loaded {icons.Count} icons");
     113                                } else {
     114                                        stats?.MswTotal.Stop ();
     115                                        Log.Out ($"[Web] IconHandler: Loaded {icons.Count} icons ({stats.Files} source images with {stats.Tints} tints applied)");
     116                                        Log.Out ($"[Web] IconHandler: Total time {stats.MswTotal.ElapsedMilliseconds} ms, loading files {stats.MswLoading.ElapsedMilliseconds} ms, tinting files {stats.MswTinting.ElapsedMilliseconds} ms, encoding files {stats.MswEncoding.ElapsedMilliseconds} ms");
     117
     118                                        int totalSize = 0;
     119                                        foreach ((string _, byte[] iconData) in icons) {
     120                                                totalSize += iconData.Length;
     121                                        }
     122                                       
     123                                        Log.Out ($"[Web] IconHandler: Cached {totalSize / 1024} KiB");
     124                                }
    102125
    103126                                return true;
     
    105128                }
    106129
    107                 private void loadIconsFromFolder (string _path, Dictionary<string, List<Color>> _tintedIcons) {
     130                private void loadIconsFromFolder (string _path, Dictionary<string, List<Color>> _tintedIcons, LoadingStats _stats) {
    108131                        if (!Directory.Exists (_path)) {
    109132                                return;
     
    118141                                        string name = Path.GetFileNameWithoutExtension (file);
    119142                                        Texture2D tex = new Texture2D (1, 1, TextureFormat.ARGB32, false);
    120                                         if (!tex.LoadImage (File.ReadAllBytes (file))) {
     143                                       
     144                                        _stats?.MswLoading.Start ();
     145                                        byte[] sourceBytes = File.ReadAllBytes (file);
     146                                        if (!tex.LoadImage (sourceBytes)) {
     147                                                _stats?.MswLoading.Stop ();
    121148                                                continue;
    122149                                        }
     150                                        _stats?.MswLoading.Stop ();
    123151
    124                                         AddIcon (name, tex, _tintedIcons);
     152                                        AddIcon (name, sourceBytes, tex, _tintedIcons, _stats);
    125153
    126154                                        Object.Destroy (tex);
     
    131159                }
    132160
    133                 private void AddIcon (string _name, Texture2D _tex, Dictionary<string, List<Color>> _tintedIcons) {
    134                         icons [_name + "__FFFFFF"] = _tex.EncodeToPNG ();
     161                private void AddIcon (string _name, byte[] _sourceBytes, Texture2D _tex, Dictionary<string, List<Color>> _tintedIcons, LoadingStats _stats) {
     162                        _stats?.MswEncoding.Start ();
     163                        icons [$"{_name}__FFFFFF"] = _sourceBytes;
     164                        _stats?.MswEncoding.Stop ();
    135165
    136                         if (!_tintedIcons.ContainsKey (_name)) {
     166                        if (_stats != null) {
     167                                _stats.Files++;
     168                        }
     169
     170                        if (!_tintedIcons.TryGetValue (_name, out List<Color> tintsList)) {
    137171                                return;
    138172                        }
    139173
    140                         foreach (Color c in _tintedIcons [_name]) {
    141                                 string tintedName = _name + "__" + AllocsUtils.ColorToHex (c);
     174                        foreach (Color c in tintsList) {
     175                                string tintedName = $"{_name}__{c.ToHexCode ()}";
    142176                                if (icons.ContainsKey (tintedName)) {
    143177                                        continue;
     
    146180                                Texture2D tintedTex = new Texture2D (_tex.width, _tex.height, TextureFormat.ARGB32, false);
    147181
    148                                 for (int x = 0; x < _tex.width; x++) {
    149                                         for (int y = 0; y < _tex.height; y++) {
    150                                                 tintedTex.SetPixel (x, y, _tex.GetPixel (x, y) * c);
    151                                         }
    152                                 }
     182                                _stats?.MswTinting.Start ();
     183                                TextureUtils.ApplyTint (_tex, tintedTex, c);
     184                                _stats?.MswTinting.Stop ();
    153185
     186                                _stats?.MswEncoding.Start ();
    154187                                icons [tintedName] = tintedTex.EncodeToPNG ();
     188                                _stats?.MswEncoding.Stop ();
    155189
    156190                                Object.Destroy (tintedTex);
     191
     192                                if (_stats != null) {
     193                                        _stats.Tints++;
     194                                }
    157195                        }
    158196                }
     197               
    159198        }
    160199}
  • binary-improvements2/WebServer/src/UrlHandlers/RewriteHandler.cs

    r391 r402  
    1010
    1111                public override void HandleRequest (RequestContext _context) {
    12                         _context.RequestPath = fixedTarget ? target : target + _context.RequestPath.Remove (0, urlBasePath.Length);
     12                        _context.RequestPath = fixedTarget ? target : $"{target}{_context.RequestPath.Remove (0, urlBasePath.Length)}";
    1313                        parent.ApplyPathHandler (_context);
    1414                }
  • binary-improvements2/WebServer/src/UrlHandlers/SessionHandler.cs

    r399 r402  
    11using System;
     2using System.Collections.Generic;
     3using System.IO;
    24using System.Net;
     5using Platform.Steam;
     6using Utf8Json;
    37
    48namespace Webserver.UrlHandlers {
     
    610                private const string pageBasePath = "/app";
    711                private const string pageErrorPath = "/app/error/";
     12               
    813                private const string steamOpenIdVerifyUrl = "verifysteamopenid";
    914                private const string steamLoginUrl = "loginsteam";
     15                private const string userPassLoginUrl = "login";
    1016
    1117                private readonly ConnectionHandler connectionHandler;
     
    3743                                return;
    3844                        }
     45                       
     46                        if (subpath.StartsWith (userPassLoginUrl)) {
     47                                HandleUserPassLogin (_context);
     48                                return;
     49                        }
    3950
    4051                        _context.Response.Redirect (pageErrorPath + "InvalidSessionsCommand");
    4152                }
    4253
     54                private void HandleUserPassLogin (RequestContext _context) {
     55                        if (!_context.Request.HasEntityBody) {
     56                                _context.Response.Redirect (pageErrorPath + "NoLoginData");
     57                                return;
     58                        }
     59
     60                        Stream requestInputStream = _context.Request.InputStream;
     61
     62                        byte[] jsonInputData = new byte[_context.Request.ContentLength64];
     63                        requestInputStream.Read (jsonInputData, 0, (int)_context.Request.ContentLength64);
     64
     65                        IDictionary<string, object> inputJson;
     66                        try {
     67                                inputJson = JsonSerializer.Deserialize<IDictionary<string, object>> (jsonInputData);
     68                        } catch (Exception e) {
     69                                Log.Error ("Error deserializing JSON from user/password login:");
     70                                Log.Exception (e);
     71                                _context.Response.Redirect (pageErrorPath + "InvalidLoginJson");
     72                                return;
     73                        }
     74
     75                        if (!inputJson.TryGetValue ("username", out object fieldNode) || fieldNode is not string username) {
     76                                _context.Response.Redirect (pageErrorPath + "InvalidLoginJson");
     77                                return;
     78                        }
     79
     80                        if (!inputJson.TryGetValue ("password", out fieldNode) || fieldNode is not string password) {
     81                                _context.Response.Redirect (pageErrorPath + "InvalidLoginJson");
     82                                return;
     83                        }
     84
     85                        // TODO: Apply login
     86
     87                        string remoteEndpointString = _context.Request.RemoteEndPoint!.ToString ();
     88
     89                        if (username != "test" || password != "123") {
     90                                // TODO: failed login
     91                                Log.Out ($"[Web] User/pass login failed from {remoteEndpointString}");
     92                                _context.Response.Redirect (pageErrorPath + "UserPassInvalid");
     93                                return;
     94                        }
     95                       
     96                        try {
     97                                // TODO: Match username/password to UserIdentifierAbs / serveradmins.xml
     98                               
     99                                WebConnection con = connectionHandler.LogIn (new UserIdentifierSteam (76561198066968172ul), _context.Request.RemoteEndPoint.Address);
     100                                int level = GameManager.Instance.adminTools.GetUserPermissionLevel (con.UserId);
     101                                Log.Out ($"[Web] User/pass login from {remoteEndpointString} with ID {con.UserId}, permission level {level}");
     102
     103                                Cookie cookie = new Cookie ("sid", con.SessionID, "/") {
     104                                        Expired = false,
     105                                        Expires = DateTime.MinValue,
     106                                        HttpOnly = true,
     107                                        Secure = false
     108                                };
     109                                _context.Response.AppendCookie (cookie);
     110                                _context.Response.Redirect (pageBasePath);
     111
     112                                return;
     113                        } catch (Exception e) {
     114                                Log.Error ("[Web] Error during user/pass login:");
     115                                Log.Exception (e);
     116                        }
     117
     118                        _context.Response.Redirect (pageErrorPath + "UserPassLoginFailed");
     119                }
     120
    43121                private void HandleSteamLogin (RequestContext _context) {
    44                         string host = (WebUtils.IsSslRedirected (_context.Request) ? "https://" : "http://") + _context.Request.UserHostName;
    45                         string url = OpenID.GetOpenIdLoginUrl (host, host + urlBasePath + steamOpenIdVerifyUrl);
     122                        string host = $"{(WebUtils.IsSslRedirected (_context.Request) ? "https://" : "http://")}{_context.Request.UserHostName}";
     123                        string url = OpenID.GetOpenIdLoginUrl (host, $"{host}{urlBasePath}{steamOpenIdVerifyUrl}");
    46124                        _context.Response.Redirect (url);
    47125                }
     
    68146                                ulong id = OpenID.Validate (_context.Request);
    69147                                if (id > 0) {
    70                                         WebConnection con = connectionHandler.LogIn (id, _context.Request.RemoteEndPoint.Address);
     148                                        WebConnection con = connectionHandler.LogIn (new UserIdentifierSteam (id), _context.Request.RemoteEndPoint.Address);
    71149                                        int level = GameManager.Instance.adminTools.GetUserPermissionLevel (con.UserId);
    72                                         Log.Out ("[Web] Steam OpenID login from {0} with ID {1}, permission level {2}",
    73                                                 remoteEndpointString, con.UserId, level);
     150                                        Log.Out ($"[Web] Steam OpenID login from {remoteEndpointString} with ID {con.UserId}, permission level {level}");
    74151
    75152                                        Cookie cookie = new Cookie ("sid", con.SessionID, "/") {
  • binary-improvements2/WebServer/src/UrlHandlers/SseHandler.cs

    r399 r402  
    3939                        base.SetBasePathAndParent (_parent, _relativePath);
    4040
    41                         queueThead = ThreadManager.StartThread ("SSE-Processing_" + urlBasePath, QueueProcessThread, ThreadPriority.BelowNormal,
     41                        queueThead = ThreadManager.StartThread ($"SSE-Processing_{urlBasePath}", QueueProcessThread, ThreadPriority.BelowNormal,
    4242                                _useRealThread: true);
    4343                }
     
    4949                }
    5050
     51                // ReSharper disable once MemberCanBePrivate.Global
    5152                public void AddEvent (string _eventName, AbsEvent _eventInstance) {
    5253                        events.Add (_eventName, _eventInstance);
    53                         WebPermissions.Instance.AddKnownModule ("webevent." + _eventName, _eventInstance.DefaultPermissionLevel ());
     54                        WebPermissions.Instance.AddKnownModule ($"webevent.{_eventName}", _eventInstance.DefaultPermissionLevel ());
    5455                }
    5556
     
    8889
    8990                private bool IsAuthorizedForEvent (string _eventName, int _permissionLevel) {
    90                         return WebPermissions.Instance.ModuleAllowedWithLevel ("webevent." + _eventName, _permissionLevel);
     91                        return WebPermissions.Instance.ModuleAllowedWithLevel ($"webevent.{_eventName}", _permissionLevel);
    9192                }
    9293
  • binary-improvements2/WebServer/src/UrlHandlers/StaticHandler.cs

    r399 r402  
    11using System.IO;
    22using System.Net;
    3 using AllocsFixes.FileCache;
     3using Webserver.FileCache;
    44
    55namespace Webserver.UrlHandlers {
     
    1111                public StaticHandler (string _filePath, AbstractCache _cache, bool _logMissingFiles,
    1212                        string _moduleName = null) : base (_moduleName) {
    13                         datapath = _filePath + (_filePath [_filePath.Length - 1] == '/' ? "" : "/");
     13                        datapath = $"{_filePath}{(_filePath [^1] == '/' ? "" : "/")}";
    1414                        cache = _cache;
    1515                        logMissingFiles = _logMissingFiles;
     
    1919                        string fn = _context.RequestPath.Remove (0, urlBasePath.Length);
    2020
    21                         byte[] content = cache.GetFileContent (datapath + fn);
     21                        byte[] content = cache.GetFileContent ($"{datapath}{fn}");
    2222
    2323                        if (content != null) {
     
    2828                                _context.Response.StatusCode = (int) HttpStatusCode.NotFound;
    2929                                if (logMissingFiles) {
    30                                         Log.Warning ("[Web] Static: FileNotFound: \"" + _context.RequestPath + "\" @ \"" + datapath + fn + "\"");
     30                                        Log.Warning ($"[Web] Static: FileNotFound: \"{_context.RequestPath}\" @ \"{datapath}{fn}\"");
    3131                                }
    3232                        }
  • binary-improvements2/WebServer/src/UrlHandlers/UserStatusHandler.cs

    r391 r402  
    1 using AllocsFixes.JSON;
     1using Utf8Json;
    22
    33namespace Webserver.UrlHandlers {
     
    66                }
    77
     8                private static readonly byte[] jsonLoggedInKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("loggedIn");
     9                private static readonly byte[] jsonUsernameKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("username");
     10                private static readonly byte[] jsonPermissionsKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("permissions");
     11
     12                private static readonly byte[] jsonModuleKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("module");
     13                private static readonly byte[] jsonAllowedKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("allowed");
     14
    815                public override void HandleRequest (RequestContext _context) {
    9                         JsonObject result = new JsonObject ();
     16                        WebUtils.PrepareEnvelopedResult (out JsonWriter writer);
     17                       
     18                        writer.WriteRaw (jsonLoggedInKey);
     19                        writer.WriteBoolean (_context.Connection != null);
     20                       
     21                        writer.WriteRaw (jsonUsernameKey);
     22                        writer.WriteString (_context.Connection != null ? _context.Connection.UserId.ToString () : string.Empty);
     23                       
     24                        writer.WriteRaw (jsonPermissionsKey);
     25                        writer.WriteBeginArray ();
    1026
    11                         result.Add ("loggedin", new JsonBoolean (_context.Connection != null));
    12                         result.Add ("username", new JsonString (_context.Connection != null ? _context.Connection.UserId.ToString () : string.Empty));
     27                        bool first = true;
     28                        foreach (WebPermissions.WebModulePermission perm in WebPermissions.Instance.GetModules ()) {
     29                                if (!first) {
     30                                        writer.WriteValueSeparator ();
     31                                }
    1332
    14                         JsonArray perms = new JsonArray ();
    15                         foreach (WebPermissions.WebModulePermission perm in WebPermissions.Instance.GetModules ()) {
    16                                 JsonObject permObj = new JsonObject ();
    17                                 permObj.Add ("module", new JsonString (perm.module));
    18                                 permObj.Add ("allowed", new JsonBoolean (perm.permissionLevel >= _context.PermissionLevel));
    19                                 perms.Add (permObj);
     33                                first = false;
     34                               
     35                                writer.WriteRaw (jsonModuleKey);
     36                                writer.WriteString (perm.module);
     37                               
     38                                writer.WriteRaw (jsonAllowedKey);
     39                                writer.WriteBoolean (perm.permissionLevel >= _context.PermissionLevel);
     40                               
     41                                writer.WriteEndObject ();
    2042                        }
    2143
    22                         result.Add ("permissions", perms);
    23 
    24                         WebUtils.WriteJson (_context.Response, result);
     44                        writer.WriteEndArray ();
     45                       
     46                        writer.WriteEndObject ();
     47                       
     48                        WebUtils.SendEnvelopedResult (_context, ref writer);
    2549                }
    2650        }
  • binary-improvements2/WebServer/src/Web.cs

    r398 r402  
    33using System.IO;
    44using System.Net.Sockets;
    5 using AllocsFixes.FileCache;
    6 using MapRendering;
    75using SpaceWizards.HttpListener;
    86using UnityEngine;
     7using Webserver.FileCache;
    98using Webserver.UrlHandlers;
    109using Cookie = System.Net.Cookie;
     
    1413namespace Webserver {
    1514        public class Web : IConsoleServer {
     15                public static event Action<Web> ServerInitialized;
     16               
    1617                private const int guestPermissionLevel = 2000;
    1718                private const string indexPageUrl = "/app";
     
    2627                public Web (string _modInstancePath) {
    2728                        try {
    28                                 int webPort = GamePrefs.GetInt (EnumUtils.Parse<EnumGamePrefs> ("ControlPanelPort"));
     29                                int webPort = GamePrefs.GetInt (EnumUtils.Parse<EnumGamePrefs> (nameof (EnumGamePrefs.ControlPanelPort)));
    2930                                if (webPort < 1 || webPort > 65533) {
    3031                                        Log.Out ("[Web] Webserver not started (ControlPanelPort not within 1-65533)");
     
    4445
    4546                                string webfilesFolder = DetectWebserverFolder (_modInstancePath);
    46                                 string webfilesFolderLegacy = _modInstancePath + "/weblegacy";
     47                                string webfilesFolderLegacy = $"{_modInstancePath}/weblegacy";
    4748
    4849                                connectionHandler = new ConnectionHandler ();
     
    5657                                RegisterPathHandler ("/weblegacy", new StaticHandler (
    5758                                        webfilesFolderLegacy,
    58                                         useStaticCache ? (AbstractCache)new SimpleCache () : new DirectAccess (),
     59                                        useStaticCache ? new SimpleCache () : new DirectAccess (),
    5960                                        false)
    6061                                );
     
    6869                                RegisterPathHandler ("/files/", new StaticHandler (
    6970                                        webfilesFolder,
    70                                         useStaticCache ? (AbstractCache) new SimpleCache () : new DirectAccess (),
     71                                        useStaticCache ? new SimpleCache () : new DirectAccess (),
    7172                                        false)
    7273                                );
    7374                                RegisterPathHandler ("/itemicons/", new ItemIconHandler (true));
    74                                 RegisterPathHandler ("/map/", new StaticHandler (
    75                                         GameIO.GetSaveGameDir () + "/map",
    76                                         MapRenderer.GetTileCache (),
    77                                         false,
    78                                         "web.map")
    79                                 );
    8075                                RegisterPathHandler ("/api/", new ApiHandler ());
     76                               
     77                                // Allow other code to add their stuff
     78                                ServerInitialized?.Invoke (this);
    8179
    8280                                listener.Prefixes.Add ($"http://+:{webPort}/");
     
    8785                                SdtdConsole.Instance.RegisterServer (this);
    8886
    89                                 Log.Out ("[Web] Started Webserver on port " + webPort);
     87                                Log.Out ($"[Web] Started Webserver on port {webPort}");
    9088                        } catch (Exception e) {
    9189                                Log.Error ("[Web] Error in Web.ctor: ");
     
    9593
    9694                private static string DetectWebserverFolder (string _modInstancePath) {
    97                         string webserverFolder = _modInstancePath + "/webserver";
     95                        string webserverFolder = $"{_modInstancePath}/webserver";
    9896
    9997                        foreach (Mod mod in ModManager.GetLoadedMods ()) {
    100                                 string modServerFolder = mod.Path + "/webserver";
     98                                string modServerFolder = $"{mod.Path}/webserver";
    10199                               
    102100                                if (Directory.Exists (modServerFolder)) {
     
    127125                        foreach (Mod mod in ModManager.GetLoadedMods ()) {
    128126                                try {
    129                                         string webModPath = mod.Path + "/WebMod";
     127                                        string webModPath = $"{mod.Path}/WebMod";
    130128                                        if (!Directory.Exists (webModPath)) {
    131129                                                continue;
     
    136134                                                webMods.Add (webMod);
    137135                                        } catch (InvalidDataException e) {
    138                                                 Log.Error ($"[Web] Could not load webmod from mod {mod.ModInfo.Name.Value}: {e.Message}");
     136                                                Log.Error ($"[Web] Could not load webmod from mod {mod.Name}: {e.Message}");
    139137                                        }
    140138                                } catch (Exception e) {
    141                                         Log.Error ("[Web] Failed loading web mods from mod " + mod.ModInfo.Name.Value);
     139                                        Log.Error ($"[Web] Failed loading web mods from mod {mod.Name}");
    142140                                        Log.Exception (e);
    143141                                }
     
    150148                                listener.Close ();
    151149                        } catch (Exception e) {
    152                                 Log.Out ("[Web] Error in Web.Disconnect: " + e);
     150                                Log.Out ($"[Web] Error in Web.Disconnect: {e}");
    153151                        }
    154152                }
     
    238236                        } catch (IOException e) {
    239237                                if (e.InnerException is SocketException) {
    240                                         Log.Out ("[Web] Error in Web.HandleRequest(): Remote host closed connection: " + e.InnerException.Message);
     238                                        Log.Out ($"[Web] Error in Web.HandleRequest(): Remote host closed connection: {e.InnerException.Message}");
    241239                                } else {
    242                                         Log.Out ("[Web] Error (IO) in Web.HandleRequest(): " + e);
     240                                        Log.Out ($"[Web] Error (IO) in Web.HandleRequest(): {e}");
    243241                                }
    244242                        } catch (Exception e) {
     
    313311                        }
    314312
    315                         Log.Warning ("[Web] Invalid Admintoken used from " + reqRemoteEndPoint);
     313                        Log.Warning ($"[Web] Invalid Admintoken used from {reqRemoteEndPoint}");
    316314
    317315                        return guestPermissionLevel;
  • binary-improvements2/WebServer/src/WebAPI/APIs/Animal.cs

    r401 r402  
    11using System.Collections.Generic;
    2 using AllocsFixes.JSON;
    3 using AllocsFixes.LiveData;
    42using JetBrains.Annotations;
     3using Utf8Json;
     4using Webserver.LiveData;
    55
    6 namespace Webserver.WebAPI {
     6namespace Webserver.WebAPI.APIs {
    77        [UsedImplicitly]
    8         internal class GetAnimalsLocation : AbsWebAPI {
    9                 private readonly List<EntityAnimal> animals = new List<EntityAnimal> ();
     8        internal class Animal : AbsRestApi {
     9                private readonly List<EntityAnimal> entities = new List<EntityAnimal> ();
    1010
    11                 public override void HandleRequest (RequestContext _context) {
    12                         JsonArray animalsJsResult = new JsonArray ();
     11                private static readonly byte[] jsonKeyId = JsonWriter.GetEncodedPropertyNameWithBeginObject ("id");
     12                private static readonly byte[] jsonKeyName = JsonWriter.GetEncodedPropertyNameWithBeginObject ("name");
     13                private static readonly byte[] jsonKeyPosition = JsonWriter.GetEncodedPropertyNameWithBeginObject ("position");
    1314
    14                         Animals.Instance.Get (animals);
    15                         for (int i = 0; i < animals.Count; i++) {
    16                                 EntityAnimal entity = animals [i];
    17                                 Vector3i position = new Vector3i (entity.GetPosition ());
     15                protected override void HandleRestGet (RequestContext _context) {
     16                        PrepareEnvelopedResult (out JsonWriter writer);
     17                        writer.WriteBeginArray ();
     18                       
     19                        lock (entities) {
     20                                Animals.Instance.Get (entities);
     21                               
     22                                for (int i = 0; i < entities.Count; i++) {
     23                                        if (i > 0) {
     24                                                writer.WriteValueSeparator ();
     25                                        }
     26                                       
     27                                        EntityAlive entity = entities [i];
     28                                        Vector3i position = new Vector3i (entity.GetPosition ());
     29                                       
     30                                        writer.WriteRaw (jsonKeyId);
     31                                        writer.WriteInt32 (entity.entityId);
     32                                       
     33                                        writer.WriteRaw (jsonKeyName);
     34                                        writer.WriteString (!string.IsNullOrEmpty (entity.EntityName) ? entity.EntityName : $"animal class #{entity.entityClass}");
     35                                       
     36                                        writer.WriteRaw (jsonKeyPosition);
     37                                        JsonCommons.WritePositionObject (writer, position);
    1838
    19                                 JsonObject jsonPOS = new JsonObject ();
    20                                 jsonPOS.Add ("x", new JsonNumber (position.x));
    21                                 jsonPOS.Add ("y", new JsonNumber (position.y));
    22                                 jsonPOS.Add ("z", new JsonNumber (position.z));
    23 
    24                                 JsonObject pJson = new JsonObject ();
    25                                 pJson.Add ("id", new JsonNumber (entity.entityId));
    26 
    27                                 if (!string.IsNullOrEmpty (entity.EntityName)) {
    28                                         pJson.Add ("name", new JsonString (entity.EntityName));
    29                                 } else {
    30                                         pJson.Add ("name", new JsonString ("animal class #" + entity.entityClass));
     39                                        writer.WriteEndObject ();
    3140                                }
    32 
    33                                 pJson.Add ("position", jsonPOS);
    34 
    35                                 animalsJsResult.Add (pJson);
    3641                        }
    37 
    38                         WebUtils.WriteJson (_context.Response, animalsJsResult);
     42                       
     43                        writer.WriteEndArray ();
     44                        SendEnvelopedResult (_context, ref writer);
    3945                }
    4046        }
  • binary-improvements2/WebServer/src/WebAPI/APIs/GetLandClaims.cs

    r401 r402  
    1 using System.Collections.Generic;
    2 using System.Net;
    3 using AllocsFixes;
    4 using AllocsFixes.JSON;
    5 using AllocsFixes.PersistentData;
    6 using JetBrains.Annotations;
    7 
    8 namespace Webserver.WebAPI {
    9         [UsedImplicitly]
    10         public class GetLandClaims : AbsWebAPI {
    11                 public override void HandleRequest (RequestContext _context) {
    12                         PlatformUserIdentifierAbs requestedUserId = null;
    13                         if (_context.Request.QueryString ["userid"] != null) {
    14                                 if (!PlatformUserIdentifierAbs.TryFromCombinedString (_context.Request.QueryString ["userid"], out requestedUserId)) {
    15                                         WebUtils.WriteText (_context.Response, "Invalid user id given", HttpStatusCode.BadRequest);
    16                                         return;
    17                                 }
    18                         }
    19 
    20                         // default user, cheap way to avoid 'null reference exception'
    21                         PlatformUserIdentifierAbs userId = _context.Connection?.UserId;
    22 
    23                         bool bViewAll = WebConnection.CanViewAllClaims (_context.PermissionLevel);
    24 
    25                         JsonObject result = new JsonObject ();
    26                         result.Add ("claimsize", new JsonNumber (GamePrefs.GetInt (EnumUtils.Parse<EnumGamePrefs> ("LandClaimSize"))));
    27 
    28                         JsonArray claimOwners = new JsonArray ();
    29                         result.Add ("claimowners", claimOwners);
    30 
    31                         LandClaimList.OwnerFilter[] ownerFilters = null;
    32                         if (requestedUserId != null || !bViewAll) {
    33                                 if (requestedUserId != null && !bViewAll) {
    34                                         ownerFilters = new[] {
    35                                                 LandClaimList.UserIdFilter (userId),
    36                                                 LandClaimList.UserIdFilter (requestedUserId)
    37                                         };
    38                                 } else if (!bViewAll) {
    39                                         ownerFilters = new[] {LandClaimList.UserIdFilter (userId)};
    40                                 } else {
    41                                         ownerFilters = new[] {LandClaimList.UserIdFilter (requestedUserId)};
    42                                 }
    43                         }
    44 
    45                         LandClaimList.PositionFilter[] posFilters = null;
    46 
    47                         Dictionary<Player, List<Vector3i>> claims = LandClaimList.GetLandClaims (ownerFilters, posFilters);
    48 
    49                         foreach ((Player player, List<Vector3i> claimPositions) in claims) {
    50                                 JsonObject owner = new JsonObject ();
    51                                 claimOwners.Add (owner);
    52 
    53                                 owner.Add ("steamid", new JsonString (player.PlatformId.CombinedString));
    54                                 owner.Add ("claimactive", new JsonBoolean (player.LandProtectionActive));
    55 
    56                                 if (player.Name.Length > 0) {
    57                                         owner.Add ("playername", new JsonString (player.Name));
    58                                 } else {
    59                                         owner.Add ("playername", new JsonNull ());
    60                                 }
    61 
    62                                 JsonArray claimsJson = new JsonArray ();
    63                                 owner.Add ("claims", claimsJson);
    64 
    65                                 foreach (Vector3i v in claimPositions) {
    66                                         JsonObject claim = new JsonObject ();
    67                                         claim.Add ("x", new JsonNumber (v.x));
    68                                         claim.Add ("y", new JsonNumber (v.y));
    69                                         claim.Add ("z", new JsonNumber (v.z));
    70 
    71                                         claimsJson.Add (claim);
    72                                 }
    73                         }
    74 
    75                         WebUtils.WriteJson (_context.Response, result);
    76                 }
    77         }
    78 }
     1// using System.Collections.Generic;
     2// using System.Net;
     3// using AllocsFixes;
     4// using AllocsFixes.PersistentData;
     5// using JetBrains.Annotations;
     6//
     7// namespace Webserver.WebAPI.APIs {
     8//      [UsedImplicitly]
     9//      public class GetLandClaims : AbsWebAPI {
     10//              public override void HandleRequest (RequestContext _context) {
     11//                      PlatformUserIdentifierAbs requestedUserId = null;
     12//                      if (_context.Request.QueryString ["userid"] != null) {
     13//                              if (!PlatformUserIdentifierAbs.TryFromCombinedString (_context.Request.QueryString ["userid"], out requestedUserId)) {
     14//                                      WebUtils.WriteText (_context.Response, "Invalid user id given", HttpStatusCode.BadRequest);
     15//                                      return;
     16//                              }
     17//                      }
     18//
     19//                      // default user, cheap way to avoid 'null reference exception'
     20//                      PlatformUserIdentifierAbs userId = _context.Connection?.UserId;
     21//
     22//                      bool bViewAll = WebConnection.CanViewAllClaims (_context.PermissionLevel);
     23//
     24//                      JsonObject result = new JsonObject ();
     25//                      result.Add ("claimsize",
     26//                              new JsonNumber (GamePrefs.GetInt (EnumUtils.Parse<EnumGamePrefs> (nameof (EnumGamePrefs.LandClaimSize)))));
     27//
     28//                      JsonArray claimOwners = new JsonArray ();
     29//                      result.Add ("claimowners", claimOwners);
     30//
     31//                      LandClaimList.OwnerFilter[] ownerFilters = null;
     32//                      if (requestedUserId != null || !bViewAll) {
     33//                              if (requestedUserId != null && !bViewAll) {
     34//                                      ownerFilters = new[] {
     35//                                              LandClaimList.UserIdFilter (userId),
     36//                                              LandClaimList.UserIdFilter (requestedUserId)
     37//                                      };
     38//                              } else if (!bViewAll) {
     39//                                      ownerFilters = new[] {LandClaimList.UserIdFilter (userId)};
     40//                              } else {
     41//                                      ownerFilters = new[] {LandClaimList.UserIdFilter (requestedUserId)};
     42//                              }
     43//                      }
     44//
     45//                      LandClaimList.PositionFilter[] posFilters = null;
     46//
     47//                      Dictionary<Player, List<Vector3i>> claims = LandClaimList.GetLandClaims (ownerFilters, posFilters);
     48//
     49//                      foreach ((Player player, List<Vector3i> claimPositions) in claims) {
     50//                              JsonObject owner = new JsonObject ();
     51//                              claimOwners.Add (owner);
     52//
     53//                              owner.Add ("steamid", new JsonString (player.PlatformId.CombinedString));
     54//                              owner.Add ("claimactive", new JsonBoolean (player.LandProtectionActive));
     55//
     56//                              if (player.Name.Length > 0) {
     57//                                      owner.Add ("playername", new JsonString (player.Name));
     58//                              } else {
     59//                                      owner.Add ("playername", new JsonNull ());
     60//                              }
     61//
     62//                              JsonArray claimsJson = new JsonArray ();
     63//                              owner.Add ("claims", claimsJson);
     64//
     65//                              foreach (Vector3i v in claimPositions) {
     66//                                      JsonObject claim = new JsonObject ();
     67//                                      claim.Add ("x", new JsonNumber (v.x));
     68//                                      claim.Add ("y", new JsonNumber (v.y));
     69//                                      claim.Add ("z", new JsonNumber (v.z));
     70//
     71//                                      claimsJson.Add (claim);
     72//                              }
     73//                      }
     74//
     75//                      WebUtils.WriteJson (_context.Response, result);
     76//              }
     77//      }
     78// }
  • binary-improvements2/WebServer/src/WebAPI/APIs/GetPlayerInventories.cs

    r401 r402  
    1 using System.Collections.Generic;
    2 using AllocsFixes.JSON;
    3 using AllocsFixes.PersistentData;
    4 using JetBrains.Annotations;
    5 
    6 namespace Webserver.WebAPI {
    7         [UsedImplicitly]
    8         public class GetPlayerInventories : AbsWebAPI {
    9                 public override void HandleRequest (RequestContext _context) {
    10                         GetPlayerInventory.GetInventoryArguments (_context.Request, out bool showIconColor, out bool showIconName);
    11 
    12                         JsonArray allInventoriesResult = new JsonArray ();
    13 
    14                         foreach ((PlatformUserIdentifierAbs userId, Player player) in PersistentContainer.Instance.Players.Dict) {
    15                                 if (player == null) {
    16                                         continue;
    17                                 }
    18 
    19                                 if (player.IsOnline) {
    20                                         allInventoriesResult.Add (GetPlayerInventory.DoPlayer (userId.CombinedString, player, showIconColor, showIconName));
    21                                 }
    22                         }
    23 
    24                         WebUtils.WriteJson (_context.Response, allInventoriesResult);
    25                 }
    26         }
    27 }
     1// using AllocsFixes.PersistentData;
     2// using JetBrains.Annotations;
     3//
     4// namespace Webserver.WebAPI.APIs {
     5//      [UsedImplicitly]
     6//      public class GetPlayerInventories : AbsWebAPI {
     7//              public override void HandleRequest (RequestContext _context) {
     8//                      GetPlayerInventory.GetInventoryArguments (_context.Request, out bool showIconColor, out bool showIconName);
     9//
     10//                      JsonArray allInventoriesResult = new JsonArray ();
     11//
     12//                      foreach ((PlatformUserIdentifierAbs userId, Player player) in PersistentContainer.Instance.Players.Dict) {
     13//                              if (player == null) {
     14//                                      continue;
     15//                              }
     16//
     17//                              if (player.IsOnline) {
     18//                                      allInventoriesResult.Add (GetPlayerInventory.DoPlayer (userId.CombinedString, player, showIconColor, showIconName));
     19//                              }
     20//                      }
     21//
     22//                      WebUtils.WriteJson (_context.Response, allInventoriesResult);
     23//              }
     24//      }
     25// }
  • binary-improvements2/WebServer/src/WebAPI/APIs/GetPlayerInventory.cs

    r401 r402  
    1 using System.Collections.Generic;
    2 using System.Net;
    3 using AllocsFixes.JSON;
    4 using AllocsFixes.PersistentData;
    5 using JetBrains.Annotations;
    6 using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
    7 
    8 namespace Webserver.WebAPI {
    9         [UsedImplicitly]
    10         public class GetPlayerInventory : AbsWebAPI {
    11                 public override void HandleRequest (RequestContext _context) {
    12                         if (_context.Request.QueryString ["userid"] == null) {
    13                                 WebUtils.WriteText (_context.Response, "No user id given", HttpStatusCode.BadRequest);
    14                                 return;
    15                         }
    16 
    17                         string userIdString = _context.Request.QueryString ["userid"];
    18                         if (!PlatformUserIdentifierAbs.TryFromCombinedString (userIdString, out PlatformUserIdentifierAbs userId)) {
    19                                 WebUtils.WriteText (_context.Response, "Invalid user id given", HttpStatusCode.BadRequest);
    20                                 return;
    21                         }
    22 
    23                         Player p = PersistentContainer.Instance.Players [userId, false];
    24                         if (p == null) {
    25                                 WebUtils.WriteText (_context.Response, "Unknown user id given", HttpStatusCode.NotFound);
    26                                 return;
    27                         }
    28 
    29                         GetInventoryArguments (_context.Request, out bool showIconColor, out bool showIconName);
    30 
    31                         JsonObject result = DoPlayer (userIdString, p, showIconColor, showIconName);
    32 
    33                         WebUtils.WriteJson (_context.Response, result);
    34                 }
    35 
    36                 internal static void GetInventoryArguments (HttpListenerRequest _req, out bool _showIconColor, out bool _showIconName) {
    37                         if (_req.QueryString ["showiconcolor"] == null || !bool.TryParse (_req.QueryString ["showiconcolor"], out _showIconColor)) {
    38                                 _showIconColor = true;
    39                         }
    40                        
    41                         if (_req.QueryString ["showiconname"] == null || !bool.TryParse (_req.QueryString ["showiconname"], out _showIconName)) {
    42                                 _showIconName = true;
    43                         }
    44                 }
    45 
    46                 internal static JsonObject DoPlayer (string _steamId, Player _player, bool _showIconColor, bool _showIconName) {
    47                         AllocsFixes.PersistentData.Inventory inv = _player.Inventory;
    48 
    49                         JsonObject result = new JsonObject ();
    50 
    51                         JsonArray bag = new JsonArray ();
    52                         JsonArray belt = new JsonArray ();
    53                         JsonObject equipment = new JsonObject ();
    54                         result.Add ("userid", new JsonString (_steamId));
    55                         result.Add ("entityid", new JsonNumber (_player.EntityID));
    56                         result.Add ("playername", new JsonString (_player.Name));
    57                         result.Add ("bag", bag);
    58                         result.Add ("belt", belt);
    59                         result.Add ("equipment", equipment);
    60 
    61                         DoInventory (belt, inv.belt, _showIconColor, _showIconName);
    62                         DoInventory (bag, inv.bag, _showIconColor, _showIconName);
    63 
    64                         AddEquipment (equipment, "head", inv.equipment, EquipmentSlots.Headgear, _showIconColor, _showIconName);
    65                         AddEquipment (equipment, "eyes", inv.equipment, EquipmentSlots.Eyewear, _showIconColor, _showIconName);
    66                         AddEquipment (equipment, "face", inv.equipment, EquipmentSlots.Face, _showIconColor, _showIconName);
    67 
    68                         AddEquipment (equipment, "armor", inv.equipment, EquipmentSlots.ChestArmor, _showIconColor, _showIconName);
    69                         AddEquipment (equipment, "jacket", inv.equipment, EquipmentSlots.Jacket, _showIconColor, _showIconName);
    70                         AddEquipment (equipment, "shirt", inv.equipment, EquipmentSlots.Shirt, _showIconColor, _showIconName);
    71 
    72                         AddEquipment (equipment, "legarmor", inv.equipment, EquipmentSlots.LegArmor, _showIconColor, _showIconName);
    73                         AddEquipment (equipment, "pants", inv.equipment, EquipmentSlots.Legs, _showIconColor, _showIconName);
    74                         AddEquipment (equipment, "boots", inv.equipment, EquipmentSlots.Feet, _showIconColor, _showIconName);
    75 
    76                         AddEquipment (equipment, "gloves", inv.equipment, EquipmentSlots.Hands, _showIconColor, _showIconName);
    77 
    78                         return result;
    79                 }
    80 
    81                 private static void DoInventory (JsonArray _jsonRes, List<InvItem> _inv, bool _showIconColor, bool _showIconName) {
    82                         for (int i = 0; i < _inv.Count; i++) {
    83                                 _jsonRes.Add (GetJsonForItem (_inv [i], _showIconColor, _showIconName));
    84                         }
    85                 }
    86 
    87                 private static void AddEquipment (JsonObject _eq, string _slotname, InvItem[] _items, EquipmentSlots _slot, bool _showIconColor, bool _showIconName) {
    88                         int[] slotindices = XUiM_PlayerEquipment.GetSlotIndicesByEquipmentSlot (_slot);
    89 
    90                         for (int i = 0; i < slotindices.Length; i++) {
    91                                 if (_items? [slotindices [i]] == null) {
    92                                         continue;
    93                                 }
    94 
    95                                 InvItem item = _items [slotindices [i]];
    96                                 _eq.Add (_slotname, GetJsonForItem (item, _showIconColor, _showIconName));
    97                                 return;
    98                         }
    99 
    100                         _eq.Add (_slotname, new JsonNull ());
    101                 }
    102 
    103                 private static JsonNode GetJsonForItem (InvItem _item, bool _showIconColor, bool _showIconName) {
    104                         if (_item == null) {
    105                                 return new JsonNull ();
    106                         }
    107 
    108                         JsonObject jsonItem = new JsonObject ();
    109                         jsonItem.Add ("count", new JsonNumber (_item.count));
    110                         jsonItem.Add ("name", new JsonString (_item.itemName));
    111                        
    112                         if (_showIconName) {
    113                                 jsonItem.Add ("icon", new JsonString (_item.icon));
    114                         }
    115 
    116                         if (_showIconColor) {
    117                                 jsonItem.Add ("iconcolor", new JsonString (_item.iconcolor));
    118                         }
    119 
    120                         jsonItem.Add ("quality", new JsonNumber (_item.quality));
    121                         if (_item.quality >= 0) {
    122                                 jsonItem.Add ("qualitycolor", new JsonString (QualityInfo.GetQualityColorHex (_item.quality)));
    123                         }
    124 
    125                         return jsonItem;
    126 
    127                 }
    128         }
    129 }
     1// using System.Collections.Generic;
     2// using System.Net;
     3// using AllocsFixes.PersistentData;
     4// using JetBrains.Annotations;
     5// using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
     6//
     7// namespace Webserver.WebAPI.APIs {
     8//      [UsedImplicitly]
     9//      public class GetPlayerInventory : AbsWebAPI {
     10//              public override void HandleRequest (RequestContext _context) {
     11//                      if (_context.Request.QueryString ["userid"] == null) {
     12//                              WebUtils.WriteText (_context.Response, "No user id given", HttpStatusCode.BadRequest);
     13//                              return;
     14//                      }
     15//
     16//                      string userIdString = _context.Request.QueryString ["userid"];
     17//                      if (!PlatformUserIdentifierAbs.TryFromCombinedString (userIdString, out PlatformUserIdentifierAbs userId)) {
     18//                              WebUtils.WriteText (_context.Response, "Invalid user id given", HttpStatusCode.BadRequest);
     19//                              return;
     20//                      }
     21//
     22//                      Player p = PersistentContainer.Instance.Players [userId, false];
     23//                      if (p == null) {
     24//                              WebUtils.WriteText (_context.Response, "Unknown user id given", HttpStatusCode.NotFound);
     25//                              return;
     26//                      }
     27//
     28//                      GetInventoryArguments (_context.Request, out bool showIconColor, out bool showIconName);
     29//
     30//                      JsonObject result = DoPlayer (userIdString, p, showIconColor, showIconName);
     31//
     32//                      WebUtils.WriteJson (_context.Response, result);
     33//              }
     34//
     35//              internal static void GetInventoryArguments (HttpListenerRequest _req, out bool _showIconColor, out bool _showIconName) {
     36//                      if (_req.QueryString ["showiconcolor"] == null || !bool.TryParse (_req.QueryString ["showiconcolor"], out _showIconColor)) {
     37//                              _showIconColor = true;
     38//                      }
     39//                     
     40//                      if (_req.QueryString ["showiconname"] == null || !bool.TryParse (_req.QueryString ["showiconname"], out _showIconName)) {
     41//                              _showIconName = true;
     42//                      }
     43//              }
     44//
     45//              internal static JsonObject DoPlayer (string _steamId, Player _player, bool _showIconColor, bool _showIconName) {
     46//                      AllocsFixes.PersistentData.Inventory inv = _player.Inventory;
     47//
     48//                      JsonObject result = new JsonObject ();
     49//
     50//                      JsonArray bag = new JsonArray ();
     51//                      JsonArray belt = new JsonArray ();
     52//                      JsonObject equipment = new JsonObject ();
     53//                      result.Add ("userid", new JsonString (_steamId));
     54//                      result.Add ("entityid", new JsonNumber (_player.EntityID));
     55//                      result.Add ("playername", new JsonString (_player.Name));
     56//                      result.Add ("bag", bag);
     57//                      result.Add ("belt", belt);
     58//                      result.Add ("equipment", equipment);
     59//
     60//                      DoInventory (belt, inv.belt, _showIconColor, _showIconName);
     61//                      DoInventory (bag, inv.bag, _showIconColor, _showIconName);
     62//
     63//                      AddEquipment (equipment, "head", inv.equipment, EquipmentSlots.Headgear, _showIconColor, _showIconName);
     64//                      AddEquipment (equipment, "eyes", inv.equipment, EquipmentSlots.Eyewear, _showIconColor, _showIconName);
     65//                      AddEquipment (equipment, "face", inv.equipment, EquipmentSlots.Face, _showIconColor, _showIconName);
     66//
     67//                      AddEquipment (equipment, "armor", inv.equipment, EquipmentSlots.ChestArmor, _showIconColor, _showIconName);
     68//                      AddEquipment (equipment, "jacket", inv.equipment, EquipmentSlots.Jacket, _showIconColor, _showIconName);
     69//                      AddEquipment (equipment, "shirt", inv.equipment, EquipmentSlots.Shirt, _showIconColor, _showIconName);
     70//
     71//                      AddEquipment (equipment, "legarmor", inv.equipment, EquipmentSlots.LegArmor, _showIconColor, _showIconName);
     72//                      AddEquipment (equipment, "pants", inv.equipment, EquipmentSlots.Legs, _showIconColor, _showIconName);
     73//                      AddEquipment (equipment, "boots", inv.equipment, EquipmentSlots.Feet, _showIconColor, _showIconName);
     74//
     75//                      AddEquipment (equipment, "gloves", inv.equipment, EquipmentSlots.Hands, _showIconColor, _showIconName);
     76//
     77//                      return result;
     78//              }
     79//
     80//              private static void DoInventory (JsonArray _jsonRes, List<InvItem> _inv, bool _showIconColor, bool _showIconName) {
     81//                      for (int i = 0; i < _inv.Count; i++) {
     82//                              _jsonRes.Add (GetJsonForItem (_inv [i], _showIconColor, _showIconName));
     83//                      }
     84//              }
     85//
     86//              private static void AddEquipment (JsonObject _eq, string _slotname, InvItem[] _items, EquipmentSlots _slot, bool _showIconColor, bool _showIconName) {
     87//                      int[] slotindices = XUiM_PlayerEquipment.GetSlotIndicesByEquipmentSlot (_slot);
     88//
     89//                      for (int i = 0; i < slotindices.Length; i++) {
     90//                              if (_items? [slotindices [i]] == null) {
     91//                                      continue;
     92//                              }
     93//
     94//                              InvItem item = _items [slotindices [i]];
     95//                              _eq.Add (_slotname, GetJsonForItem (item, _showIconColor, _showIconName));
     96//                              return;
     97//                      }
     98//
     99//                      _eq.Add (_slotname, new JsonNull ());
     100//              }
     101//
     102//              private static JsonNode GetJsonForItem (InvItem _item, bool _showIconColor, bool _showIconName) {
     103//                      if (_item == null) {
     104//                              return new JsonNull ();
     105//                      }
     106//
     107//                      JsonObject jsonItem = new JsonObject ();
     108//                      jsonItem.Add ("count", new JsonNumber (_item.count));
     109//                      jsonItem.Add ("name", new JsonString (_item.itemName));
     110//                     
     111//                      if (_showIconName) {
     112//                              jsonItem.Add ("icon", new JsonString (_item.icon));
     113//                      }
     114//
     115//                      if (_showIconColor) {
     116//                              jsonItem.Add ("iconcolor", new JsonString (_item.iconcolor));
     117//                      }
     118//
     119//                      jsonItem.Add ("quality", new JsonNumber (_item.quality));
     120//                      if (_item.quality >= 0) {
     121//                              jsonItem.Add ("qualitycolor", new JsonString (QualityInfo.GetQualityColorHex (_item.quality)));
     122//                      }
     123//
     124//                      return jsonItem;
     125//
     126//              }
     127//      }
     128// }
  • binary-improvements2/WebServer/src/WebAPI/APIs/GetPlayerList.cs

    r401 r402  
    1 using System;
    2 using System.Collections.Generic;
    3 using System.Linq;
    4 using System.Text.RegularExpressions;
    5 using AllocsFixes.JSON;
    6 using AllocsFixes.PersistentData;
    7 using JetBrains.Annotations;
    8 
    9 namespace Webserver.WebAPI {
    10         [UsedImplicitly]
    11         public class GetPlayerList : AbsWebAPI {
    12                 private static readonly Regex numberFilterMatcher =
    13                         new Regex (@"^(>=|=>|>|<=|=<|<|==|=)?\s*([0-9]+(\.[0-9]*)?)$");
    14 
    15                 private static readonly UnityEngine.Profiling.CustomSampler jsonSerializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Build");
    16 
    17                 public override void HandleRequest (RequestContext _context) {
    18                         AdminTools admTools = GameManager.Instance.adminTools;
    19                         PlatformUserIdentifierAbs userId = _context.Connection?.UserId;
    20 
    21                         bool bViewAll = WebConnection.CanViewAllPlayers (_context.PermissionLevel);
    22 
    23                         // TODO: Sort (and filter?) prior to converting to JSON ... hard as how to get the correct column's data? (i.e. column name matches JSON object field names, not source data)
    24 
    25                         int rowsPerPage = 25;
    26                         if (_context.Request.QueryString ["rowsperpage"] != null) {
    27                                 int.TryParse (_context.Request.QueryString ["rowsperpage"], out rowsPerPage);
    28                         }
    29 
    30                         int page = 0;
    31                         if (_context.Request.QueryString ["page"] != null) {
    32                                 int.TryParse (_context.Request.QueryString ["page"], out page);
    33                         }
    34 
    35                         int firstEntry = page * rowsPerPage;
    36 
    37                         Players playersList = PersistentContainer.Instance.Players;
    38 
    39                        
    40                         List<JsonObject> playerList = new List<JsonObject> ();
    41 
    42                         jsonSerializeSampler.Begin ();
    43 
    44                         foreach (KeyValuePair<PlatformUserIdentifierAbs, Player> kvp in playersList.Dict) {
    45                                 Player p = kvp.Value;
    46 
    47                                 if (bViewAll || p.PlatformId.Equals (userId)) {
    48                                         JsonObject pos = new JsonObject ();
    49                                         pos.Add ("x", new JsonNumber (p.LastPosition.x));
    50                                         pos.Add ("y", new JsonNumber (p.LastPosition.y));
    51                                         pos.Add ("z", new JsonNumber (p.LastPosition.z));
    52 
    53                                         JsonObject pJson = new JsonObject ();
    54                                         pJson.Add ("steamid", new JsonString (kvp.Key.CombinedString));
    55                                         pJson.Add ("entityid", new JsonNumber (p.EntityID));
    56                                         pJson.Add ("ip", new JsonString (p.IP));
    57                                         pJson.Add ("name", new JsonString (p.Name));
    58                                         pJson.Add ("online", new JsonBoolean (p.IsOnline));
    59                                         pJson.Add ("position", pos);
    60 
    61                                         pJson.Add ("totalplaytime", new JsonNumber (p.TotalPlayTime));
    62                                         pJson.Add ("lastonline",
    63                                                 new JsonString (p.LastOnline.ToUniversalTime ().ToString ("yyyy-MM-ddTHH:mm:ssZ")));
    64                                         pJson.Add ("ping", new JsonNumber (p.IsOnline ? p.ClientInfo.ping : -1));
    65 
    66                                         JsonBoolean banned = admTools != null ? new JsonBoolean (admTools.IsBanned (kvp.Key, out _, out _)) : new JsonBoolean (false);
    67 
    68                                         pJson.Add ("banned", banned);
    69 
    70                                         playerList.Add (pJson);
    71                                 }
    72                         }
    73 
    74                         jsonSerializeSampler.End ();
    75 
    76                         IEnumerable<JsonObject> list = playerList;
    77 
    78                         foreach (string key in _context.Request.QueryString.AllKeys) {
    79                                 if (!string.IsNullOrEmpty (key) && key.StartsWith ("filter[")) {
    80                                         string filterCol = key.Substring (key.IndexOf ('[') + 1);
    81                                         filterCol = filterCol.Substring (0, filterCol.Length - 1);
    82                                         string filterVal = _context.Request.QueryString.Get (key).Trim ();
    83 
    84                                         list = ExecuteFilter (list, filterCol, filterVal);
    85                                 }
    86                         }
    87 
    88                         int totalAfterFilter = list.Count ();
    89 
    90                         foreach (string key in _context.Request.QueryString.AllKeys) {
    91                                 if (!string.IsNullOrEmpty (key) && key.StartsWith ("sort[")) {
    92                                         string sortCol = key.Substring (key.IndexOf ('[') + 1);
    93                                         sortCol = sortCol.Substring (0, sortCol.Length - 1);
    94                                         string sortVal = _context.Request.QueryString.Get (key);
    95 
    96                                         list = ExecuteSort (list, sortCol, sortVal == "0");
    97                                 }
    98                         }
    99 
    100                         list = list.Skip (firstEntry);
    101                         list = list.Take (rowsPerPage);
    102 
    103 
    104                         JsonArray playersJsResult = new JsonArray ();
    105                         foreach (JsonObject jsO in list) {
    106                                 playersJsResult.Add (jsO);
    107                         }
    108 
    109                         JsonObject result = new JsonObject ();
    110                         result.Add ("total", new JsonNumber (totalAfterFilter));
    111                         result.Add ("totalUnfiltered", new JsonNumber (playerList.Count));
    112                         result.Add ("firstResult", new JsonNumber (firstEntry));
    113                         result.Add ("players", playersJsResult);
    114 
    115                         WebUtils.WriteJson (_context.Response, result);
    116                 }
    117 
    118                 private IEnumerable<JsonObject> ExecuteFilter (IEnumerable<JsonObject> _list, string _filterCol,
    119                         string _filterVal) {
    120                         if (!_list.Any()) {
    121                                 return _list;
    122                         }
    123 
    124                         if (_list.First ().ContainsKey (_filterCol)) {
    125                                 Type colType = _list.First () [_filterCol].GetType ();
    126                                 if (colType == typeof (JsonNumber)) {
    127                                         return ExecuteNumberFilter (_list, _filterCol, _filterVal);
    128                                 }
    129 
    130                                 if (colType == typeof (JsonBoolean)) {
    131                                         bool value = StringParsers.ParseBool (_filterVal);
    132                                         return _list.Where (_line => ((JsonBoolean) _line [_filterCol]).GetBool () == value);
    133                                 }
    134 
    135                                 if (colType == typeof (JsonString)) {
    136                                         // regex-match whole ^string$, replace * by .*, ? by .?, + by .+
    137                                         _filterVal = _filterVal.Replace ("*", ".*").Replace ("?", ".?").Replace ("+", ".+");
    138                                         _filterVal = "^" + _filterVal + "$";
    139 
    140                                         //Log.Out ("GetPlayerList: Filter on String with Regex '" + _filterVal + "'");
    141                                         Regex matcher = new Regex (_filterVal, RegexOptions.IgnoreCase);
    142                                         return _list.Where (_line => matcher.IsMatch (((JsonString) _line [_filterCol]).GetString ()));
    143                                 }
    144                         }
    145 
    146                         return _list;
    147                 }
    148 
    149 
    150                 private IEnumerable<JsonObject> ExecuteNumberFilter (IEnumerable<JsonObject> _list, string _filterCol,
    151                         string _filterVal) {
    152                         // allow value (exact match), =, ==, >=, >, <=, <
    153                         Match filterMatch = numberFilterMatcher.Match (_filterVal);
    154                         if (filterMatch.Success) {
    155                                 double value = StringParsers.ParseDouble (filterMatch.Groups [2].Value);
    156                                 NumberMatchType matchType;
    157                                 double epsilon = value / 100000;
    158                                 switch (filterMatch.Groups [1].Value) {
    159                                         case "":
    160                                         case "=":
    161                                         case "==":
    162                                                 matchType = NumberMatchType.Equal;
    163                                                 break;
    164                                         case ">":
    165                                                 matchType = NumberMatchType.Greater;
    166                                                 break;
    167                                         case ">=":
    168                                         case "=>":
    169                                                 matchType = NumberMatchType.GreaterEqual;
    170                                                 break;
    171                                         case "<":
    172                                                 matchType = NumberMatchType.Lesser;
    173                                                 break;
    174                                         case "<=":
    175                                         case "=<":
    176                                                 matchType = NumberMatchType.LesserEqual;
    177                                                 break;
    178                                         default:
    179                                                 matchType = NumberMatchType.Equal;
    180                                                 break;
    181                                 }
    182 
    183                                 return _list.Where (delegate (JsonObject _line) {
    184                                         double objVal = ((JsonNumber) _line [_filterCol]).GetDouble ();
    185                                         switch (matchType) {
    186                                                 case NumberMatchType.Greater:
    187                                                         return objVal > value;
    188                                                 case NumberMatchType.GreaterEqual:
    189                                                         return objVal >= value;
    190                                                 case NumberMatchType.Lesser:
    191                                                         return objVal < value;
    192                                                 case NumberMatchType.LesserEqual:
    193                                                         return objVal <= value;
    194                                                 case NumberMatchType.Equal:
    195                                                 default:
    196                                                         return NearlyEqual (objVal, value, epsilon);
    197                                         }
    198                                 });
    199                         }
    200 
    201                         Log.Out ("[Web] GetPlayerList: ignoring invalid filter for number-column '{0}': '{1}'", _filterCol, _filterVal);
    202                         return _list;
    203                 }
    204 
    205 
    206                 private IEnumerable<JsonObject> ExecuteSort (IEnumerable<JsonObject> _list, string _sortCol, bool _ascending) {
    207                         if (_list.Count () == 0) {
    208                                 return _list;
    209                         }
    210 
    211                         if (_list.First ().ContainsKey (_sortCol)) {
    212                                 Type colType = _list.First () [_sortCol].GetType ();
    213                                 if (colType == typeof (JsonNumber)) {
    214                                         if (_ascending) {
    215                                                 return _list.OrderBy (_line => ((JsonNumber) _line [_sortCol]).GetDouble ());
    216                                         }
    217 
    218                                         return _list.OrderByDescending (_line => ((JsonNumber) _line [_sortCol]).GetDouble ());
    219                                 }
    220 
    221                                 if (colType == typeof (JsonBoolean)) {
    222                                         if (_ascending) {
    223                                                 return _list.OrderBy (_line => ((JsonBoolean) _line [_sortCol]).GetBool ());
    224                                         }
    225 
    226                                         return _list.OrderByDescending (_line => ((JsonBoolean) _line [_sortCol]).GetBool ());
    227                                 }
    228 
    229                                 if (_ascending) {
    230                                         return _list.OrderBy (_line => _line [_sortCol].ToString ());
    231                                 }
    232 
    233                                 return _list.OrderByDescending (_line => _line [_sortCol].ToString ());
    234                         }
    235 
    236                         return _list;
    237                 }
    238 
    239 
    240                 private bool NearlyEqual (double _a, double _b, double _epsilon) {
    241                         double absA = Math.Abs (_a);
    242                         double absB = Math.Abs (_b);
    243                         double diff = Math.Abs (_a - _b);
    244 
    245                         if (_a == _b) {
    246                                 return true;
    247                         }
    248 
    249                         if (_a == 0 || _b == 0 || diff < double.Epsilon) {
    250                                 return diff < _epsilon;
    251                         }
    252 
    253                         return diff / (absA + absB) < _epsilon;
    254                 }
    255 
    256                 private enum NumberMatchType {
    257                         Equal,
    258                         Greater,
    259                         GreaterEqual,
    260                         Lesser,
    261                         LesserEqual
    262                 }
    263         }
    264 }
     1// using System;
     2// using System.Collections.Generic;
     3// using System.Linq;
     4// using System.Text.RegularExpressions;
     5// using AllocsFixes.PersistentData;
     6// using JetBrains.Annotations;
     7//
     8// namespace Webserver.WebAPI.APIs {
     9//      [UsedImplicitly]
     10//      public class GetPlayerList : AbsWebAPI {
     11//              private static readonly Regex numberFilterMatcher =
     12//                      new Regex (@"^(>=|=>|>|<=|=<|<|==|=)?\s*([0-9]+(\.[0-9]*)?)$");
     13//
     14//              private static readonly UnityEngine.Profiling.CustomSampler jsonSerializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Build");
     15//
     16//              public override void HandleRequest (RequestContext _context) {
     17//                      AdminTools admTools = GameManager.Instance.adminTools;
     18//                      PlatformUserIdentifierAbs userId = _context.Connection?.UserId;
     19//
     20//                      bool bViewAll = WebConnection.CanViewAllPlayers (_context.PermissionLevel);
     21//
     22//                      // TODO: Sort (and filter?) prior to converting to JSON ... hard as how to get the correct column's data? (i.e. column name matches JSON object field names, not source data)
     23//
     24//                      int rowsPerPage = 25;
     25//                      if (_context.Request.QueryString ["rowsperpage"] != null) {
     26//                              int.TryParse (_context.Request.QueryString ["rowsperpage"], out rowsPerPage);
     27//                      }
     28//
     29//                      int page = 0;
     30//                      if (_context.Request.QueryString ["page"] != null) {
     31//                              int.TryParse (_context.Request.QueryString ["page"], out page);
     32//                      }
     33//
     34//                      int firstEntry = page * rowsPerPage;
     35//
     36//                      Players playersList = PersistentContainer.Instance.Players;
     37//
     38//                     
     39//                      List<JsonObject> playerList = new List<JsonObject> ();
     40//
     41//                      jsonSerializeSampler.Begin ();
     42//
     43//                      foreach (KeyValuePair<PlatformUserIdentifierAbs, Player> kvp in playersList.Dict) {
     44//                              Player p = kvp.Value;
     45//
     46//                              if (bViewAll || p.PlatformId.Equals (userId)) {
     47//                                      JsonObject pos = new JsonObject ();
     48//                                      pos.Add ("x", new JsonNumber (p.LastPosition.x));
     49//                                      pos.Add ("y", new JsonNumber (p.LastPosition.y));
     50//                                      pos.Add ("z", new JsonNumber (p.LastPosition.z));
     51//
     52//                                      JsonObject pJson = new JsonObject ();
     53//                                      pJson.Add ("steamid", new JsonString (kvp.Key.CombinedString));
     54//                                      pJson.Add ("entityid", new JsonNumber (p.EntityID));
     55//                                      pJson.Add ("ip", new JsonString (p.IP));
     56//                                      pJson.Add ("name", new JsonString (p.Name));
     57//                                      pJson.Add ("online", new JsonBoolean (p.IsOnline));
     58//                                      pJson.Add ("position", pos);
     59//
     60//                                      pJson.Add ("totalplaytime", new JsonNumber (p.TotalPlayTime));
     61//                                      pJson.Add ("lastonline",
     62//                                              new JsonString (p.LastOnline.ToUniversalTime ().ToString ("yyyy-MM-ddTHH:mm:ssZ")));
     63//                                      pJson.Add ("ping", new JsonNumber (p.IsOnline ? p.ClientInfo.ping : -1));
     64//
     65//                                      JsonBoolean banned = admTools != null ? new JsonBoolean (admTools.IsBanned (kvp.Key, out _, out _)) : new JsonBoolean (false);
     66//
     67//                                      pJson.Add ("banned", banned);
     68//
     69//                                      playerList.Add (pJson);
     70//                              }
     71//                      }
     72//
     73//                      jsonSerializeSampler.End ();
     74//
     75//                      IEnumerable<JsonObject> list = playerList;
     76//
     77//                      foreach (string key in _context.Request.QueryString.AllKeys) {
     78//                              if (!string.IsNullOrEmpty (key) && key.StartsWith ("filter[")) {
     79//                                      string filterCol = key.Substring (key.IndexOf ('[') + 1);
     80//                                      filterCol = filterCol.Substring (0, filterCol.Length - 1);
     81//                                      string filterVal = _context.Request.QueryString.Get (key).Trim ();
     82//
     83//                                      list = ExecuteFilter (list, filterCol, filterVal);
     84//                              }
     85//                      }
     86//
     87//                      int totalAfterFilter = list.Count ();
     88//
     89//                      foreach (string key in _context.Request.QueryString.AllKeys) {
     90//                              if (!string.IsNullOrEmpty (key) && key.StartsWith ("sort[")) {
     91//                                      string sortCol = key.Substring (key.IndexOf ('[') + 1);
     92//                                      sortCol = sortCol.Substring (0, sortCol.Length - 1);
     93//                                      string sortVal = _context.Request.QueryString.Get (key);
     94//
     95//                                      list = ExecuteSort (list, sortCol, sortVal == "0");
     96//                              }
     97//                      }
     98//
     99//                      list = list.Skip (firstEntry);
     100//                      list = list.Take (rowsPerPage);
     101//
     102//
     103//                      JsonArray playersJsResult = new JsonArray ();
     104//                      foreach (JsonObject jsO in list) {
     105//                              playersJsResult.Add (jsO);
     106//                      }
     107//
     108//                      JsonObject result = new JsonObject ();
     109//                      result.Add ("total", new JsonNumber (totalAfterFilter));
     110//                      result.Add ("totalUnfiltered", new JsonNumber (playerList.Count));
     111//                      result.Add ("firstResult", new JsonNumber (firstEntry));
     112//                      result.Add ("players", playersJsResult);
     113//
     114//                      WebUtils.WriteJson (_context.Response, result);
     115//              }
     116//
     117//              private IEnumerable<JsonObject> ExecuteFilter (IEnumerable<JsonObject> _list, string _filterCol,
     118//                      string _filterVal) {
     119//                      if (!_list.Any()) {
     120//                              return _list;
     121//                      }
     122//
     123//                      if (_list.First ().ContainsKey (_filterCol)) {
     124//                              Type colType = _list.First () [_filterCol].GetType ();
     125//                              if (colType == typeof (JsonNumber)) {
     126//                                      return ExecuteNumberFilter (_list, _filterCol, _filterVal);
     127//                              }
     128//
     129//                              if (colType == typeof (JsonBoolean)) {
     130//                                      bool value = StringParsers.ParseBool (_filterVal);
     131//                                      return _list.Where (_line => ((JsonBoolean) _line [_filterCol]).GetBool () == value);
     132//                              }
     133//
     134//                              if (colType == typeof (JsonString)) {
     135//                                      // regex-match whole ^string$, replace * by .*, ? by .?, + by .+
     136//                                      _filterVal = _filterVal.Replace ("*", ".*").Replace ("?", ".?").Replace ("+", ".+");
     137//                                      _filterVal = "^" + _filterVal + "$";
     138//
     139//                                      //Log.Out ("GetPlayerList: Filter on String with Regex '" + _filterVal + "'");
     140//                                      Regex matcher = new Regex (_filterVal, RegexOptions.IgnoreCase);
     141//                                      return _list.Where (_line => matcher.IsMatch (((JsonString) _line [_filterCol]).GetString ()));
     142//                              }
     143//                      }
     144//
     145//                      return _list;
     146//              }
     147//
     148//
     149//              private IEnumerable<JsonObject> ExecuteNumberFilter (IEnumerable<JsonObject> _list, string _filterCol,
     150//                      string _filterVal) {
     151//                      // allow value (exact match), =, ==, >=, >, <=, <
     152//                      Match filterMatch = numberFilterMatcher.Match (_filterVal);
     153//                      if (filterMatch.Success) {
     154//                              double value = StringParsers.ParseDouble (filterMatch.Groups [2].Value);
     155//                              NumberMatchType matchType;
     156//                              double epsilon = value / 100000;
     157//                              switch (filterMatch.Groups [1].Value) {
     158//                                      case "":
     159//                                      case "=":
     160//                                      case "==":
     161//                                              matchType = NumberMatchType.Equal;
     162//                                              break;
     163//                                      case ">":
     164//                                              matchType = NumberMatchType.Greater;
     165//                                              break;
     166//                                      case ">=":
     167//                                      case "=>":
     168//                                              matchType = NumberMatchType.GreaterEqual;
     169//                                              break;
     170//                                      case "<":
     171//                                              matchType = NumberMatchType.Lesser;
     172//                                              break;
     173//                                      case "<=":
     174//                                      case "=<":
     175//                                              matchType = NumberMatchType.LesserEqual;
     176//                                              break;
     177//                                      default:
     178//                                              matchType = NumberMatchType.Equal;
     179//                                              break;
     180//                              }
     181//
     182//                              return _list.Where (delegate (JsonObject _line) {
     183//                                      double objVal = ((JsonNumber) _line [_filterCol]).GetDouble ();
     184//                                      switch (matchType) {
     185//                                              case NumberMatchType.Greater:
     186//                                                      return objVal > value;
     187//                                              case NumberMatchType.GreaterEqual:
     188//                                                      return objVal >= value;
     189//                                              case NumberMatchType.Lesser:
     190//                                                      return objVal < value;
     191//                                              case NumberMatchType.LesserEqual:
     192//                                                      return objVal <= value;
     193//                                              case NumberMatchType.Equal:
     194//                                              default:
     195//                                                      return NearlyEqual (objVal, value, epsilon);
     196//                                      }
     197//                              });
     198//                      }
     199//
     200//                      global::Log.Out ("[Web] GetPlayerList: ignoring invalid filter for number-column '{0}': '{1}'", _filterCol, _filterVal);
     201//                      return _list;
     202//              }
     203//
     204//
     205//              private IEnumerable<JsonObject> ExecuteSort (IEnumerable<JsonObject> _list, string _sortCol, bool _ascending) {
     206//                      if (_list.Count () == 0) {
     207//                              return _list;
     208//                      }
     209//
     210//                      if (_list.First ().ContainsKey (_sortCol)) {
     211//                              Type colType = _list.First () [_sortCol].GetType ();
     212//                              if (colType == typeof (JsonNumber)) {
     213//                                      if (_ascending) {
     214//                                              return _list.OrderBy (_line => ((JsonNumber) _line [_sortCol]).GetDouble ());
     215//                                      }
     216//
     217//                                      return _list.OrderByDescending (_line => ((JsonNumber) _line [_sortCol]).GetDouble ());
     218//                              }
     219//
     220//                              if (colType == typeof (JsonBoolean)) {
     221//                                      if (_ascending) {
     222//                                              return _list.OrderBy (_line => ((JsonBoolean) _line [_sortCol]).GetBool ());
     223//                                      }
     224//
     225//                                      return _list.OrderByDescending (_line => ((JsonBoolean) _line [_sortCol]).GetBool ());
     226//                              }
     227//
     228//                              if (_ascending) {
     229//                                      return _list.OrderBy (_line => _line [_sortCol].ToString ());
     230//                              }
     231//
     232//                              return _list.OrderByDescending (_line => _line [_sortCol].ToString ());
     233//                      }
     234//
     235//                      return _list;
     236//              }
     237//
     238//
     239//              private bool NearlyEqual (double _a, double _b, double _epsilon) {
     240//                      double absA = Math.Abs (_a);
     241//                      double absB = Math.Abs (_b);
     242//                      double diff = Math.Abs (_a - _b);
     243//
     244//                      if (_a == _b) {
     245//                              return true;
     246//                      }
     247//
     248//                      if (_a == 0 || _b == 0 || diff < double.Epsilon) {
     249//                              return diff < _epsilon;
     250//                      }
     251//
     252//                      return diff / (absA + absB) < _epsilon;
     253//              }
     254//
     255//              private enum NumberMatchType {
     256//                      Equal,
     257//                      Greater,
     258//                      GreaterEqual,
     259//                      Lesser,
     260//                      LesserEqual
     261//              }
     262//      }
     263// }
  • binary-improvements2/WebServer/src/WebAPI/APIs/GetPlayersLocation.cs

    r401 r402  
    1 using System.Collections.Generic;
    2 using AllocsFixes.JSON;
    3 using AllocsFixes.PersistentData;
    4 using JetBrains.Annotations;
    5 
    6 namespace Webserver.WebAPI {
    7         [UsedImplicitly]
    8         public class GetPlayersLocation : AbsWebAPI {
    9                 public override void HandleRequest (RequestContext _context) {
    10                         AdminTools admTools = GameManager.Instance.adminTools;
    11                         PlatformUserIdentifierAbs reqUserId = _context.Connection?.UserId;
    12 
    13                         bool listOffline = false;
    14                         if (_context.Request.QueryString ["offline"] != null) {
    15                                 bool.TryParse (_context.Request.QueryString ["offline"], out listOffline);
    16                         }
    17 
    18                         bool bViewAll = WebConnection.CanViewAllPlayers (_context.PermissionLevel);
    19 
    20                         JsonArray playersJsResult = new JsonArray ();
    21 
    22                         Players playersList = PersistentContainer.Instance.Players;
    23 
    24                         foreach ((PlatformUserIdentifierAbs userId, Player player) in playersList.Dict) {
    25                                 if (admTools != null) {
    26                                         if (admTools.IsBanned (userId, out _, out _)) {
    27                                                 continue;
    28                                         }
    29                                 }
    30 
    31                                 if (!listOffline && !player.IsOnline) {
    32                                         continue;
    33                                 }
    34 
    35                                 if (!bViewAll && !player.PlatformId.Equals (reqUserId)) {
    36                                         continue;
    37                                 }
    38 
    39                                 JsonObject pos = new JsonObject ();
    40                                 pos.Add ("x", new JsonNumber (player.LastPosition.x));
    41                                 pos.Add ("y", new JsonNumber (player.LastPosition.y));
    42                                 pos.Add ("z", new JsonNumber (player.LastPosition.z));
    43 
    44                                 JsonObject pJson = new JsonObject ();
    45                                 pJson.Add ("steamid", new JsonString (userId.CombinedString));
    46 
    47                                 //                                      pJson.Add("entityid", new JSONNumber (p.EntityID));
    48                                 //                    pJson.Add("ip", new JSONString (p.IP));
    49                                 pJson.Add ("name", new JsonString (player.Name));
    50                                 pJson.Add ("online", new JsonBoolean (player.IsOnline));
    51                                 pJson.Add ("position", pos);
    52 
    53                                 //                                      pJson.Add ("totalplaytime", new JSONNumber (p.TotalPlayTime));
    54                                 //                                      pJson.Add ("lastonline", new JSONString (p.LastOnline.ToString ("s")));
    55                                 //                                      pJson.Add ("ping", new JSONNumber (p.IsOnline ? p.ClientInfo.ping : -1));
    56 
    57                                 playersJsResult.Add (pJson);
    58                         }
    59 
    60                         WebUtils.WriteJson (_context.Response, playersJsResult);
    61                 }
    62         }
    63 }
     1// using AllocsFixes.PersistentData;
     2// using JetBrains.Annotations;
     3//
     4// namespace Webserver.WebAPI.APIs {
     5//      [UsedImplicitly]
     6//      public class GetPlayersLocation : AbsWebAPI {
     7//              public override void HandleRequest (RequestContext _context) {
     8//                      AdminTools admTools = GameManager.Instance.adminTools;
     9//                      PlatformUserIdentifierAbs reqUserId = _context.Connection?.UserId;
     10//
     11//                      bool listOffline = false;
     12//                      if (_context.Request.QueryString ["offline"] != null) {
     13//                              bool.TryParse (_context.Request.QueryString ["offline"], out listOffline);
     14//                      }
     15//
     16//                      bool bViewAll = WebConnection.CanViewAllPlayers (_context.PermissionLevel);
     17//
     18//                      JsonArray playersJsResult = new JsonArray ();
     19//
     20//                      Players playersList = PersistentContainer.Instance.Players;
     21//
     22//                      foreach ((PlatformUserIdentifierAbs userId, Player player) in playersList.Dict) {
     23//                              if (admTools != null) {
     24//                                      if (admTools.IsBanned (userId, out _, out _)) {
     25//                                              continue;
     26//                                      }
     27//                              }
     28//
     29//                              if (!listOffline && !player.IsOnline) {
     30//                                      continue;
     31//                              }
     32//
     33//                              if (!bViewAll && !player.PlatformId.Equals (reqUserId)) {
     34//                                      continue;
     35//                              }
     36//
     37//                              JsonObject pos = new JsonObject ();
     38//                              pos.Add ("x", new JsonNumber (player.LastPosition.x));
     39//                              pos.Add ("y", new JsonNumber (player.LastPosition.y));
     40//                              pos.Add ("z", new JsonNumber (player.LastPosition.z));
     41//
     42//                              JsonObject pJson = new JsonObject ();
     43//                              pJson.Add ("steamid", new JsonString (userId.CombinedString));
     44//
     45//                              //                                      pJson.Add("entityid", new JSONNumber (p.EntityID));
     46//                              //                    pJson.Add("ip", new JSONString (p.IP));
     47//                              pJson.Add ("name", new JsonString (player.Name));
     48//                              pJson.Add ("online", new JsonBoolean (player.IsOnline));
     49//                              pJson.Add ("position", pos);
     50//
     51//                              //                                      pJson.Add ("totalplaytime", new JSONNumber (p.TotalPlayTime));
     52//                              //                                      pJson.Add ("lastonline", new JSONString (p.LastOnline.ToString ("s")));
     53//                              //                                      pJson.Add ("ping", new JSONNumber (p.IsOnline ? p.ClientInfo.ping : -1));
     54//
     55//                              playersJsResult.Add (pJson);
     56//                      }
     57//
     58//                      WebUtils.WriteJson (_context.Response, playersJsResult);
     59//              }
     60//      }
     61// }
  • binary-improvements2/WebServer/src/WebAPI/APIs/GetPlayersOnline.cs

    r401 r402  
    1 using System.Collections.Generic;
    2 using AllocsFixes.JSON;
    3 using AllocsFixes.PersistentData;
    4 using JetBrains.Annotations;
    5 
    6 namespace Webserver.WebAPI {
    7         [UsedImplicitly]
    8         public class GetPlayersOnline : AbsWebAPI {
    9                 public override void HandleRequest (RequestContext _context) {
    10                         JsonArray players = new JsonArray ();
    11 
    12                         World w = GameManager.Instance.World;
    13                         foreach ((int entityId, EntityPlayer entityPlayer) in w.Players.dict) {
    14                                 ClientInfo ci = ConnectionManager.Instance.Clients.ForEntityId (entityId);
    15                                 Player player = PersistentContainer.Instance.Players [ci.InternalId, false];
    16 
    17                                 JsonObject pos = new JsonObject ();
    18                                 pos.Add ("x", new JsonNumber ((int) entityPlayer.GetPosition ().x));
    19                                 pos.Add ("y", new JsonNumber ((int) entityPlayer.GetPosition ().y));
    20                                 pos.Add ("z", new JsonNumber ((int) entityPlayer.GetPosition ().z));
    21 
    22                                 JsonObject p = new JsonObject ();
    23                                 p.Add ("steamid", new JsonString (ci.PlatformId.CombinedString));
    24                                 p.Add ("entityid", new JsonNumber (ci.entityId));
    25                                 p.Add ("ip", new JsonString (ci.ip));
    26                                 p.Add ("name", new JsonString (entityPlayer.EntityName));
    27                                 p.Add ("online", new JsonBoolean (true));
    28                                 p.Add ("position", pos);
    29 
    30                                 p.Add ("level", new JsonNumber (player?.Level ?? -1));
    31                                 p.Add ("health", new JsonNumber (entityPlayer.Health));
    32                                 p.Add ("stamina", new JsonNumber (entityPlayer.Stamina));
    33                                 p.Add ("zombiekills", new JsonNumber (entityPlayer.KilledZombies));
    34                                 p.Add ("playerkills", new JsonNumber (entityPlayer.KilledPlayers));
    35                                 p.Add ("playerdeaths", new JsonNumber (entityPlayer.Died));
    36                                 p.Add ("score", new JsonNumber (entityPlayer.Score));
    37 
    38                                 p.Add ("totalplaytime", new JsonNumber (player?.TotalPlayTime ?? -1));
    39                                 p.Add ("lastonline", new JsonString (player != null ? player.LastOnline.ToString ("s") : string.Empty));
    40                                 p.Add ("ping", new JsonNumber (ci.ping));
    41 
    42                                 players.Add (p);
    43                         }
    44 
    45                         WebUtils.WriteJson (_context.Response, players);
    46                 }
    47         }
    48 }
     1// using AllocsFixes.PersistentData;
     2// using JetBrains.Annotations;
     3//
     4// namespace Webserver.WebAPI.APIs {
     5//      [UsedImplicitly]
     6//      public class GetPlayersOnline : AbsWebAPI {
     7//              public override void HandleRequest (RequestContext _context) {
     8//                      JsonArray players = new JsonArray ();
     9//
     10//                      World w = GameManager.Instance.World;
     11//                      foreach ((int entityId, EntityPlayer entityPlayer) in w.Players.dict) {
     12//                              ClientInfo ci = ConnectionManager.Instance.Clients.ForEntityId (entityId);
     13//                              Player player = PersistentContainer.Instance.Players [ci.InternalId, false];
     14//
     15//                              JsonObject pos = new JsonObject ();
     16//                              pos.Add ("x", new JsonNumber ((int) entityPlayer.GetPosition ().x));
     17//                              pos.Add ("y", new JsonNumber ((int) entityPlayer.GetPosition ().y));
     18//                              pos.Add ("z", new JsonNumber ((int) entityPlayer.GetPosition ().z));
     19//
     20//                              JsonObject p = new JsonObject ();
     21//                              p.Add ("steamid", new JsonString (ci.PlatformId.CombinedString));
     22//                              p.Add ("entityid", new JsonNumber (ci.entityId));
     23//                              p.Add ("ip", new JsonString (ci.ip));
     24//                              p.Add ("name", new JsonString (entityPlayer.EntityName));
     25//                              p.Add ("online", new JsonBoolean (true));
     26//                              p.Add ("position", pos);
     27//
     28//                              p.Add ("level", new JsonNumber (player?.Level ?? -1));
     29//                              p.Add ("health", new JsonNumber (entityPlayer.Health));
     30//                              p.Add ("stamina", new JsonNumber (entityPlayer.Stamina));
     31//                              p.Add ("zombiekills", new JsonNumber (entityPlayer.KilledZombies));
     32//                              p.Add ("playerkills", new JsonNumber (entityPlayer.KilledPlayers));
     33//                              p.Add ("playerdeaths", new JsonNumber (entityPlayer.Died));
     34//                              p.Add ("score", new JsonNumber (entityPlayer.Score));
     35//
     36//                              p.Add ("totalplaytime", new JsonNumber (player?.TotalPlayTime ?? -1));
     37//                              p.Add ("lastonline", new JsonString (player != null ? player.LastOnline.ToString ("s") : string.Empty));
     38//                              p.Add ("ping", new JsonNumber (ci.ping));
     39//
     40//                              players.Add (p);
     41//                      }
     42//
     43//                      WebUtils.WriteJson (_context.Response, players);
     44//              }
     45//      }
     46// }
  • binary-improvements2/WebServer/src/WebAPI/APIs/Hostile.cs

    r401 r402  
    11using System.Collections.Generic;
    2 using AllocsFixes.JSON;
    3 using AllocsFixes.LiveData;
    42using JetBrains.Annotations;
     3using Utf8Json;
     4using Webserver.LiveData;
    55
    6 namespace Webserver.WebAPI {
     6namespace Webserver.WebAPI.APIs {
    77        [UsedImplicitly]
    8         internal class GetHostileLocation : AbsWebAPI {
    9                 private readonly List<EntityEnemy> enemies = new List<EntityEnemy> ();
     8        internal class Hostile : AbsRestApi {
     9                private readonly List<EntityEnemy> entities = new List<EntityEnemy> ();
    1010
    11                 public override void HandleRequest (RequestContext _context) {
    12                         JsonArray hostilesJsResult = new JsonArray ();
     11                private static readonly byte[] jsonKeyId = JsonWriter.GetEncodedPropertyNameWithBeginObject ("id");
     12                private static readonly byte[] jsonKeyName = JsonWriter.GetEncodedPropertyNameWithBeginObject ("name");
     13                private static readonly byte[] jsonKeyPosition = JsonWriter.GetEncodedPropertyNameWithBeginObject ("position");
    1314
    14                         Hostiles.Instance.Get (enemies);
    15                         for (int i = 0; i < enemies.Count; i++) {
    16                                 EntityEnemy entity = enemies [i];
    17                                 Vector3i position = new Vector3i (entity.GetPosition ());
     15                protected override void HandleRestGet (RequestContext _context) {
     16                        PrepareEnvelopedResult (out JsonWriter writer);
     17                        writer.WriteBeginArray ();
     18                       
     19                        lock (entities) {
     20                                Hostiles.Instance.Get (entities);
     21                               
     22                                for (int i = 0; i < entities.Count; i++) {
     23                                        if (i > 0) {
     24                                                writer.WriteValueSeparator ();
     25                                        }
     26                                       
     27                                        EntityAlive entity = entities [i];
     28                                        Vector3i position = new Vector3i (entity.GetPosition ());
     29                                       
     30                                        writer.WriteRaw (jsonKeyId);
     31                                        writer.WriteInt32 (entity.entityId);
     32                                       
     33                                        writer.WriteRaw (jsonKeyName);
     34                                        writer.WriteString (!string.IsNullOrEmpty (entity.EntityName) ? entity.EntityName : $"enemy class #{entity.entityClass}");
     35                                       
     36                                        writer.WriteRaw (jsonKeyPosition);
     37                                        JsonCommons.WritePositionObject (writer, position);
    1838
    19                                 JsonObject jsonPOS = new JsonObject ();
    20                                 jsonPOS.Add ("x", new JsonNumber (position.x));
    21                                 jsonPOS.Add ("y", new JsonNumber (position.y));
    22                                 jsonPOS.Add ("z", new JsonNumber (position.z));
    23 
    24                                 JsonObject pJson = new JsonObject ();
    25                                 pJson.Add ("id", new JsonNumber (entity.entityId));
    26 
    27                                 if (!string.IsNullOrEmpty (entity.EntityName)) {
    28                                         pJson.Add ("name", new JsonString (entity.EntityName));
    29                                 } else {
    30                                         pJson.Add ("name", new JsonString ("enemy class #" + entity.entityClass));
     39                                        writer.WriteEndObject ();
    3140                                }
    32 
    33                                 pJson.Add ("position", jsonPOS);
    34 
    35                                 hostilesJsResult.Add (pJson);
    3641                        }
    37 
    38                         WebUtils.WriteJson (_context.Response, hostilesJsResult);
     42                       
     43                        writer.WriteEndArray ();
     44                        SendEnvelopedResult (_context, ref writer);
    3945                }
    4046        }
  • binary-improvements2/WebServer/src/WebAPI/APIs/Log.cs

    r401 r402  
    11using System.Collections.Generic;
    2 using AllocsFixes.JSON;
    32using JetBrains.Annotations;
     3using Utf8Json;
    44
    5 namespace Webserver.WebAPI {
     5namespace Webserver.WebAPI.APIs {
    66        [UsedImplicitly]
    7         public class GetLog : AbsWebAPI {
    8                 private const int MAX_COUNT = 1000;
     7        public class Log : AbsRestApi {
     8                private const int maxCount = 1000;
     9
     10                private static readonly byte[] jsonKeyEntries = JsonWriter.GetEncodedPropertyNameWithBeginObject ("entries");
     11                private static readonly byte[] jsonKeyFirstLine = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("firstLine");
     12                private static readonly byte[] jsonKeyLastLine = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("lastLine");
     13
     14                private static readonly byte[] jsonMsgKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("msg");
     15                private static readonly byte[] jsonTypeKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("type");
     16                private static readonly byte[] jsonTraceKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("trace");
     17                private static readonly byte[] jsonIsotimeKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("isotime");
     18                private static readonly byte[] jsonUptimeKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("uptime");
    919               
    10                 public override void HandleRequest (RequestContext _context) {
     20                protected override void HandleRestGet (RequestContext _context) {
    1121                        if (_context.Request.QueryString ["count"] == null || !int.TryParse (_context.Request.QueryString ["count"], out int count)) {
    1222                                count = 50;
     
    1727                        }
    1828
    19                         if (count > MAX_COUNT) {
    20                                 count = MAX_COUNT;
     29                        if (count > maxCount) {
     30                                count = maxCount;
    2131                        }
    2232
    23                         if (count < -MAX_COUNT) {
    24                                 count = -MAX_COUNT;
     33                        if (count < -maxCount) {
     34                                count = -maxCount;
    2535                        }
    2636
     
    2838                                firstLine = count > 0 ? LogBuffer.Instance.OldestLine : LogBuffer.Instance.LatestLine;
    2939                        }
    30 
    31                         JsonObject result = new JsonObject ();
    32 
     40                       
     41                        PrepareEnvelopedResult (out JsonWriter writer);
     42                       
     43                        writer.WriteRaw (jsonKeyEntries);
     44                       
    3345                        List<LogBuffer.LogEntry> logEntries = LogBuffer.Instance.GetRange (ref firstLine, count, out int lastLine);
    3446
    35                         JsonArray entries = new JsonArray ();
     47                        writer.WriteBeginArray ();
     48
     49                        bool first = true;
    3650                        foreach (LogBuffer.LogEntry logEntry in logEntries) {
    37                                 JsonObject entry = new JsonObject ();
    38                                 entry.Add ("isotime", new JsonString (logEntry.isoTime));
    39                                 entry.Add ("uptime", new JsonString (logEntry.uptime.ToString ()));
    40                                 entry.Add ("msg", new JsonString (logEntry.message));
    41                                 entry.Add ("trace", new JsonString (logEntry.trace));
    42                                 entry.Add ("type", new JsonString (logEntry.type.ToStringCached ()));
    43                                 entries.Add (entry);
     51                                if (!first) {
     52                                        writer.WriteValueSeparator ();
     53                                }
     54
     55                                first = false;
     56                               
     57                                writer.WriteRaw (jsonMsgKey);
     58                                writer.WriteString (logEntry.message);
     59                               
     60                                writer.WriteRaw (jsonTypeKey);
     61                                writer.WriteString (logEntry.type.ToStringCached ());
     62                               
     63                                writer.WriteRaw (jsonTraceKey);
     64                                writer.WriteString (logEntry.trace);
     65                               
     66                                writer.WriteRaw (jsonIsotimeKey);
     67                                writer.WriteString (logEntry.isoTime);
     68                               
     69                                writer.WriteRaw (jsonUptimeKey);
     70                                writer.WriteString (logEntry.uptime.ToString ());
     71                               
     72                                writer.WriteEndObject ();
    4473                        }
     74                        writer.WriteEndArray ();
    4575
    46                         result.Add ("firstLine", new JsonNumber (firstLine));
    47                         result.Add ("lastLine", new JsonNumber (lastLine));
    48                         result.Add ("entries", entries);
     76                        writer.WriteRaw (jsonKeyFirstLine);
     77                        writer.WriteInt32 (firstLine);
     78                       
     79                        writer.WriteRaw (jsonKeyLastLine);
     80                        writer.WriteInt32 (lastLine);
     81                       
     82                        writer.WriteEndObject ();
    4983
    50                         WebUtils.WriteJson (_context.Response, result);
     84                        SendEnvelopedResult (_context, ref writer);
    5185                }
    5286        }
  • binary-improvements2/WebServer/src/WebAPI/APIs/ServerInfo.cs

    r401 r402  
    1 using System;
    2 using AllocsFixes.JSON;
    31using JetBrains.Annotations;
     2using Utf8Json;
    43
    5 namespace Webserver.WebAPI {
     4namespace Webserver.WebAPI.APIs {
    65        [UsedImplicitly]
    7         public class GetServerInfo : AbsWebAPI {
    8                 public override void HandleRequest (RequestContext _context) {
    9                         JsonObject serverInfo = new JsonObject ();
     6        public class ServerInfo : AbsRestApi {
     7                private static readonly UnityEngine.Profiling.CustomSampler buildSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_ServerInfo_BuildSampler");
    108
     9                private static readonly byte[] keyType = JsonWriter.GetEncodedPropertyNameWithBeginObject ("type");
     10                private static readonly byte[] keyValue = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("value");
     11
     12                private int largestBuffer;
     13
     14                protected override void HandleRestGet (RequestContext _context) {
     15                        buildSampler.Begin ();
     16
     17                        PrepareEnvelopedResult (out JsonWriter writer);
     18                       
     19                        writer.EnsureCapacity (largestBuffer);
     20                        writer.WriteBeginObject ();
     21                       
    1122                        GameServerInfo gsi = ConnectionManager.Instance.LocalServerInfo;
    1223
    13                         foreach (string stringGamePref in Enum.GetNames (typeof (GameInfoString))) {
    14                                 string value = gsi.GetValue ((GameInfoString) Enum.Parse (typeof (GameInfoString), stringGamePref));
     24                        bool first = true;
     25                       
     26                       
    1527
    16                                 JsonObject singleStat = new JsonObject ();
    17                                 singleStat.Add ("type", new JsonString ("string"));
    18                                 singleStat.Add ("value", new JsonString (value));
     28                        foreach (GameInfoString stringGamePref in EnumUtils.Values<GameInfoString> ()) {
     29                                string value = gsi.GetValue (stringGamePref);
    1930
    20                                 serverInfo.Add (stringGamePref, singleStat);
     31                                if (!first) {
     32                                        writer.WriteValueSeparator ();
     33                                }
     34
     35                                first = false;
     36                               
     37                                writer.WriteString (stringGamePref.ToStringCached ());
     38                                writer.WriteNameSeparator ();
     39                               
     40                                writer.WriteRaw (keyType);
     41                                writer.WriteString ("string");
     42                               
     43                                writer.WriteRaw (keyValue);
     44                                writer.WriteString (value);
     45                               
     46                                writer.WriteEndObject ();
    2147                        }
    2248
    23                         foreach (string intGamePref in Enum.GetNames (typeof (GameInfoInt))) {
    24                                 int value = gsi.GetValue ((GameInfoInt) Enum.Parse (typeof (GameInfoInt), intGamePref));
     49                        foreach (GameInfoInt intGamePref in EnumUtils.Values<GameInfoInt> ()) {
     50                                int value = gsi.GetValue (intGamePref);
    2551
    26                                 JsonObject singleStat = new JsonObject ();
    27                                 singleStat.Add ("type", new JsonString ("int"));
    28                                 singleStat.Add ("value", new JsonNumber (value));
     52                                if (!first) {
     53                                        writer.WriteValueSeparator ();
     54                                }
    2955
    30                                 serverInfo.Add (intGamePref, singleStat);
     56                                first = false;
     57                               
     58                                writer.WriteString (intGamePref.ToStringCached ());
     59                                writer.WriteNameSeparator ();
     60                               
     61                                writer.WriteRaw (keyType);
     62                                writer.WriteString ("int");
     63                               
     64                                writer.WriteRaw (keyValue);
     65                                writer.WriteInt32 (value);
     66                               
     67                                writer.WriteEndObject ();
    3168                        }
    3269
    33                         foreach (string boolGamePref in Enum.GetNames (typeof (GameInfoBool))) {
    34                                 bool value = gsi.GetValue ((GameInfoBool) Enum.Parse (typeof (GameInfoBool), boolGamePref));
     70                        foreach (GameInfoBool boolGamePref in EnumUtils.Values<GameInfoBool> ()) {
     71                                bool value = gsi.GetValue (boolGamePref);
    3572
    36                                 JsonObject singleStat = new JsonObject ();
    37                                 singleStat.Add ("type", new JsonString ("bool"));
    38                                 singleStat.Add ("value", new JsonBoolean (value));
     73                                if (!first) {
     74                                        writer.WriteValueSeparator ();
     75                                }
    3976
    40                                 serverInfo.Add (boolGamePref, singleStat);
     77                                first = false;
     78                               
     79                                writer.WriteString (boolGamePref.ToStringCached ());
     80                                writer.WriteNameSeparator ();
     81                               
     82                                writer.WriteRaw (keyType);
     83                                writer.WriteString ("bool");
     84                               
     85                                writer.WriteRaw (keyValue);
     86                                writer.WriteBoolean (value);
     87                               
     88                                writer.WriteEndObject ();
    4189                        }
     90                       
     91                        writer.WriteEndObject ();
     92                       
     93                        buildSampler.End ();
    4294
    43 
    44                         WebUtils.WriteJson (_context.Response, serverInfo);
     95                        int bufferContentSize = writer.CurrentOffset + 128;
     96                        if (bufferContentSize > largestBuffer) {
     97                                largestBuffer = bufferContentSize;
     98                        }
     99                       
     100                        SendEnvelopedResult (_context, ref writer);
    45101                }
    46102        }
  • binary-improvements2/WebServer/src/WebAPI/APIs/ServerStats.cs

    r401 r402  
    1 using AllocsFixes.JSON;
    2 using AllocsFixes.LiveData;
    31using JetBrains.Annotations;
     2using Utf8Json;
     3using Webserver.LiveData;
    44
    5 namespace Webserver.WebAPI {
     5namespace Webserver.WebAPI.APIs {
    66        [UsedImplicitly]
    7         public class GetStats : AbsWebAPI {
    8                 public override void HandleRequest (RequestContext _context) {
    9                         JsonObject result = new JsonObject ();
     7        public class ServerStats : AbsRestApi {
     8                private static readonly byte[] jsonKeyGameTime = JsonWriter.GetEncodedPropertyNameWithBeginObject ("gameTime");
     9                private static readonly byte[] jsonKeyPlayers = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("players");
     10                private static readonly byte[] jsonKeyHostiles = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("hostiles");
     11                private static readonly byte[] jsonKeyAnimals = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("animals");
     12               
     13                private static readonly byte[] jsonKeyDays = JsonWriter.GetEncodedPropertyNameWithBeginObject ("days");
     14                private static readonly byte[] jsonKeyHours = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("hours");
     15                private static readonly byte[] jsonKeyMinutes = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("minutes");
    1016
    11                         JsonObject time = new JsonObject ();
    12                         time.Add ("days", new JsonNumber (GameUtils.WorldTimeToDays (GameManager.Instance.World.worldTime)));
    13                         time.Add ("hours", new JsonNumber (GameUtils.WorldTimeToHours (GameManager.Instance.World.worldTime)));
    14                         time.Add ("minutes", new JsonNumber (GameUtils.WorldTimeToMinutes (GameManager.Instance.World.worldTime)));
    15                         result.Add ("gametime", time);
     17                protected override void HandleRestGet (RequestContext _context) {
     18                        PrepareEnvelopedResult (out JsonWriter writer);
     19                       
     20                        writer.WriteRaw (jsonKeyGameTime);
    1621
    17                         result.Add ("players", new JsonNumber (GameManager.Instance.World.Players.Count));
    18                         result.Add ("hostiles", new JsonNumber (Hostiles.Instance.GetCount ()));
    19                         result.Add ("animals", new JsonNumber (Animals.Instance.GetCount ()));
     22                        (int days, int hours, int minutes) = GameUtils.WorldTimeToElements (GameManager.Instance.World.worldTime);
     23                       
     24                        writer.WriteRaw (jsonKeyDays);
     25                        writer.WriteInt32 (days);
     26                       
     27                        writer.WriteRaw (jsonKeyHours);
     28                        writer.WriteInt32 (hours);
     29                       
     30                        writer.WriteRaw (jsonKeyMinutes);
     31                        writer.WriteInt32 (minutes);
     32                       
     33                        writer.WriteEndObject ();
    2034
    21                         WebUtils.WriteJson (_context.Response, result);
     35                        writer.WriteRaw (jsonKeyPlayers);
     36                        writer.WriteInt32 (GameManager.Instance.World.Players.Count);
     37                       
     38                        writer.WriteRaw (jsonKeyHostiles);
     39                        writer.WriteInt32 (Hostiles.Instance.GetCount ());
     40                       
     41                        writer.WriteRaw (jsonKeyAnimals);
     42                        writer.WriteInt32 (Animals.Instance.GetCount ());
     43                       
     44                        writer.WriteEndObject ();
     45
     46                        SendEnvelopedResult (_context, ref writer);
    2247                }
    2348
  • binary-improvements2/WebServer/src/WebAPI/APIs/WebMods.cs

    r401 r402  
    1 using AllocsFixes.JSON;
    21using JetBrains.Annotations;
     2using Utf8Json;
    33
    4 namespace Webserver.WebAPI {
     4namespace Webserver.WebAPI.APIs {
    55        [UsedImplicitly]
    6         public class GetWebMods : AbsWebAPI {
    7                 private readonly JsonArray loadedWebMods = new JsonArray ();
     6        public class WebMods : AbsRestApi {
     7                private readonly byte[] loadedWebMods;
    88
    9                 public GetWebMods (Web _parent) {
     9                public WebMods (Web _parent) {
     10                        JsonWriter writer = new JsonWriter ();
     11                        writer.WriteBeginArray ();
     12
     13                        bool first = true;
    1014                        foreach (WebMod webMod in _parent.webMods) {
    11                                 JsonObject modJson = new JsonObject ();
     15                                if (!first) {
     16                                        writer.WriteValueSeparator ();
     17                                }
     18                                first = false;
     19                               
     20                                writer.WriteBeginObject ();
     21                               
     22                                writer.WriteString ("name");
     23                                writer.WriteNameSeparator ();
     24                                writer.WriteString (webMod.ParentMod.Name);
    1225
    13                                 modJson.Add ("name", new JsonString (webMod.ParentMod.ModInfo.Name.Value));
    14                                
    1526                                string webModReactBundle = webMod.ReactBundle;
    1627                                if (webModReactBundle != null) {
    17                                         modJson.Add ("bundle", new JsonString (webModReactBundle));
     28                                        writer.WriteValueSeparator ();
     29                                        writer.WriteString ("bundle");
     30                                        writer.WriteNameSeparator ();
     31                                        writer.WriteString (webModReactBundle);
    1832                                }
    19 
     33                               
    2034                                string webModCssFile = webMod.CssPath;
    2135                                if (webModCssFile != null) {
    22                                         modJson.Add ("css", new JsonString (webModCssFile));
     36                                        writer.WriteValueSeparator ();
     37                                        writer.WriteString ("css");
     38                                        writer.WriteNameSeparator ();
     39                                        writer.WriteString (webModCssFile);
    2340                                }
     41                               
     42                                writer.WriteEndObject ();
     43                        }
     44                       
     45                        writer.WriteEndArray ();
    2446
    25                                 loadedWebMods.Add (modJson);
    26                         }
     47                        loadedWebMods = writer.ToUtf8ByteArray ();
    2748                }
    2849
    29                 public override void HandleRequest (RequestContext _context) {
    30                         WebUtils.WriteJson (_context.Response, loadedWebMods);
     50                protected override void HandleRestGet (RequestContext _context) {
     51                        PrepareEnvelopedResult (out JsonWriter writer);
     52                        writer.WriteRaw (loadedWebMods);
     53                        SendEnvelopedResult (_context, ref writer);
    3154                }
    3255
  • binary-improvements2/WebServer/src/WebAPI/APIs/WebUiUpdates.cs

    r401 r402  
    1 using AllocsFixes.JSON;
    2 using AllocsFixes.LiveData;
    31using JetBrains.Annotations;
     2using Utf8Json;
     3using Webserver.LiveData;
    44
    5 namespace Webserver.WebAPI {
     5namespace Webserver.WebAPI.APIs {
    66        [UsedImplicitly]
    7         public class GetWebUIUpdates : AbsWebAPI {
    8                 public override void HandleRequest (RequestContext _context) {
     7        public class WebUiUpdates : AbsRestApi {
     8                private static readonly byte[] jsonKeyGameTime = JsonWriter.GetEncodedPropertyNameWithBeginObject ("gameTime");
     9                private static readonly byte[] jsonKeyPlayers = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("players");
     10                private static readonly byte[] jsonKeyHostiles = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("hostiles");
     11                private static readonly byte[] jsonKeyAnimals = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("animals");
     12                private static readonly byte[] jsonKeyNewLogs = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("newLogs");
     13               
     14                private static readonly byte[] jsonKeyDays = JsonWriter.GetEncodedPropertyNameWithBeginObject ("days");
     15                private static readonly byte[] jsonKeyHours = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("hours");
     16                private static readonly byte[] jsonKeyMinutes = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("minutes");
     17
     18               
     19                protected override void HandleRestGet (RequestContext _context) {
    920                        if (_context.Request.QueryString ["latestLine"] == null ||
    1021                            !int.TryParse (_context.Request.QueryString ["latestLine"], out int latestLine)) {
    1122                                latestLine = 0;
    1223                        }
     24                       
     25                        PrepareEnvelopedResult (out JsonWriter writer);
     26                       
     27                        writer.WriteRaw (jsonKeyGameTime);
    1328
    14                         JsonObject result = new JsonObject ();
     29                        (int days, int hours, int minutes) = GameUtils.WorldTimeToElements (GameManager.Instance.World.worldTime);
     30                       
     31                        writer.WriteRaw (jsonKeyDays);
     32                        writer.WriteInt32 (days);
     33                       
     34                        writer.WriteRaw (jsonKeyHours);
     35                        writer.WriteInt32 (hours);
     36                       
     37                        writer.WriteRaw (jsonKeyMinutes);
     38                        writer.WriteInt32 (minutes);
     39                       
     40                        writer.WriteEndObject ();
    1541
    16                         JsonObject time = new JsonObject ();
    17                         time.Add ("days", new JsonNumber (GameUtils.WorldTimeToDays (GameManager.Instance.World.worldTime)));
    18                         time.Add ("hours", new JsonNumber (GameUtils.WorldTimeToHours (GameManager.Instance.World.worldTime)));
    19                         time.Add ("minutes", new JsonNumber (GameUtils.WorldTimeToMinutes (GameManager.Instance.World.worldTime)));
    20                         result.Add ("gametime", time);
     42                        writer.WriteRaw (jsonKeyPlayers);
     43                        writer.WriteInt32 (GameManager.Instance.World.Players.Count);
     44                       
     45                        writer.WriteRaw (jsonKeyHostiles);
     46                        writer.WriteInt32 (Hostiles.Instance.GetCount ());
     47                       
     48                        writer.WriteRaw (jsonKeyAnimals);
     49                        writer.WriteInt32 (Animals.Instance.GetCount ());
     50                       
     51                        writer.WriteRaw (jsonKeyNewLogs);
     52                        writer.WriteInt32 (LogBuffer.Instance.LatestLine - latestLine);
    2153
    22                         result.Add ("players", new JsonNumber (GameManager.Instance.World.Players.Count));
    23                         result.Add ("hostiles", new JsonNumber (Hostiles.Instance.GetCount ()));
    24                         result.Add ("animals", new JsonNumber (Animals.Instance.GetCount ()));
     54                        writer.WriteEndObject ();
    2555
    26                         result.Add ("newlogs", new JsonNumber (LogBuffer.Instance.LatestLine - latestLine));
    27 
    28                         WebUtils.WriteJson (_context.Response, result);
     56                        SendEnvelopedResult (_context, ref writer);
    2957                }
    3058
  • binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs

    r394 r402  
    11using System;
     2using System.Collections.Generic;
    23using System.IO;
    34using System.Net;
    4 using AllocsFixes.JSON;
     5using Utf8Json;
    56
    67namespace Webserver.WebAPI {
     
    910
    1011                public sealed override void HandleRequest (RequestContext _context) {
    11                         JsonNode jsonBody = null;
     12                        IDictionary<string, object> inputJson = null;
     13                        byte[] jsonInputData = null;
     14                       
     15                        if (_context.Request.HasEntityBody) {
     16                                Stream requestInputStream = _context.Request.InputStream;
     17                               
     18                                jsonInputData = new byte[_context.Request.ContentLength64];
     19                                requestInputStream.Read (jsonInputData, 0, (int)_context.Request.ContentLength64);
     20                               
     21                                try {
     22                                        jsonDeserializeSampler.Begin ();
     23                                        inputJson = JsonSerializer.Deserialize<IDictionary<string, object>> (jsonInputData);
     24                                       
     25                                        // Log.Out ("JSON body:");
     26                                        // foreach ((string key, object value) in inputJson) {
     27                                        //      Log.Out ($" - {key} = {value} ({value.GetType ()})");
     28                                        // }
     29                                       
     30                                        jsonDeserializeSampler.End ();
     31                                } catch (Exception e) {
     32                                        jsonDeserializeSampler.End ();
    1233
    13                         if (_context.Request.HasEntityBody) {
    14                                 string body = new StreamReader (_context.Request.InputStream).ReadToEnd ();
    15 
    16                                 if (!string.IsNullOrEmpty (body)) {
    17                                         try {
    18                                                 jsonDeserializeSampler.Begin ();
    19                                                 jsonBody = Parser.Parse (body);
    20                                                 jsonDeserializeSampler.End ();
    21                                         } catch (Exception e) {
    22                                                 jsonDeserializeSampler.End ();
    23 
    24                                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
    25                                                 return;
    26                                         }
     34                                        SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
     35                                        return;
    2736                                }
    2837                        }
     
    3140                                switch (_context.Request.HttpMethod) {
    3241                                        case "GET":
    33                                                 if (jsonBody != null) {
    34                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "GET_WITH_BODY");
     42                                                if (inputJson != null) {
     43                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "GET_WITH_BODY");
    3544                                                        return;
    3645                                                }
     
    4049                                        case "POST":
    4150                                                if (!string.IsNullOrEmpty (_context.RequestPath)) {
    42                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "POST_WITH_ID");
     51                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "POST_WITH_ID");
    4352                                                        return;
    4453                                                }
    4554
    46                                                 if (jsonBody == null) {
    47                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
     55                                                if (inputJson == null) {
     56                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
    4857                                                        return;
    4958                                                }
    5059
    51                                                 HandleRestPost (_context, jsonBody);
     60                                                HandleRestPost (_context, inputJson, jsonInputData);
    5261                                                return;
    5362                                        case "PUT":
    5463                                                if (string.IsNullOrEmpty (_context.RequestPath)) {
    55                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "PUT_WITHOUT_ID");
     64                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "PUT_WITHOUT_ID");
    5665                                                        return;
    5766                                                }
    5867
    59                                                 if (jsonBody == null) {
    60                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
     68                                                if (inputJson == null) {
     69                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
    6170                                                        return;
    6271                                                }
    6372
    64                                                 HandleRestPut (_context, jsonBody);
     73                                                HandleRestPut (_context, inputJson, jsonInputData);
    6574                                                return;
    6675                                        case "DELETE":
    6776                                                if (string.IsNullOrEmpty (_context.RequestPath)) {
    68                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "DELETE_WITHOUT_ID");
     77                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "DELETE_WITHOUT_ID");
    6978                                                        return;
    7079                                                }
    7180
    72                                                 if (jsonBody != null) {
    73                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
     81                                                if (inputJson != null) {
     82                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
    7483                                                        return;
    7584                                                }
     
    7887                                                return;
    7988                                        default:
    80                                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
     89                                                SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
    8190                                                return;
    8291                                }
    8392                        } catch (Exception e) {
    84                                 SendEnvelopedResult (_context, null, HttpStatusCode.InternalServerError, jsonBody, "ERROR_PROCESSING", e);
     93                                SendErrorResult (_context, HttpStatusCode.InternalServerError, jsonInputData, "ERROR_PROCESSING", e);
    8594                        }
    8695                }
    8796
    88                 private static readonly JsonArray emptyData = new JsonArray ();
    89 
    90                 protected void SendEnvelopedResult (RequestContext _context, JsonNode _resultData, HttpStatusCode _statusCode = HttpStatusCode.OK,
    91                         JsonNode _jsonInputBody = null, string _errorCode = null, Exception _exception = null) {
    92                         JsonObject meta = new JsonObject ();
    93 
    94                         meta.Add ("serverTime", new JsonString (DateTime.Now.ToString ("o")));
    95                         if (!string.IsNullOrEmpty (_errorCode)) {
    96                                 meta.Add ("requestMethod", new JsonString (_context.Request.HttpMethod));
    97                                 meta.Add ("requestSubpath", new JsonString (_context.RequestPath));
    98                                 meta.Add ("requestBody", new JsonString (_jsonInputBody?.ToString () ?? "-empty-"));
    99                                 meta.Add ("errorCode", new JsonString (_errorCode));
    100                                 if (_exception != null) {
    101                                         meta.Add ("exceptionMessage", new JsonString (_exception.Message));
    102                                         meta.Add ("exceptionTrace", new JsonString (_exception.StackTrace));
    103                                 }
    104                         }
    105 
    106                         JsonObject envelope = new JsonObject ();
    107                         envelope.Add ("meta", meta);
    108                         envelope.Add ("data", _resultData ?? emptyData);
    109 
    110                         WebUtils.WriteJson (_context.Response, envelope, _statusCode);
     97                protected void SendErrorResult (RequestContext _context, HttpStatusCode _statusCode, byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
     98                        PrepareEnvelopedResult (out JsonWriter writer);
     99                        writer.WriteRaw (JsonEmptyData);
     100                        SendEnvelopedResult (_context, ref writer, _statusCode, _jsonInputData, _errorCode, _exception);
    111101                }
    112102
    113                 protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out int _value) {
     103                static AbsRestApi () {
     104                        JsonWriter writer = new JsonWriter ();
     105                        writer.WriteBeginArray ();
     106                        writer.WriteEndArray ();
     107                        JsonEmptyData = writer.ToUtf8ByteArray ();
     108                }
     109
     110                protected static readonly byte[] JsonEmptyData;
     111               
     112                protected void PrepareEnvelopedResult (out JsonWriter _writer) {
     113                        WebUtils.PrepareEnvelopedResult (out _writer);
     114                }
     115
     116                protected void SendEnvelopedResult (RequestContext _context, ref JsonWriter _writer, HttpStatusCode _statusCode = HttpStatusCode.OK,
     117                        byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
     118                       
     119                        WebUtils.SendEnvelopedResult (_context, ref _writer, _statusCode, _jsonInputData, _errorCode, _exception);
     120                }
     121
     122                protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out int _value) {
    114123                        _value = default;
    115124                       
    116                         if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
     125                        if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
    117126                                return false;
    118127                        }
    119128
    120                         if (!(fieldNode is JsonValue valueField)) {
     129                        if (fieldNode is not double value) {
    121130                                return false;
    122131                        }
    123132
    124133                        try {
    125                                 _value = valueField.AsInt;
     134                                _value = (int)value;
    126135                                return true;
    127136                        } catch (Exception) {
     
    130139                }
    131140
    132                 protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out double _value) {
     141                protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out double _value) {
    133142                        _value = default;
    134143                       
    135                         if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
     144                        if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
    136145                                return false;
    137146                        }
    138147
    139                         if (!(fieldNode is JsonValue valueField)) {
     148                        if (fieldNode is not double value) {
    140149                                return false;
    141150                        }
    142151
    143152                        try {
    144                                 _value = valueField.AsDouble;
     153                                _value = value;
    145154                                return true;
    146155                        } catch (Exception) {
     
    149158                }
    150159
    151                 protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out string _value) {
     160                protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out string _value) {
    152161                        _value = default;
    153162                       
    154                         if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
     163                        if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
    155164                                return false;
    156165                        }
    157166
    158                         if (!(fieldNode is JsonValue valueField)) {
     167                        if (fieldNode is not string value) {
    159168                                return false;
    160169                        }
    161170
    162171                        try {
    163                                 _value = valueField.AsString;
     172                                _value = value;
    164173                                return true;
    165174                        } catch (Exception) {
     
    168177                }
    169178
    170                 protected abstract void HandleRestGet (RequestContext _context);
     179                protected virtual void HandleRestGet (RequestContext _context) {
     180                        SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
     181                }
    171182
    172                 protected abstract void HandleRestPost (RequestContext _context, JsonNode _jsonBody);
     183                protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
     184                        SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
     185                }
    173186
    174                 protected abstract void HandleRestPut (RequestContext _context, JsonNode _jsonBody);
     187                protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
     188                        SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
     189                }
    175190
    176                 protected abstract void HandleRestDelete (RequestContext _context);
     191                protected virtual void HandleRestDelete (RequestContext _context) {
     192                        SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
     193                }
    177194        }
    178195}
  • binary-improvements2/WebServer/src/WebCommandResult.cs

    r399 r402  
    44using System.Net.Sockets;
    55using System.Text;
    6 using AllocsFixes.JSON;
    76using UnityEngine;
    8 using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
     7using Utf8Json;
    98
    109namespace Webserver {
     
    1918                private readonly string parameters;
    2019
    21                 private readonly HttpListenerResponse response;
     20                private readonly RequestContext context;
    2221                private readonly ResultType responseType;
    2322
    24                 public WebCommandResult (string _command, string _parameters, ResultType _responseType, HttpListenerResponse _response) {
    25                         response = _response;
     23                public WebCommandResult (string _command, string _parameters, ResultType _responseType, RequestContext _context) {
     24                        context = _context;
    2625                        command = _command;
    2726                        parameters = _parameters;
     
    2928                }
    3029
     30                private static readonly byte[] jsonRawKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("resultRaw");
     31               
     32                private static readonly byte[] jsonCommandKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("command");
     33                private static readonly byte[] jsonParametersKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("parameters");
     34                private static readonly byte[] jsonResultKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("result");
     35               
    3136                public void SendLines (List<string> _output) {
    3237                        StringBuilder sb = new StringBuilder ();
     
    3540                        }
    3641
     42                        string commandOutput = sb.ToString ();
     43
    3744                        try {
    38                                 response.SendChunked = false;
    39 
    4045                                if (responseType == ResultType.Raw) {
    41                                         WebUtils.WriteText (response, sb.ToString ());
     46                                        WebUtils.WriteText (context.Response, commandOutput);
    4247                                } else {
    43                                         JsonNode result;
     48                                        WebUtils.PrepareEnvelopedResult (out JsonWriter writer);
     49                       
    4450                                        if (responseType == ResultType.ResultOnly) {
    45                                                 result = new JsonString (sb.ToString ());
     51                                                writer.WriteRaw (jsonRawKey);
     52                                                writer.WriteString (commandOutput);
     53                                                writer.WriteEndObject ();
    4654                                        } else {
    47                                                 JsonObject resultObj = new JsonObject ();
    48 
    49                                                 resultObj.Add ("command", new JsonString (command));
    50                                                 resultObj.Add ("parameters", new JsonString (parameters));
    51                                                 resultObj.Add ("result", new JsonString (sb.ToString ()));
    52 
    53                                                 result = resultObj;
     55                                                writer.WriteRaw (jsonCommandKey);
     56                                                writer.WriteString (command);
     57                                               
     58                                                writer.WriteRaw (jsonParametersKey);
     59                                                writer.WriteString (parameters);
     60                                               
     61                                                writer.WriteRaw (jsonResultKey);
     62                                                writer.WriteString (commandOutput);
     63                                               
     64                                                writer.WriteEndObject ();
    5465                                        }
    5566
    56                                         WebUtils.WriteJson (response, result);
     67                                        WebUtils.SendEnvelopedResult (context, ref writer);
    5768                                }
    5869                        } catch (IOException e) {
    5970                                if (e.InnerException is SocketException) {
    60                                         Log.Warning ("[Web] Error in WebCommandResult.SendLines(): Remote host closed connection: " + e.InnerException.Message);
     71                                        Log.Warning ($"[Web] Error in WebCommandResult.SendLines(): Remote host closed connection: {e.InnerException.Message}");
    6172                                } else {
    62                                         Log.Warning ("[Web] Error (IO) in WebCommandResult.SendLines(): " + e);
     73                                        Log.Warning ($"[Web] Error (IO) in WebCommandResult.SendLines(): {e}");
    6374                                }
    6475                        } catch (Exception e) {
    65                                 Log.Warning ("[Web] Error in WebCommandResult.SendLines(): " + e);
     76                                Log.Warning ($"[Web] Error in WebCommandResult.SendLines(): {e}");
    6677                        } finally {
    67                                 response?.Close ();
     78                                context?.Response?.Close ();
    6879                        }
    6980                }
     
    8293
    8394                public string GetDescription () {
    84                         return "WebCommandResult_for_" + command;
     95                        return $"WebCommandResult_for_{command}";
    8596                }
    8697        }
  • binary-improvements2/WebServer/src/WebConnection.cs

    r391 r402  
    2525                        login = DateTime.Now;
    2626                        lastAction = login;
    27                         conDescription = "WebPanel from " + Endpoint;
     27                        conDescription = $"WebPanel from {Endpoint}";
    2828                }
    2929
  • binary-improvements2/WebServer/src/WebMod.cs

    r391 r402  
    11using System.IO;
    2 using AllocsFixes.FileCache;
     2using Webserver.FileCache;
    33using Webserver.UrlHandlers;
    44
     
    1414
    1515                public WebMod (Web _parentWeb, Mod _parentMod, bool _useStaticCache) {
    16                         string folder = _parentMod.Path + "/WebMod";
     16                        string folder = $"{_parentMod.Path}/WebMod";
    1717                        if (!Directory.Exists (folder)) {
    1818                                throw new InvalidDataException("No WebMod folder in mod");
     
    2121                        string urlWebModBase = $"{modsBaseUrl}{_parentMod.FolderName}/";
    2222
    23                         ReactBundle = folder + "/" + reactBundleName;
    24                         if (File.Exists (ReactBundle)) {
    25                                 ReactBundle = urlWebModBase + reactBundleName;
    26                         } else {
    27                                 ReactBundle = null;
    28                         }
     23                        ReactBundle = $"{folder}/{reactBundleName}";
     24                        ReactBundle = File.Exists (ReactBundle) ? $"{urlWebModBase}{reactBundleName}" : null;
    2925
    30                         CssPath = folder + "/" + stylingFileName;
    31                         if (File.Exists (CssPath)) {
    32                                 CssPath = urlWebModBase + stylingFileName;
    33                         } else {
    34                                 CssPath = null;
    35                         }
     26                        CssPath = $"{folder}/{stylingFileName}";
     27                        CssPath = File.Exists (CssPath) ? $"{urlWebModBase}{stylingFileName}" : null;
    3628
    3729                        if (ReactBundle == null && CssPath == null) {
     
    4335                        _parentWeb.RegisterPathHandler (urlWebModBase, new StaticHandler (
    4436                                folder,
    45                                 _useStaticCache ? (AbstractCache) new SimpleCache () : new DirectAccess (),
     37                                _useStaticCache ? new SimpleCache () : new DirectAccess (),
    4638                                false)
    4739                        );
  • binary-improvements2/WebServer/src/WebPermissions.cs

    r399 r402  
    3636                private readonly ReadOnlyCollection<WebModulePermission> allModulesListRo;
    3737
    38                 private static string SettingsFilePath => GamePrefs.GetString (EnumUtils.Parse<EnumGamePrefs> ("SaveGameFolder"));
     38                private static string SettingsFilePath => GamePrefs.GetString (EnumUtils.Parse<EnumGamePrefs> (nameof (EnumGamePrefs.SaveGameFolder)));
    3939                private static string SettingsFileName => permissionsFileName;
    40                 private static string SettingsFullPath => SettingsFilePath + "/" + SettingsFileName;
     40                private static string SettingsFullPath => $"{SettingsFilePath}/{SettingsFileName}";
    4141
    4242                private WebPermissions () {
     
    184184
    185185                private void OnFileChanged (object _source, FileSystemEventArgs _e) {
    186                         Log.Out ("[Web] [Perms] Reloading " + SettingsFileName);
     186                        Log.Out ($"[Web] [Perms] Reloading {SettingsFileName}");
    187187                        Load ();
    188188                }
     
    205205                                xmlDoc.Load (SettingsFullPath);
    206206                        } catch (XmlException e) {
    207                                 Log.Error ("[Web] [Perms] Failed loading permissions file: " + e.Message);
     207                                Log.Error ($"[Web] [Perms] Failed loading permissions file: {e.Message}");
    208208                                return;
    209209                        }
  • binary-improvements2/WebServer/src/WebUtils.cs

    r394 r402  
    11using System;
     2using System.Diagnostics.CodeAnalysis;
    23using System.Net;
    34using System.Text;
    4 using AllocsFixes.JSON;
     5using Utf8Json;
    56using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
    67using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
     
    89namespace Webserver {
    910        public static class WebUtils {
     11                // ReSharper disable once MemberCanBePrivate.Global
    1012                public const string MimePlain = "text/plain";
    1113                public const string MimeHtml = "text/html";
     14                // ReSharper disable once MemberCanBePrivate.Global
    1215                public const string MimeJson = "application/json";
    1316               
    14                 private static readonly UnityEngine.Profiling.CustomSampler jsonSerializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Serialize");
     17                private static readonly UnityEngine.Profiling.CustomSampler envelopeBuildSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_EnvelopeBuilding");
    1518                private static readonly UnityEngine.Profiling.CustomSampler netWriteSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Write");
    16 
    17                 public static void WriteJson (HttpListenerResponse _resp, JsonNode _root, HttpStatusCode _statusCode = HttpStatusCode.OK) {
    18                         jsonSerializeSampler.Begin ();
    19                         StringBuilder sb = new StringBuilder ();
    20                         _root.ToString (sb);
    21                         jsonSerializeSampler.End ();
    22                         netWriteSampler.Begin ();
    23                         WriteText (_resp, sb.ToString(), _statusCode, MimeJson);
    24                         netWriteSampler.End ();
    25                 }
    2619
    2720                public static void WriteText (HttpListenerResponse _resp, string _text, HttpStatusCode _statusCode = HttpStatusCode.OK, string _mimeType = null) {
     
    4336                        return Guid.NewGuid ().ToString ();
    4437                }
     38
     39                [SuppressMessage ("ReSharper", "MemberCanBePrivate.Global")]
     40                public static void WriteJsonData (HttpListenerResponse _resp, ref JsonWriter _jsonWriter, HttpStatusCode _statusCode = HttpStatusCode.OK) {
     41                        ArraySegment<byte> jsonData = _jsonWriter.GetBuffer ();
     42
     43                        netWriteSampler.Begin ();
     44                        _resp.StatusCode = (int)_statusCode;
     45                        _resp.ContentType = MimeJson;
     46                        _resp.ContentEncoding = Encoding.UTF8;
     47                        _resp.ContentLength64 = jsonData.Count;
     48                        _resp.OutputStream.Write (jsonData.Array!, 0, jsonData.Count);
     49                        netWriteSampler.End ();
     50                }
     51               
     52               
     53                private static readonly byte[] jsonRawDataKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("data"); // {"data":
     54
     55                private static readonly byte[] jsonRawMetaKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("meta"); // ,"meta":
     56                private static readonly byte[] jsonRawMetaServertimeKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("serverTime"); // {"serverTime":
     57                private static readonly byte[] jsonRawMetaRequestMethodKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("requestMethod"); // ,"requestMethod":
     58                private static readonly byte[] jsonRawMetaRequestSubpathKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("requestSubpath"); // ,"requestSubpath":
     59                private static readonly byte[] jsonRawMetaRequestBodyKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("requestBody"); // ,"requestBody":
     60                private static readonly byte[] jsonRawMetaErrorCodeKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("errorCode"); // ,"errorCode":
     61                private static readonly byte[] jsonRawMetaExceptionMessageKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("exceptionMessage"); // ,"exceptionMessage":
     62                private static readonly byte[] jsonRawMetaExceptionTraceKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("exceptionTrace"); // ,"exceptionTrace":
     63               
     64                public static void PrepareEnvelopedResult (out JsonWriter _writer) {
     65                        _writer = new JsonWriter ();
     66                        _writer.WriteRaw (jsonRawDataKey);
     67                }
     68
     69                public static void SendEnvelopedResult (RequestContext _context, ref JsonWriter _writer, HttpStatusCode _statusCode = HttpStatusCode.OK,
     70                        byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
     71                       
     72                        envelopeBuildSampler.Begin ();
     73                       
     74                        _writer.WriteRaw (jsonRawMetaKey);
     75
     76                        _writer.WriteRaw (jsonRawMetaServertimeKey);
     77                        _writer.WriteString (DateTime.Now.ToString ("o"));
     78
     79                        if (!string.IsNullOrEmpty (_errorCode)) {
     80                                _writer.WriteRaw (jsonRawMetaRequestMethodKey);
     81                                _writer.WriteString (_context.Request.HttpMethod);
     82
     83                                _writer.WriteRaw (jsonRawMetaRequestSubpathKey);
     84                                _writer.WriteString (_context.RequestPath);
     85
     86                                _writer.WriteRaw (jsonRawMetaRequestBodyKey);
     87                                if (_jsonInputData != null) {
     88                                        _writer.WriteRaw (_jsonInputData);
     89                                } else {
     90                                        _writer.WriteNull ();
     91                                }
     92
     93                                _writer.WriteRaw (jsonRawMetaErrorCodeKey);
     94                                _writer.WriteString (_errorCode);
     95
     96                                if (_exception != null) {
     97                                        _writer.WriteRaw (jsonRawMetaExceptionMessageKey);
     98                                        _writer.WriteString (_exception.Message);
     99
     100                                        _writer.WriteRaw (jsonRawMetaExceptionTraceKey);
     101                                        _writer.WriteString (_exception.StackTrace);
     102                                }
     103                        }
     104                       
     105                        _writer.WriteEndObject (); // End of "meta" object
     106                        _writer.WriteEndObject (); // End of overall result object
     107                       
     108                        envelopeBuildSampler.End ();
     109
     110                        WriteJsonData (_context.Response, ref _writer, _statusCode);
     111                }
    45112        }
    46113}
Note: See TracChangeset for help on using the changeset viewer.