diff --git a/.gitignore b/.gitignore index c41f64e68..c9b670eef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,11 @@ -RunUO.exe -RunUO.exe.config -RunUO.pdb -RunUO.vshost.exe -RunUO.vshost.exe.config +ModernUO +ModernUO.exe +ModernUO.exe.config +ModernUO.dll +ModernUO.dll.config +ModernUO.*.json +ModernUO.pdb +/Assemblies /Logs/ /Scripts/bin/ /Scripts/obj/ @@ -13,13 +16,8 @@ RunUO.vshost.exe.config *.user *.suo /.idea +/.vs /Backups /Saves -/packages -/.vs -/roslyn -Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll -Microsoft.CodeDom.Providers.DotNetCompilerPlatform.xml - .DS_Store diff --git a/Data/Assemblies.cfg b/Data/Assemblies.cfg deleted file mode 100644 index 5af4836c2..000000000 --- a/Data/Assemblies.cfg +++ /dev/null @@ -1,7 +0,0 @@ -System.dll -System.Core.dll -System.Data.dll -System.Drawing.dll -System.Web.dll -System.Windows.Forms.dll -System.Xml.dll \ No newline at end of file diff --git a/ModernUO.sln b/ModernUO.sln new file mode 100644 index 000000000..e1724b1e1 --- /dev/null +++ b/ModernUO.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29102.190 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{5E93BB35-3661-4822-9A8A-859726BAD87F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scripts", "Scripts\Scripts.csproj", "{83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5E93BB35-3661-4822-9A8A-859726BAD87F}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {5E93BB35-3661-4822-9A8A-859726BAD87F}.Debug|Any CPU.Build.0 = Release|Any CPU + {5E93BB35-3661-4822-9A8A-859726BAD87F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E93BB35-3661-4822-9A8A-859726BAD87F}.Release|Any CPU.Build.0 = Release|Any CPU + {83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Debug|Any CPU.Build.0 = Release|Any CPU + {83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83CF2484-BCCB-4B7C-9C5F-7AB43AEA5E8F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8F69EF13-E193-40B9-BA9F-4862A9F0C038} + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md index ec71f975e..41f6c9bf3 100644 --- a/README.md +++ b/README.md @@ -8,26 +8,15 @@ ModernUO - See [Goals](./GOALS.md) ### Requirements -- .NET Framework 4.7 or Mono 5.10+ +- .NET Core 3.0 (Preview 7) or newer - zlib (Linux only) -- [DotNetCompilerPlatform](https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform) v2.0+ (Windows Only) -### Building using Visual Studio (Recommended) -- Build `Server` project - - Building with Visual Studio for Windows will install `DotNetCompilerPlatform` automatically. +### Building with Visual Studio 2019 +- Publish `Server` project +- Build `Scripts` project -### Building for Windows (Without Visual Studio) -`C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc /optimize /unsafe /t:exe /out:RunUO.exe /win32icon:Server\runuo.ico /d:NEWTIMERS /recurse:Server\\*.cs` -- DotNetCompilerPlatform must be installed with the `csc.exe` file in the `roslyn` folder at the root of the repository. - -### Building for Mac/Linux (Without Visual Studio) -`mcs -optimize+ -unsafe -t:exe -out:RunUO.exe -win32icon:Server/runuo.ico -nowarn:219,414 -d:NEWTIMERS -d:MONO -recurse:"Server/*".cs` - -### Running on Mac/Linux (MONO) -`mono RunUO.exe` +### Building with .NET Core 3.0 SDK +`dotnet publish /p:PublishProfile=` +- OS must be `Windows`, `Linux`, or `OSX` ### Troubleshooting / FAQ - -#### Scripts fail to compile on Windows -This is usually caused nuget packages not being installed. Install the required packages and rebuild the Server project. -Note: The required nuget packages can be set to automatically restore on build with this [setting](https://docs.microsoft.com/en-us/nuget/consume-packages/media/restore-01-autorestoreoptions.png) diff --git a/RunUO.sln b/RunUO.sln deleted file mode 100644 index 036ea1603..000000000 --- a/RunUO.sln +++ /dev/null @@ -1,257 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{0B33CEEB-88E1-49A6-8D7D-AF6A5A357087}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scripts", "Scripts\Scripts.csproj", "{DAE872E6-6899-427C-A75D-AD52526EBCDA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Data", "Data", "{1B394627-C6BF-447D-8CBD-4A3B5262C5B4}" - ProjectSection(SolutionItems) = preProject - Data\Assemblies.cfg = Data\Assemblies.cfg - Data\bodyTable.cfg = Data\bodyTable.cfg - Data\Common.map = Data\Common.map - Data\containers.cfg = Data\containers.cfg - Data\items.cfg = Data\items.cfg - Data\MLQuests.cfg = Data\MLQuests.cfg - Data\mobiles.cfg = Data\mobiles.cfg - Data\models.txt = Data\models.txt - Data\names.xml = Data\names.xml - Data\objects.xml = Data\objects.xml - Data\pageresponse.cfg = Data\pageresponse.cfg - Data\Regions.xml = Data\Regions.xml - Data\shrink.cfg = Data\shrink.cfg - Data\signs.cfg = Data\signs.cfg - Data\SpawnDefinitions.xml = Data\SpawnDefinitions.xml - Data\treasure.cfg = Data\treasure.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Binary", "Binary", "{0BC3F1F5-95F7-4048-8BA1-71F2430104D8}" - ProjectSection(SolutionItems) = preProject - Data\Binary\Bounds.bin = Data\Binary\Bounds.bin - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Bulk Orders", "Bulk Orders", "{3CA15B59-8702-42FE-9980-54F8335CE149}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Blacksmith", "Blacksmith", "{D990829A-479F-4377-B0C2-FD7C795C4D28}" - ProjectSection(SolutionItems) = preProject - Data\Bulk Orders\Blacksmith\armor.cfg = Data\Bulk Orders\Blacksmith\armor.cfg - Data\Bulk Orders\Blacksmith\largeaxes.cfg = Data\Bulk Orders\Blacksmith\largeaxes.cfg - Data\Bulk Orders\Blacksmith\largechain.cfg = Data\Bulk Orders\Blacksmith\largechain.cfg - Data\Bulk Orders\Blacksmith\largefencing.cfg = Data\Bulk Orders\Blacksmith\largefencing.cfg - Data\Bulk Orders\Blacksmith\largemaces.cfg = Data\Bulk Orders\Blacksmith\largemaces.cfg - Data\Bulk Orders\Blacksmith\largeplate.cfg = Data\Bulk Orders\Blacksmith\largeplate.cfg - Data\Bulk Orders\Blacksmith\largepolearms.cfg = Data\Bulk Orders\Blacksmith\largepolearms.cfg - Data\Bulk Orders\Blacksmith\largering.cfg = Data\Bulk Orders\Blacksmith\largering.cfg - Data\Bulk Orders\Blacksmith\largeswords.cfg = Data\Bulk Orders\Blacksmith\largeswords.cfg - Data\Bulk Orders\Blacksmith\weapons.cfg = Data\Bulk Orders\Blacksmith\weapons.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tailoring", "Tailoring", "{2C58085D-5E30-4FB4-A71C-FD0328C60558}" - ProjectSection(SolutionItems) = preProject - Data\Bulk Orders\Tailoring\boneset.cfg = Data\Bulk Orders\Tailoring\boneset.cfg - Data\Bulk Orders\Tailoring\cloth.cfg = Data\Bulk Orders\Tailoring\cloth.cfg - Data\Bulk Orders\Tailoring\farmer.cfg = Data\Bulk Orders\Tailoring\farmer.cfg - Data\Bulk Orders\Tailoring\femaleleatherset.cfg = Data\Bulk Orders\Tailoring\femaleleatherset.cfg - Data\Bulk Orders\Tailoring\fishergirl.cfg = Data\Bulk Orders\Tailoring\fishergirl.cfg - Data\Bulk Orders\Tailoring\gypsy.cfg = Data\Bulk Orders\Tailoring\gypsy.cfg - Data\Bulk Orders\Tailoring\hatset.cfg = Data\Bulk Orders\Tailoring\hatset.cfg - Data\Bulk Orders\Tailoring\jester.cfg = Data\Bulk Orders\Tailoring\jester.cfg - Data\Bulk Orders\Tailoring\lady.cfg = Data\Bulk Orders\Tailoring\lady.cfg - Data\Bulk Orders\Tailoring\leather.cfg = Data\Bulk Orders\Tailoring\leather.cfg - Data\Bulk Orders\Tailoring\maleleatherset.cfg = Data\Bulk Orders\Tailoring\maleleatherset.cfg - Data\Bulk Orders\Tailoring\pirate.cfg = Data\Bulk Orders\Tailoring\pirate.cfg - Data\Bulk Orders\Tailoring\shoeset.cfg = Data\Bulk Orders\Tailoring\shoeset.cfg - Data\Bulk Orders\Tailoring\studdedset.cfg = Data\Bulk Orders\Tailoring\studdedset.cfg - Data\Bulk Orders\Tailoring\towncrier.cfg = Data\Bulk Orders\Tailoring\towncrier.cfg - Data\Bulk Orders\Tailoring\wizard.cfg = Data\Bulk Orders\Tailoring\wizard.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Components", "Components", "{4883A0CC-9D0C-4045-AC24-2A2FEAF09B88}" - ProjectSection(SolutionItems) = preProject - Data\Components\doors.txt = Data\Components\doors.txt - Data\Components\floors.txt = Data\Components\floors.txt - Data\Components\misc.txt = Data\Components\misc.txt - Data\Components\roof.txt = Data\Components\roof.txt - Data\Components\stairs.txt = Data\Components\stairs.txt - Data\Components\suppinfo.txt = Data\Components\suppinfo.txt - Data\Components\teleprts.txt = Data\Components\teleprts.txt - Data\Components\walls.txt = Data\Components\walls.txt - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decoration", "Decoration", "{F1E91339-C2F1-40B7-80D0-6289228168D0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Britannia", "Britannia", "{D4052FE1-A0C6-486C-B972-348945894772}" - ProjectSection(SolutionItems) = preProject - Data\Decoration\Britannia\_covetous.cfg = Data\Decoration\Britannia\_covetous.cfg - Data\Decoration\Britannia\_deceit.cfg = Data\Decoration\Britannia\_deceit.cfg - Data\Decoration\Britannia\_despise.cfg = Data\Decoration\Britannia\_despise.cfg - Data\Decoration\Britannia\_destard.cfg = Data\Decoration\Britannia\_destard.cfg - Data\Decoration\Britannia\_fire.cfg = Data\Decoration\Britannia\_fire.cfg - Data\Decoration\Britannia\_hedgemaze.cfg = Data\Decoration\Britannia\_hedgemaze.cfg - Data\Decoration\Britannia\_hythloth.cfg = Data\Decoration\Britannia\_hythloth.cfg - Data\Decoration\Britannia\_ice.cfg = Data\Decoration\Britannia\_ice.cfg - Data\Decoration\Britannia\_orccave.cfg = Data\Decoration\Britannia\_orccave.cfg - Data\Decoration\Britannia\_shame.cfg = Data\Decoration\Britannia\_shame.cfg - Data\Decoration\Britannia\_terathankeep.cfg = Data\Decoration\Britannia\_terathankeep.cfg - Data\Decoration\Britannia\_wrong.cfg = Data\Decoration\Britannia\_wrong.cfg - Data\Decoration\Britannia\britain.cfg = Data\Decoration\Britannia\britain.cfg - Data\Decoration\Britannia\bucs.cfg = Data\Decoration\Britannia\bucs.cfg - Data\Decoration\Britannia\bucsportal.cfg = Data\Decoration\Britannia\bucsportal.cfg - Data\Decoration\Britannia\cove.cfg = Data\Decoration\Britannia\cove.cfg - Data\Decoration\Britannia\delucia.cfg = Data\Decoration\Britannia\delucia.cfg - Data\Decoration\Britannia\despise.cfg = Data\Decoration\Britannia\despise.cfg - Data\Decoration\Britannia\destard.cfg = Data\Decoration\Britannia\destard.cfg - Data\Decoration\Britannia\hythloth.cfg = Data\Decoration\Britannia\hythloth.cfg - Data\Decoration\Britannia\jhelom.cfg = Data\Decoration\Britannia\jhelom.cfg - Data\Decoration\Britannia\magincia.cfg = Data\Decoration\Britannia\magincia.cfg - Data\Decoration\Britannia\minoc.cfg = Data\Decoration\Britannia\minoc.cfg - Data\Decoration\Britannia\moonglow.cfg = Data\Decoration\Britannia\moonglow.cfg - Data\Decoration\Britannia\nujelm.cfg = Data\Decoration\Britannia\nujelm.cfg - Data\Decoration\Britannia\papua.cfg = Data\Decoration\Britannia\papua.cfg - Data\Decoration\Britannia\patches.cfg = Data\Decoration\Britannia\patches.cfg - Data\Decoration\Britannia\serpent pillars.cfg = Data\Decoration\Britannia\serpent pillars.cfg - Data\Decoration\Britannia\serpentshold.cfg = Data\Decoration\Britannia\serpentshold.cfg - Data\Decoration\Britannia\shame.cfg = Data\Decoration\Britannia\shame.cfg - Data\Decoration\Britannia\shrines.cfg = Data\Decoration\Britannia\shrines.cfg - Data\Decoration\Britannia\skara.cfg = Data\Decoration\Britannia\skara.cfg - Data\Decoration\Britannia\solen matriarch quest.cfg = Data\Decoration\Britannia\solen matriarch quest.cfg - Data\Decoration\Britannia\study of solen quest.cfg = Data\Decoration\Britannia\study of solen quest.cfg - Data\Decoration\Britannia\trinsic.cfg = Data\Decoration\Britannia\trinsic.cfg - Data\Decoration\Britannia\vesper.cfg = Data\Decoration\Britannia\vesper.cfg - Data\Decoration\Britannia\wind.cfg = Data\Decoration\Britannia\wind.cfg - Data\Decoration\Britannia\witch apprentice quest.cfg = Data\Decoration\Britannia\witch apprentice quest.cfg - Data\Decoration\Britannia\yew.cfg = Data\Decoration\Britannia\yew.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Felucca", "Felucca", "{C5F8ACCC-B741-4398-8F1B-9425F7F4659A}" - ProjectSection(SolutionItems) = preProject - Data\Decoration\Felucca\_champion teleporters.cfg = Data\Decoration\Felucca\_champion teleporters.cfg - Data\Decoration\Felucca\_star room.cfg = Data\Decoration\Felucca\_star room.cfg - Data\Decoration\Felucca\ambitious solen queen quest.cfg = Data\Decoration\Felucca\ambitious solen queen quest.cfg - Data\Decoration\Felucca\khaldun entrance.cfg = Data\Decoration\Felucca\khaldun entrance.cfg - Data\Decoration\Felucca\khaldun.cfg = Data\Decoration\Felucca\khaldun.cfg - Data\Decoration\Felucca\ocllo.cfg = Data\Decoration\Felucca\ocllo.cfg - Data\Decoration\Felucca\solen matriarch quest.cfg = Data\Decoration\Felucca\solen matriarch quest.cfg - Data\Decoration\Felucca\yew.cfg = Data\Decoration\Felucca\yew.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ilshenar", "Ilshenar", "{1AE5E70F-6607-4C60-82BF-764F7BD89138}" - ProjectSection(SolutionItems) = preProject - Data\Decoration\Ilshenar\_blood.cfg = Data\Decoration\Ilshenar\_blood.cfg - Data\Decoration\Ilshenar\_central.cfg = Data\Decoration\Ilshenar\_central.cfg - Data\Decoration\Ilshenar\_exodus.cfg = Data\Decoration\Ilshenar\_exodus.cfg - Data\Decoration\Ilshenar\_gwenno.cfg = Data\Decoration\Ilshenar\_gwenno.cfg - Data\Decoration\Ilshenar\_ratcave.cfg = Data\Decoration\Ilshenar\_ratcave.cfg - Data\Decoration\Ilshenar\_regvolom.cfg = Data\Decoration\Ilshenar\_regvolom.cfg - Data\Decoration\Ilshenar\_serpentine.cfg = Data\Decoration\Ilshenar\_serpentine.cfg - Data\Decoration\Ilshenar\_sheepfarm.cfg = Data\Decoration\Ilshenar\_sheepfarm.cfg - Data\Decoration\Ilshenar\_sorcerers.cfg = Data\Decoration\Ilshenar\_sorcerers.cfg - Data\Decoration\Ilshenar\_terortskitas.cfg = Data\Decoration\Ilshenar\_terortskitas.cfg - Data\Decoration\Ilshenar\_twinoaks.cfg = Data\Decoration\Ilshenar\_twinoaks.cfg - Data\Decoration\Ilshenar\camp.cfg = Data\Decoration\Ilshenar\camp.cfg - Data\Decoration\Ilshenar\camp2.cfg = Data\Decoration\Ilshenar\camp2.cfg - Data\Decoration\Ilshenar\enslavedgargs.cfg = Data\Decoration\Ilshenar\enslavedgargs.cfg - Data\Decoration\Ilshenar\gargoylecity.cfg = Data\Decoration\Ilshenar\gargoylecity.cfg - Data\Decoration\Ilshenar\golemsandjukas.cfg = Data\Decoration\Ilshenar\golemsandjukas.cfg - Data\Decoration\Ilshenar\lakeshire.cfg = Data\Decoration\Ilshenar\lakeshire.cfg - Data\Decoration\Ilshenar\meercatacombs.cfg = Data\Decoration\Ilshenar\meercatacombs.cfg - Data\Decoration\Ilshenar\misc.cfg = Data\Decoration\Ilshenar\misc.cfg - Data\Decoration\Ilshenar\mistas.cfg = Data\Decoration\Ilshenar\mistas.cfg - Data\Decoration\Ilshenar\patches.cfg = Data\Decoration\Ilshenar\patches.cfg - Data\Decoration\Ilshenar\ratfortress.cfg = Data\Decoration\Ilshenar\ratfortress.cfg - Data\Decoration\Ilshenar\savagecamp.cfg = Data\Decoration\Ilshenar\savagecamp.cfg - Data\Decoration\Ilshenar\shrines.cfg = Data\Decoration\Ilshenar\shrines.cfg - Data\Decoration\Ilshenar\vinculuminn.cfg = Data\Decoration\Ilshenar\vinculuminn.cfg - Data\Decoration\Ilshenar\wispdungeon.cfg = Data\Decoration\Ilshenar\wispdungeon.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Malas", "Malas", "{BCB51DFB-3AD2-44C5-8531-51D43C34CF44}" - ProjectSection(SolutionItems) = preProject - Data\Decoration\Malas\_luna.cfg = Data\Decoration\Malas\_luna.cfg - Data\Decoration\Malas\_umbra.cfg = Data\Decoration\Malas\_umbra.cfg - Data\Decoration\Malas\dark tides quest.cfg = Data\Decoration\Malas\dark tides quest.cfg - Data\Decoration\Malas\doom.cfg = Data\Decoration\Malas\doom.cfg - Data\Decoration\Malas\emino's undertaking quest.cfg = Data\Decoration\Malas\emino's undertaking quest.cfg - Data\Decoration\Malas\haochi's trials quest.cfg = Data\Decoration\Malas\haochi's trials quest.cfg - Data\Decoration\Malas\luna.cfg = Data\Decoration\Malas\luna.cfg - Data\Decoration\Malas\markcontainers.cfg = Data\Decoration\Malas\markcontainers.cfg - Data\Decoration\Malas\summoning quest.cfg = Data\Decoration\Malas\summoning quest.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RuinedMaginciaFel", "RuinedMaginciaFel", "{8DD3A1F1-EBD8-4DC2-A7D7-0127929726E0}" - ProjectSection(SolutionItems) = preProject - Data\Decoration\RuinedMaginciaFel\Mag-Fel.cfg = Data\Decoration\RuinedMaginciaFel\Mag-Fel.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RuinedMaginciaTram", "RuinedMaginciaTram", "{B018CA81-2D88-49DA-B362-2F6D84148B94}" - ProjectSection(SolutionItems) = preProject - Data\Decoration\RuinedMaginciaTram\Mag-Tram.cfg = Data\Decoration\RuinedMaginciaTram\Mag-Tram.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tokuno", "Tokuno", "{A42F9968-E255-4960-9C4D-66180D828EB9}" - ProjectSection(SolutionItems) = preProject - Data\Decoration\Tokuno\terrible hatchlings quest.cfg = Data\Decoration\Tokuno\terrible hatchlings quest.cfg - Data\Decoration\Tokuno\tokuno.cfg = Data\Decoration\Tokuno\tokuno.cfg - Data\Decoration\Tokuno\treasures of tokuno.cfg = Data\Decoration\Tokuno\treasures of tokuno.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Trammel", "Trammel", "{452A8873-A7C2-4FD8-A940-8AFDEACB9702}" - ProjectSection(SolutionItems) = preProject - Data\Decoration\Trammel\_haven additions.cfg = Data\Decoration\Trammel\_haven additions.cfg - Data\Decoration\Trammel\_minoc camp.cfg = Data\Decoration\Trammel\_minoc camp.cfg - Data\Decoration\Trammel\ambitious solen queen quest.cfg = Data\Decoration\Trammel\ambitious solen queen quest.cfg - Data\Decoration\Trammel\collector quest.cfg = Data\Decoration\Trammel\collector quest.cfg - Data\Decoration\Trammel\haven.cfg = Data\Decoration\Trammel\haven.cfg - Data\Decoration\Trammel\magincia.cfg = Data\Decoration\Trammel\magincia.cfg - Data\Decoration\Trammel\solen matriarch quest.cfg = Data\Decoration\Trammel\solen matriarch quest.cfg - Data\Decoration\Trammel\uzeraan turmoil quest.cfg = Data\Decoration\Trammel\uzeraan turmoil quest.cfg - Data\Decoration\Trammel\yew.cfg = Data\Decoration\Trammel\yew.cfg - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Locations", "Locations", "{70B04D45-39DD-422D-B95F-99ED9FC3DAC1}" - ProjectSection(SolutionItems) = preProject - Data\Locations\felucca.xml = Data\Locations\felucca.xml - Data\Locations\ilshenar.xml = Data\Locations\ilshenar.xml - Data\Locations\malas.xml = Data\Locations\malas.xml - Data\Locations\tokuno.xml = Data\Locations\tokuno.xml - Data\Locations\trammel.xml = Data\Locations\trammel.xml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0B33CEEB-88E1-49A6-8D7D-AF6A5A357087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0B33CEEB-88E1-49A6-8D7D-AF6A5A357087}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0B33CEEB-88E1-49A6-8D7D-AF6A5A357087}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0B33CEEB-88E1-49A6-8D7D-AF6A5A357087}.Release|Any CPU.Build.0 = Release|Any CPU - {DAE872E6-6899-427C-A75D-AD52526EBCDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DAE872E6-6899-427C-A75D-AD52526EBCDA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DAE872E6-6899-427C-A75D-AD52526EBCDA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DAE872E6-6899-427C-A75D-AD52526EBCDA}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {0BC3F1F5-95F7-4048-8BA1-71F2430104D8} = {1B394627-C6BF-447D-8CBD-4A3B5262C5B4} - {3CA15B59-8702-42FE-9980-54F8335CE149} = {1B394627-C6BF-447D-8CBD-4A3B5262C5B4} - {D990829A-479F-4377-B0C2-FD7C795C4D28} = {3CA15B59-8702-42FE-9980-54F8335CE149} - {2C58085D-5E30-4FB4-A71C-FD0328C60558} = {3CA15B59-8702-42FE-9980-54F8335CE149} - {4883A0CC-9D0C-4045-AC24-2A2FEAF09B88} = {1B394627-C6BF-447D-8CBD-4A3B5262C5B4} - {F1E91339-C2F1-40B7-80D0-6289228168D0} = {1B394627-C6BF-447D-8CBD-4A3B5262C5B4} - {D4052FE1-A0C6-486C-B972-348945894772} = {F1E91339-C2F1-40B7-80D0-6289228168D0} - {C5F8ACCC-B741-4398-8F1B-9425F7F4659A} = {F1E91339-C2F1-40B7-80D0-6289228168D0} - {1AE5E70F-6607-4C60-82BF-764F7BD89138} = {F1E91339-C2F1-40B7-80D0-6289228168D0} - {BCB51DFB-3AD2-44C5-8531-51D43C34CF44} = {F1E91339-C2F1-40B7-80D0-6289228168D0} - {8DD3A1F1-EBD8-4DC2-A7D7-0127929726E0} = {F1E91339-C2F1-40B7-80D0-6289228168D0} - {B018CA81-2D88-49DA-B362-2F6D84148B94} = {F1E91339-C2F1-40B7-80D0-6289228168D0} - {A42F9968-E255-4960-9C4D-66180D828EB9} = {F1E91339-C2F1-40B7-80D0-6289228168D0} - {452A8873-A7C2-4FD8-A940-8AFDEACB9702} = {F1E91339-C2F1-40B7-80D0-6289228168D0} - {70B04D45-39DD-422D-B95F-99ED9FC3DAC1} = {1B394627-C6BF-447D-8CBD-4A3B5262C5B4} - EndGlobalSection -EndGlobal diff --git a/RunUO.vshost.exe.manifest b/RunUO.vshost.exe.manifest deleted file mode 100644 index f96b1d6b3..000000000 --- a/RunUO.vshost.exe.manifest +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Scripts/Accounting/Account.cs b/Scripts/Accounting/Account.cs index 1f23a2d22..e8e75fa4b 100644 --- a/Scripts/Accounting/Account.cs +++ b/Scripts/Accounting/Account.cs @@ -807,17 +807,15 @@ namespace Server.Accounting return list; } - /// - /// Checks if a specific NetState is allowed access to this account. - /// - /// NetState instance to check. - /// True if allowed, false if not. - public bool HasAccess( NetState ns ) - { - return ( ns != null && HasAccess( ns.Address ) ); - } + /// + /// Checks if a specific NetState is allowed access to this account. + /// + /// NetState instance to check. + /// True if allowed, false if not. + public bool HasAccess(NetState ns) => ns != null && HasAccess(ns.Address); - public bool HasAccess( IPAddress ipAddress ) { + public bool HasAccess( IPAddress ipAddress ) + { AccessLevel level = AccountHandler.LockdownLevel; if ( level > AccessLevel.Player ) @@ -825,9 +823,7 @@ namespace Server.Accounting bool hasAccess = false; if ( m_AccessLevel >= level ) - { hasAccess = true; - } else { for ( int i = 0; !hasAccess && i < Length; ++i ) @@ -839,11 +835,13 @@ namespace Server.Accounting } } - if ( !hasAccess ) + Console.WriteLine("{0} {1}", hasAccess ? "yes" : "no", m_AccessLevel); + + if ( !hasAccess ) return false; } - bool accessAllowed = ( IPRestrictions.Length == 0 || IPLimiter.IsExempt( ipAddress ) ); + bool accessAllowed = IPRestrictions.Length == 0 || IPLimiter.IsExempt( ipAddress ); for ( int i = 0; !accessAllowed && i < IPRestrictions.Length; ++i ) accessAllowed = Utility.IPMatch( IPRestrictions[i], ipAddress ); @@ -903,9 +901,8 @@ namespace Server.Accounting public bool CheckAccess( IPAddress ipAddress ) { bool hasAccess = HasAccess( ipAddress ); - if ( hasAccess ) { + if ( hasAccess ) LogAccess( ipAddress ); - } return hasAccess; } diff --git a/Scripts/Accounting/AccountAttackLimiter.cs b/Scripts/Accounting/AccountAttackLimiter.cs index cc516295c..742fe0ad7 100644 --- a/Scripts/Accounting/AccountAttackLimiter.cs +++ b/Scripts/Accounting/AccountAttackLimiter.cs @@ -22,14 +22,16 @@ namespace Server.Accounting PacketHandlers.RegisterThrottler(0xCF, Throttle_Callback); } - public static bool Throttle_Callback(NetState ns) + public static TimeSpan Throttle_Callback(NetState ns) { InvalidAccountAccessLog accessLog = FindAccessLog(ns); if (accessLog == null) - return true; + return TimeSpan.Zero; - return DateTime.UtcNow >= accessLog.LastAccessTime + ComputeThrottle(accessLog.Counts); + DateTime date = DateTime.UtcNow; + DateTime access = accessLog.LastAccessTime + ComputeThrottle(accessLog.Counts); + return date >= access ? TimeSpan.Zero : date - access; } public static InvalidAccountAccessLog FindAccessLog(NetState ns) @@ -126,4 +128,4 @@ namespace Server.Accounting LastAccessTime = DateTime.UtcNow; } } -} \ No newline at end of file +} diff --git a/Scripts/Accounting/AccountHandler.cs b/Scripts/Accounting/AccountHandler.cs index d26612fb0..21ed489c1 100644 --- a/Scripts/Accounting/AccountHandler.cs +++ b/Scripts/Accounting/AccountHandler.cs @@ -315,8 +315,8 @@ namespace Server.Misc if (!(Accounts.GetAccount(un) is Account acct)) { - if (AutoAccountCreation && un.Trim().Length > 0 - ) // To prevent someone from making an account of just '' or a bunch of meaningless spaces + // To prevent someone from making an account of just '' or a bunch of meaningless spaces + if (AutoAccountCreation && un.Trim().Length > 0) { e.State.Account = acct = CreateAccount(e.State, un, pw); e.Accepted = acct?.CheckAccess(e.State) ?? false; diff --git a/Scripts/Commands/Add.cs b/Scripts/Commands/Add.cs index 55bc82d0f..fddc3a453 100644 --- a/Scripts/Commands/Add.cs +++ b/Scripts/Commands/Add.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Text; using Server.Items; diff --git a/Scripts/Commands/Docs.cs b/Scripts/Commands/Docs.cs index 47e60a2dd..90c37761a 100644 --- a/Scripts/Commands/Docs.cs +++ b/Scripts/Commands/Docs.cs @@ -28,7 +28,6 @@ namespace Server.Commands World.Broadcast(0x35, true, "Documentation is being generated, please wait."); Console.WriteLine("Documentation is being generated, please wait."); - NetState.FlushAll(); NetState.Pause(); DateTime startTime = DateTime.UtcNow; diff --git a/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs b/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs index 66d25d7c9..6bc886c89 100644 --- a/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs +++ b/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs @@ -160,6 +160,10 @@ namespace Server.Commands.Generic FieldAttributes.Private | FieldAttributes.InitOnly ); +// parseMethod.Invoke(null, +// parseArgs.Length == 2 ? new object[] {toParse, (int) parseArgs[1]} : new object[] {toParse}); + + il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, toParse); diff --git a/Scripts/Commands/Generic/Extensions/DistinctExtension.cs b/Scripts/Commands/Generic/Extensions/DistinctExtension.cs index bc976c286..bc50b0168 100644 --- a/Scripts/Commands/Generic/Extensions/DistinctExtension.cs +++ b/Scripts/Commands/Generic/Extensions/DistinctExtension.cs @@ -6,7 +6,7 @@ namespace Server.Commands.Generic public sealed class DistinctExtension : BaseExtension { public static ExtensionInfo ExtInfo = - new ExtensionInfo(30, "Distinct", -1, delegate { return new DistinctExtension(); }); + new ExtensionInfo(30, "Distinct", -1, () => new DistinctExtension()); private IComparer m_Comparer; @@ -36,7 +36,7 @@ namespace Server.Commands.Generic } if (assembly == null) - assembly = new AssemblyEmitter("__dynamic", false); + assembly = new AssemblyEmitter("__dynamic"); m_Comparer = DistinctCompiler.Compile(assembly, baseType, m_Properties.ToArray()); } @@ -81,4 +81,4 @@ namespace Server.Commands.Generic } } } -} \ No newline at end of file +} diff --git a/Scripts/Commands/Generic/Extensions/SortExtension.cs b/Scripts/Commands/Generic/Extensions/SortExtension.cs index 4988421cf..fe8613240 100644 --- a/Scripts/Commands/Generic/Extensions/SortExtension.cs +++ b/Scripts/Commands/Generic/Extensions/SortExtension.cs @@ -35,7 +35,7 @@ namespace Server.Commands.Generic } if (assembly == null) - assembly = new AssemblyEmitter("__dynamic", false); + assembly = new AssemblyEmitter("__dynamic"); m_Comparer = SortCompiler.Compile(assembly, baseType, m_Orders.ToArray()); } @@ -100,4 +100,4 @@ namespace Server.Commands.Generic list.Sort(m_Comparer); } } -} \ No newline at end of file +} diff --git a/Scripts/Commands/Generic/Implementors/ObjectConditional.cs b/Scripts/Commands/Generic/Implementors/ObjectConditional.cs index f5fe4be24..502af3c1d 100644 --- a/Scripts/Commands/Generic/Implementors/ObjectConditional.cs +++ b/Scripts/Commands/Generic/Implementors/ObjectConditional.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using CPA = Server.CommandPropertyAttribute; namespace Server.Commands.Generic { @@ -32,7 +31,7 @@ namespace Server.Commands.Generic public void Compile(ref AssemblyEmitter emitter) { if (emitter == null) - emitter = new AssemblyEmitter("__dynamic", false); + emitter = new AssemblyEmitter("__dynamic"); m_Conditionals = new IConditional[m_Conditions.Length]; @@ -247,4 +246,4 @@ namespace Server.Commands.Generic return new ObjectConditional(objectType, conditions.ToArray()); } } -} \ No newline at end of file +} diff --git a/Scripts/Engines/BulkOrders/LargeSmithBOD.cs b/Scripts/Engines/BulkOrders/LargeSmithBOD.cs index 667947547..5a1ab25da 100644 --- a/Scripts/Engines/BulkOrders/LargeSmithBOD.cs +++ b/Scripts/Engines/BulkOrders/LargeSmithBOD.cs @@ -1,5 +1,3 @@ -using Mat = Server.Engines.BulkOrders.BulkMaterialType; - namespace Server.Engines.BulkOrders { public class LargeSmithBOD : LargeBOD diff --git a/Scripts/Engines/BulkOrders/LargeTailorBOD.cs b/Scripts/Engines/BulkOrders/LargeTailorBOD.cs index 192b2c8df..bb78b8ad4 100644 --- a/Scripts/Engines/BulkOrders/LargeTailorBOD.cs +++ b/Scripts/Engines/BulkOrders/LargeTailorBOD.cs @@ -1,5 +1,3 @@ -using Mat = Server.Engines.BulkOrders.BulkMaterialType; - namespace Server.Engines.BulkOrders { public class LargeTailorBOD : LargeBOD diff --git a/Scripts/Engines/BulkOrders/SmallSmithBOD.cs b/Scripts/Engines/BulkOrders/SmallSmithBOD.cs index 35faf24b9..b44b841b5 100644 --- a/Scripts/Engines/BulkOrders/SmallSmithBOD.cs +++ b/Scripts/Engines/BulkOrders/SmallSmithBOD.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using Server.Engines.Craft; -using Mat = Server.Engines.BulkOrders.BulkMaterialType; namespace Server.Engines.BulkOrders { diff --git a/Scripts/Engines/Factions/Core/PlayerState.cs b/Scripts/Engines/Factions/Core/PlayerState.cs index 67e8fb963..e9d0e11b8 100644 --- a/Scripts/Engines/Factions/Core/PlayerState.cs +++ b/Scripts/Engines/Factions/Core/PlayerState.cs @@ -271,11 +271,7 @@ namespace Server.Factions public void Invalidate() { - if (Mobile is PlayerMobile pm) - { - pm.InvalidateProperties(); - pm.InvalidateMyRunUO(); - } + (Mobile as PlayerMobile)?.InvalidateProperties(); } public void Attach() diff --git a/Scripts/Engines/Help/HelpGump.cs b/Scripts/Engines/Help/HelpGump.cs index 7833dbb0e..f4634a8a5 100644 --- a/Scripts/Engines/Help/HelpGump.cs +++ b/Scripts/Engines/Help/HelpGump.cs @@ -39,7 +39,7 @@ namespace Server.Engines.Help if (entry != null && entry.Handler == null) { m_From.SendLocalizedMessage(1005307, "", 0x35); // Removed help request. - entry.AddResponse(entry.Sender, "[Canceled]"); + // entry.AddResponse(entry.Sender, "[Canceled]"); PageQueue.Remove(entry); } else diff --git a/Scripts/Engines/Help/PageQueue.cs b/Scripts/Engines/Help/PageQueue.cs index 522d4aa8d..5dbeae26f 100644 --- a/Scripts/Engines/Help/PageQueue.cs +++ b/Scripts/Engines/Help/PageQueue.cs @@ -4,7 +4,6 @@ using System.IO; using System.Net.Mail; using Server.Accounting; using Server.Commands; -using Server.Engines.Reports; using Server.Misc; using Server.Mobiles; using Server.Network; @@ -49,19 +48,8 @@ namespace Server.Engines.Help m_Timer = new InternalTimer(this); m_Timer.Start(); - - StaffHistory history = Reports.Reports.StaffHistory; - - if (history != null) - { - PageInfo = new PageInfo(this); - - history.AddPage(PageInfo); - } } - public PageInfo PageInfo{ get; } - public Mobile Sender{ get; } public Mobile Handler @@ -93,20 +81,6 @@ namespace Server.Engines.Help m_Timer = null; } - public void AddResponse(Mobile mob, string text) - { - if (PageInfo != null) - { - lock (PageInfo) - { - PageInfo.Responses.Add(PageInfo.GetAccount(mob), text); - } - - if (PageInfo.ResFromResp(text) != PageResolution.None) - PageInfo.UpdateResolver(); - } - } - private class InternalTimer : Timer { private static TimeSpan StatusDelay = TimeSpan.FromMinutes(2.0); @@ -135,7 +109,7 @@ namespace Server.Engines.Help else { if (index != -1) - m_Entry.AddResponse(m_Entry.Sender, "[Logout]"); + // m_Entry.AddResponse(m_Entry.Sender, "[Logout]"); PageQueue.Remove(m_Entry); } diff --git a/Scripts/Engines/Help/PageQueueGump.cs b/Scripts/Engines/Help/PageQueueGump.cs index 876d981d3..5351e83ac 100644 --- a/Scripts/Engines/Help/PageQueueGump.cs +++ b/Scripts/Engines/Help/PageQueueGump.cs @@ -62,7 +62,7 @@ namespace Server.Engines.Help if (e.Sender.Deleted || e.Sender.NetState == null) { - e.AddResponse(e.Sender, "[Logout]"); + // e.AddResponse(e.Sender, "[Logout]"); PageQueue.Remove(e); } else @@ -601,7 +601,7 @@ namespace Server.Engines.Help } else { - m_Entry.AddResponse(state.Mobile, "[Go Sender]"); + // m_Entry.AddResponse(state.Mobile, "[Go Sender]"); m.MoveToWorld(m_Entry.Sender.Location, m_Entry.Sender.Map); m.SendMessage("You have been teleported to that page's sender."); @@ -628,7 +628,7 @@ namespace Server.Engines.Help } else { - m_Entry.AddResponse(state.Mobile, "[Go Handler]"); + // m_Entry.AddResponse(state.Mobile, "[Go Handler]"); m.MoveToWorld(h.Location, h.Map); m.SendMessage("You have been teleported to that page's handler."); @@ -653,7 +653,7 @@ namespace Server.Engines.Help } else { - m_Entry.AddResponse(state.Mobile, "[Go PageLoc]"); + // m_Entry.AddResponse(state.Mobile, "[Go PageLoc]"); m.MoveToWorld(m_Entry.PageLocation, m_Entry.PageMap); state.Mobile.SendMessage("You have been teleported to the original page location."); @@ -667,7 +667,7 @@ namespace Server.Engines.Help { if (m_Entry.Handler == null) { - m_Entry.AddResponse(state.Mobile, "[Handling]"); + // m_Entry.AddResponse(state.Mobile, "[Handling]"); m_Entry.Handler = state.Mobile; state.Mobile.SendMessage("You are now handling the page."); @@ -685,7 +685,7 @@ namespace Server.Engines.Help { if (m_Entry.Handler == null) { - m_Entry.AddResponse(state.Mobile, "[Deleting]"); + // m_Entry.AddResponse(state.Mobile, "[Deleting]"); PageQueue.Remove(m_Entry); state.Mobile.SendMessage("You delete the page."); @@ -707,7 +707,7 @@ namespace Server.Engines.Help { if (m_Entry.Handler == state.Mobile) { - m_Entry.AddResponse(state.Mobile, "[Abandoning]"); + // m_Entry.AddResponse(state.Mobile, "[Abandoning]"); state.Mobile.SendMessage("You abandon the page."); m_Entry.Handler = null; @@ -725,7 +725,7 @@ namespace Server.Engines.Help { if (m_Entry.Handler == state.Mobile) { - m_Entry.AddResponse(state.Mobile, "[Handled]"); + // m_Entry.AddResponse(state.Mobile, "[Handled]"); PageQueue.Remove(m_Entry); m_Entry.Handler = null; @@ -751,7 +751,7 @@ namespace Server.Engines.Help if (text != null) { - m_Entry.AddResponse(state.Mobile, "[Response] " + text.Text); + // m_Entry.AddResponse(state.Mobile, "[Response] " + text.Text); m_Entry.Sender.SendGump(new MessageSentGump(m_Entry.Sender, state.Mobile.Name, text.Text)); //m_Entry.Sender.SendMessage( 0x482, "{0} tells you:", state.Mobile.Name ); //m_Entry.Sender.SendMessage( 0x482, text.Text ); @@ -786,7 +786,7 @@ namespace Server.Engines.Help if (index >= 0 && index < preresp.Count) { - m_Entry.AddResponse(state.Mobile, "[PreDef] " + preresp[index].Title); + // m_Entry.AddResponse(state.Mobile, "[PreDef] " + preresp[index].Title); m_Entry.Sender.SendGump(new MessageSentGump(m_Entry.Sender, state.Mobile.Name, preresp[index].Message)); } diff --git a/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs b/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs index 11ae33826..a1719cbea 100644 --- a/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs +++ b/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs @@ -177,7 +177,7 @@ namespace Server.Engines.MLQuests.Gumps IRaceChanger owner = raceChangeState.m_Owner; Race targetRace = raceChangeState.m_TargetRace; - if (pvSrc.Size == 5) + if (pvSrc.Length == 5) { owner?.OnCancel(pm); diff --git a/Scripts/Engines/MyRunUO/DatabaseCommandQueue.cs b/Scripts/Engines/MyRunUO/DatabaseCommandQueue.cs deleted file mode 100644 index 22125e710..000000000 --- a/Scripts/Engines/MyRunUO/DatabaseCommandQueue.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System; -using System.Collections; -using System.Data.Odbc; -using System.Threading; - -namespace Server.Engines.MyRunUO -{ - public class DatabaseCommandQueue - { - private string m_CompletionString; - private string m_ConnectionString; - private Queue m_Queue; - private ManualResetEvent m_Sync; - - public DatabaseCommandQueue(string completionString, string threadName) : this(Config.CompileConnectionString(), - completionString, threadName) - { - } - - public DatabaseCommandQueue(string connectionString, string completionString, string threadName) - { - m_CompletionString = completionString; - m_ConnectionString = connectionString; - - m_Queue = Queue.Synchronized(new Queue()); - - m_Queue.Enqueue(null); // signal connect - - /*m_Queue.Enqueue( "DELETE FROM myrunuo_characters" ); - m_Queue.Enqueue( "DELETE FROM myrunuo_characters_layers" ); - m_Queue.Enqueue( "DELETE FROM myrunuo_characters_skills" ); - m_Queue.Enqueue( "DELETE FROM myrunuo_guilds" ); - m_Queue.Enqueue( "DELETE FROM myrunuo_guilds_wars" );*/ - - m_Sync = new ManualResetEvent(true); - - // MyRunUO Database Command Queue; - Thread thread = new Thread(Thread_Start) { Name = threadName, Priority = Config.DatabaseThreadPriority }; - thread.Start(); - } - - public bool HasCompleted{ get; private set; } - - public void Enqueue(object obj) - { - lock (m_Queue.SyncRoot) - { - m_Queue.Enqueue(obj); - try - { - m_Sync.Set(); - } - catch - { - // ignored - } - } - } - - private void Thread_Start() - { - bool connected = false; - - OdbcConnection connection = null; - OdbcCommand command = null; - OdbcTransaction transact = null; - - DateTime start = DateTime.UtcNow; - - bool shouldWriteException = true; - - while (true) - { - m_Sync.WaitOne(); - - while (m_Queue.Count > 0) - try - { - object obj = m_Queue.Dequeue(); - - if (obj == null) - { - if (connected) - { - if (transact != null) - try - { - transact.Commit(); - } - catch (Exception commitException) - { - Console.WriteLine("MyRunUO: Exception caught when committing transaction"); - Console.WriteLine(commitException); - - try - { - transact.Rollback(); - Console.WriteLine("MyRunUO: Transaction has been rolled back"); - } - catch (Exception rollbackException) - { - Console.WriteLine("MyRunUO: Exception caught when rolling back transaction"); - Console.WriteLine(rollbackException); - } - } - - try - { - connection.Close(); - } - catch - { - // ignored - } - - try - { - connection.Dispose(); - } - catch - { - // ignored - } - - try - { - command.Dispose(); - } - catch - { - // ignored - } - - try - { - m_Sync.Close(); - } - catch - { - // ignored - } - - Console.WriteLine(m_CompletionString, (DateTime.UtcNow - start).TotalSeconds); - HasCompleted = true; - - return; - } - - try - { - connected = true; - connection = new OdbcConnection(m_ConnectionString); - connection.Open(); - command = connection.CreateCommand(); - - if (Config.UseTransactions) - { - transact = connection.BeginTransaction(); - command.Transaction = transact; - } - } - catch (Exception e) - { - try - { - transact?.Rollback(); - } - catch - { - // ignored - } - - try - { - connection?.Close(); - } - catch - { - // ignored - } - - try - { - connection?.Dispose(); - } - catch - { - // ignored - } - - try - { - command?.Dispose(); - } - catch - { - // ignored - } - - try - { - m_Sync.Close(); - } - catch - { - // ignored - } - - Console.WriteLine("MyRunUO: Unable to connect to the database"); - Console.WriteLine(e); - HasCompleted = true; - return; - } - } - else if (obj is string s) - { - command.CommandText = s; - command.ExecuteNonQuery(); - } - else - { - string[] parms = (string[])obj; - - command.CommandText = parms[0]; - - if (command.ExecuteScalar() == null) - { - command.CommandText = parms[1]; - command.ExecuteNonQuery(); - } - } - } - catch (Exception e) - { - if (shouldWriteException) - { - Console.WriteLine("MyRunUO: Exception caught in database thread"); - Console.WriteLine(e); - shouldWriteException = false; - } - } - - lock (m_Queue.SyncRoot) - { - if (m_Queue.Count == 0) - m_Sync.Reset(); - } - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/MyRunUO/MyRunUO.cs b/Scripts/Engines/MyRunUO/MyRunUO.cs deleted file mode 100644 index efce89134..000000000 --- a/Scripts/Engines/MyRunUO/MyRunUO.cs +++ /dev/null @@ -1,716 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Server.Accounting; -using Server.Commands; -using Server.Guilds; -using Server.Misc; -using Server.Mobiles; - -namespace Server.Engines.MyRunUO -{ - public class MyRunUO : Timer - { - public const char LineStart = '\"'; - public const string EntrySep = "\",\""; - public const string LineEnd = "\"\n"; - private static double CpuInterval = 0.1; // Processor runs every 0.1 seconds - - private static double - CpuPercent = 0.25; // Processor runs for 25% of Interval, or ~25ms. This should take around 25% cpu - - private static Timer m_Timer; - - private static DatabaseCommandQueue m_Command; - - private static List m_MobilesToUpdate = new List(); - private List m_Collecting; - private int m_Index; - - private List m_Items = new List(); - private string m_LayersPath; - private ArrayList m_List; - private string m_MobilesPath; - private StreamWriter m_OpLayers; - private StreamWriter m_OpMobiles; - - private StreamWriter m_OpSkills; - - private string m_SkillsPath; - - private Stage m_Stage; - - private DateTime m_StartTime; - - public MyRunUO() : base(TimeSpan.FromSeconds(CpuInterval), TimeSpan.FromSeconds(CpuInterval)) - { - m_List = new ArrayList(); - m_Collecting = new List(); - - m_StartTime = DateTime.UtcNow; - Console.WriteLine("MyRunUO: Updating character database"); - } - - public static void Initialize() - { - if (Config.Enabled) - { - DelayCall(TimeSpan.FromSeconds(10.0), Config.CharacterUpdateInterval, Begin); - - CommandSystem.Register("InitMyRunUO", AccessLevel.Administrator, InitMyRunUO_OnCommand); - CommandSystem.Register("UpdateMyRunUO", AccessLevel.Administrator, UpdateMyRunUO_OnCommand); - - CommandSystem.Register("PublicChar", AccessLevel.Player, PublicChar_OnCommand); - CommandSystem.Register("PrivateChar", AccessLevel.Player, PrivateChar_OnCommand); - } - } - - [Usage("PublicChar")] - [Description("Enables showing extended character stats and skills in MyRunUO.")] - public static void PublicChar_OnCommand(CommandEventArgs e) - { - if (e.Mobile is PlayerMobile pm) - { - if (pm.PublicMyRunUO) - { - pm.SendMessage("You have already chosen to show your skills and stats."); - } - else - { - pm.PublicMyRunUO = true; - pm.SendMessage("All of your skills and stats will now be shown publicly in MyRunUO."); - } - } - } - - [Usage("PrivateChar")] - [Description("Disables showing extended character stats and skills in MyRunUO.")] - public static void PrivateChar_OnCommand(CommandEventArgs e) - { - if (e.Mobile is PlayerMobile pm) - { - if (!pm.PublicMyRunUO) - { - pm.SendMessage("You have already chosen to not show your skills and stats."); - } - else - { - pm.PublicMyRunUO = false; - pm.SendMessage("Only a general level of your top three skills will be shown in MyRunUO."); - } - } - } - - [Usage("InitMyRunUO")] - [Description("Initially creates the database schema.")] - public static void InitMyRunUO_OnCommand(CommandEventArgs e) - { - if (m_Command?.HasCompleted == true) - { - TableCreation(); - e.Mobile.SendMessage("MyRunUO table creation process has been started."); - } - else - { - e.Mobile.SendMessage("MyRunUO table creation is already running."); - } - } - - public static void TableCreation() - { - if (m_Command?.HasCompleted == false) - return; - // DateTime start = DateTime.Now; - Console.WriteLine("MyRunUO: Creating tables"); - try - { - m_Command = new DatabaseCommandQueue("MyRunUO: Tables created in {0:F1} seconds", - "MyRunUO Status Database Thread"); - m_Command.Enqueue( - "CREATE TABLE IF NOT EXISTS `myrunuo_characters` ( `char_id` int(10) unsigned NOT NULL, `char_name` varchar(255) NOT NULL, `char_str` smallint(3) unsigned NOT NULL, `char_dex` smallint(3) unsigned NOT NULL, `char_int` smallint(3) unsigned NOT NULL, `char_female` tinyint(1) NOT NULL, `char_counts` smallint(6) NOT NULL, `char_guild` varchar(255) DEFAULT NULL, `char_guildtitle` varchar(255) DEFAULT NULL, `char_nototitle` varchar(255) DEFAULT NULL, `char_bodyhue` smallint(5) unsigned DEFAULT NULL, `char_public` tinyint(1) NOT NULL, PRIMARY KEY (`char_id`))"); - m_Command.Enqueue( - "CREATE TABLE IF NOT EXISTS `myrunuo_characters_layers` ( `char_id` int(10) unsigned NOT NULL, `layer_id` tinyint(3) unsigned NOT NULL, `item_id` smallint(5) unsigned NOT NULL, `item_hue` smallint(5) unsigned NOT NULL, PRIMARY KEY (`char_id`,`layer_id`))"); - m_Command.Enqueue( - "CREATE TABLE IF NOT EXISTS `myrunuo_characters_skills` ( `char_id` int(10) unsigned NOT NULL, `skill_id` tinyint(3) NOT NULL, `skill_value` smallint(5) unsigned NOT NULL, PRIMARY KEY (`char_id`,`skill_id`), KEY `skill_id` (`skill_id`))"); - m_Command.Enqueue( - "CREATE TABLE IF NOT EXISTS `myrunuo_guilds` ( `guild_id` smallint(5) unsigned NOT NULL, `guild_name` varchar(255) NOT NULL, `guild_abbreviation` varchar(8) DEFAULT NULL, `guild_website` varchar(255) DEFAULT NULL, `guild_charter` varchar(255) DEFAULT NULL, `guild_type` varchar(8) NOT NULL, `guild_wars` smallint(5) unsigned NOT NULL, `guild_members` smallint(5) unsigned NOT NULL, `guild_master` int(10) unsigned NOT NULL, PRIMARY KEY (`guild_id`))"); - m_Command.Enqueue( - "CREATE TABLE IF NOT EXISTS `myrunuo_guilds_wars` ( `guild_1` smallint(5) unsigned NOT NULL DEFAULT '0', `guild_2` smallint(5) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`guild_1`,`guild_2`), KEY `guild1` (`guild_1`), KEY `guild2` (`guild_2`))"); - m_Command.Enqueue( - "CREATE TABLE IF NOT EXISTS `myrunuo_status` ( `char_id` int(10) NOT NULL, PRIMARY KEY (`char_id`))"); - } - catch (Exception e) - { - Console.WriteLine("MyRunUO: Error creating tables."); - Console.WriteLine(e); - } - - m_Command?.Enqueue(null); - } - - [Usage("UpdateMyRunUO")] - [Description("Starts the process of updating the MyRunUO character and guild database.")] - public static void UpdateMyRunUO_OnCommand(CommandEventArgs e) - { - if (m_Command?.HasCompleted == true) - m_Command = null; - - if (m_Timer == null && m_Command == null) - { - Begin(); - e.Mobile.SendMessage("MyRunUO update process has been started."); - } - else - { - e.Mobile.SendMessage("MyRunUO database is already being updated."); - } - } - - public static void Begin() - { - if (m_Command?.HasCompleted == true) - m_Command = null; - - if (m_Timer != null || m_Command != null) - return; - - m_Timer = new MyRunUO(); - m_Timer.Start(); - } - - protected override void OnTick() - { - bool shouldExit; - - try - { - shouldExit = Process(DateTime.UtcNow + TimeSpan.FromSeconds(CpuInterval * CpuPercent)); - - if (shouldExit) - Console.WriteLine("MyRunUO: Database statements compiled in {0:F2} seconds", - (DateTime.UtcNow - m_StartTime).TotalSeconds); - } - catch (Exception e) - { - Console.WriteLine("MyRunUO: {0}: Exception cought while processing", m_Stage); - Console.WriteLine(e); - shouldExit = true; - } - - if (shouldExit) - { - m_Command.Enqueue(null); - - Stop(); - m_Timer = null; - } - } - - public bool Process(DateTime endTime) - { - switch (m_Stage) - { - case Stage.CollectingMobiles: - CollectMobiles(endTime); - break; - case Stage.DumpingMobiles: - DumpMobiles(endTime); - break; - case Stage.CollectingGuilds: - CollectGuilds(endTime); - break; - case Stage.DumpingGuilds: - DumpGuilds(endTime); - break; - } - - return m_Stage == Stage.Complete; - } - - public static void QueueMobileUpdate(Mobile m) - { - if (!Config.Enabled || Config.LoadDataInFile) - return; - - m_MobilesToUpdate.Add(m); - } - - public void CollectMobiles(DateTime endTime) - { - if (Config.LoadDataInFile) - { - if (m_Index == 0) - m_Collecting.AddRange(Accounts.GetAccounts()); - - for (int i = m_Index; i < m_Collecting.Count; ++i) - { - IAccount acct = m_Collecting[i]; - - for (int j = 0; j < acct.Length; ++j) - { - Mobile mob = acct[j]; - - if (mob?.AccessLevel < Config.HiddenAccessLevel) - m_List.Add(mob); - } - - ++m_Index; - - if (DateTime.UtcNow >= endTime) - break; - } - - if (m_Index == m_Collecting.Count) - { - m_Collecting = new List(); - m_Stage = Stage.DumpingMobiles; - m_Index = 0; - } - } - else - { - m_List = new ArrayList(m_MobilesToUpdate); - m_MobilesToUpdate = new List(); - m_Stage = Stage.DumpingMobiles; - m_Index = 0; - } - } - - public void CheckConnection() - { - if (m_Command == null) - { - m_Command = new DatabaseCommandQueue("MyRunUO: Character database updated in {0:F1} seconds", - "MyRunUO Character Database Thread"); - - if (Config.LoadDataInFile) - { - m_OpSkills = GetUniqueWriter("skills", out m_SkillsPath); - m_OpLayers = GetUniqueWriter("layers", out m_LayersPath); - m_OpMobiles = GetUniqueWriter("mobiles", out m_MobilesPath); - - m_Command.Enqueue("TRUNCATE TABLE myrunuo_characters"); - m_Command.Enqueue("TRUNCATE TABLE myrunuo_characters_layers"); - m_Command.Enqueue("TRUNCATE TABLE myrunuo_characters_skills"); - } - - m_Command.Enqueue("TRUNCATE TABLE myrunuo_guilds"); - m_Command.Enqueue("TRUNCATE TABLE myrunuo_guilds_wars"); - } - } - - public void ExecuteNonQuery(string text) - { - m_Command.Enqueue(text); - } - - public void ExecuteNonQuery(string format, params object[] args) - { - ExecuteNonQuery(string.Format(format, args)); - } - - public void ExecuteNonQueryIfNull(string select, string insert) - { - m_Command.Enqueue(new[] { select, insert }); - } - - private void AppendCharEntity(string input, int charIndex, ref StringBuilder sb, char c) - { - if (sb == null) - { - sb = charIndex > 0 ? new StringBuilder(input, 0, charIndex, input.Length + 20) : new StringBuilder(input.Length + 20); - } - - sb.Append("&#"); - sb.Append((int)c); - sb.Append(";"); - } - - private void AppendEntityRef(string input, int charIndex, ref StringBuilder sb, string ent) - { - if (sb == null) - { - sb = charIndex > 0 ? new StringBuilder(input, 0, charIndex, input.Length + 20) : new StringBuilder(input.Length + 20); - } - - sb.Append(ent); - } - - private string SafeString(string input) - { - if (input == null) - return ""; - - StringBuilder sb = null; - - for (int i = 0; i < input.Length; ++i) - { - char c = input[i]; - - if (c < 0x20 || c >= 0x7F) - AppendCharEntity(input, i, ref sb, c); - else - switch (c) - { - case '&': - AppendEntityRef(input, i, ref sb, "&"); - break; - case '>': - AppendEntityRef(input, i, ref sb, ">"); - break; - case '<': - AppendEntityRef(input, i, ref sb, "<"); - break; - case '"': - AppendEntityRef(input, i, ref sb, """); - break; - case '\'': - case ':': - case '/': - case '\\': - AppendCharEntity(input, i, ref sb, c); - break; - default: - { - sb?.Append(c); - - break; - } - } - } - - return sb != null ? sb.ToString() : input; - } - - public void InsertMobile(Mobile mob) - { - string guildTitle = mob.GuildTitle; - - if (guildTitle == null || (guildTitle = guildTitle.Trim()).Length == 0) - guildTitle = "NULL"; - else - guildTitle = SafeString(guildTitle); - - string notoTitle = SafeString(Titles.ComputeTitle(null, mob)); - string female = mob.Female ? "1" : "0"; - - bool pubBool = mob is PlayerMobile mobile && mobile.PublicMyRunUO; - - string pubString = pubBool ? "1" : "0"; - - string guildId = mob.Guild == null ? "NULL" : mob.Guild.Id.ToString(); - - if (Config.LoadDataInFile) - { - m_OpMobiles.Write(LineStart); - m_OpMobiles.Write(mob.Serial.Value); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(SafeString(mob.Name)); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(mob.RawStr); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(mob.RawDex); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(mob.RawInt); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(female); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(mob.Kills); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(guildId); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(guildTitle); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(notoTitle); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(mob.Hue); - m_OpMobiles.Write(EntrySep); - m_OpMobiles.Write(pubString); - m_OpMobiles.Write(LineEnd); - } - else - { - ExecuteNonQuery( - "INSERT INTO myrunuo_characters (char_id, char_name, char_str, char_dex, char_int, char_female, char_counts, char_guild, char_guildtitle, char_nototitle, char_bodyhue, char_public ) VALUES ({0}, '{1}', {2}, {3}, {4}, {5}, {6}, {7}, {8}, '{9}', {10}, {11})", - mob.Serial.Value.ToString(), SafeString(mob.Name), mob.RawStr.ToString(), mob.RawDex.ToString(), - mob.RawInt.ToString(), female, mob.Kills.ToString(), guildId, guildTitle, notoTitle, mob.Hue.ToString(), - pubString); - } - } - - public void InsertSkills(Mobile mob) - { - Skills skills = mob.Skills; - string serial = mob.Serial.Value.ToString(); - - for (int i = 0; i < skills.Length; ++i) - { - Skill skill = skills[i]; - - if (skill.BaseFixedPoint > 0) - { - if (Config.LoadDataInFile) - { - m_OpSkills.Write(LineStart); - m_OpSkills.Write(serial); - m_OpSkills.Write(EntrySep); - m_OpSkills.Write(i); - m_OpSkills.Write(EntrySep); - m_OpSkills.Write(skill.BaseFixedPoint); - m_OpSkills.Write(LineEnd); - } - else - { - ExecuteNonQuery( - "INSERT INTO myrunuo_characters_skills (char_id, skill_id, skill_value) VALUES ({0}, {1}, {2})", - serial, i.ToString(), skill.BaseFixedPoint.ToString()); - } - } - } - } - - private void InsertItem(string serial, int index, int itemID, int hue) - { - if (Config.LoadDataInFile) - { - m_OpLayers.Write(LineStart); - m_OpLayers.Write(serial); - m_OpLayers.Write(EntrySep); - m_OpLayers.Write(index); - m_OpLayers.Write(EntrySep); - m_OpLayers.Write(itemID); - m_OpLayers.Write(EntrySep); - m_OpLayers.Write(hue); - m_OpLayers.Write(LineEnd); - } - else - { - ExecuteNonQuery( - "INSERT INTO myrunuo_characters_layers (char_id, layer_id, item_id, item_hue) VALUES ({0}, {1}, {2}, {3})", - serial, index.ToString(), itemID.ToString(), hue.ToString()); - } - } - - public void InsertItems(Mobile mob) - { - List items = m_Items; - items.AddRange(mob.Items); - string serial = mob.Serial.Value.ToString(); - - items.Sort(LayerComparer.Instance); - - int index = 0; - - bool hidePants = false; - bool alive = mob.Alive; - bool hideHair = !alive; - - for (int i = 0; i < items.Count; ++i) - { - Item item = items[i]; - - if (!LayerComparer.IsValid(item)) - break; - - if (!alive && item.ItemID != 8270) - continue; - - if (item.ItemID == 0x1411 || item.ItemID == 0x141A) // plate legs - hidePants = true; - else if (hidePants && item.Layer == Layer.Pants) - continue; - - if (!hideHair && item.Layer == Layer.Helm) - hideHair = true; - - InsertItem(serial, index++, item.ItemID, item.Hue); - } - - if (mob.FacialHairItemID != 0 && alive) - InsertItem(serial, index++, mob.FacialHairItemID, mob.FacialHairHue); - - if (mob.HairItemID != 0 && !hideHair) - InsertItem(serial, index, mob.HairItemID, mob.HairHue); - - items.Clear(); - } - - public void DeleteMobile(Mobile mob) - { - ExecuteNonQuery("DELETE FROM myrunuo_characters WHERE char_id = {0}", mob.Serial.Value.ToString()); - ExecuteNonQuery("DELETE FROM myrunuo_characters_skills WHERE char_id = {0}", mob.Serial.Value.ToString()); - ExecuteNonQuery("DELETE FROM myrunuo_characters_layers WHERE char_id = {0}", mob.Serial.Value.ToString()); - } - - public StreamWriter GetUniqueWriter(string type, out string filePath) - { - filePath = Path.Combine(Core.BaseDirectory, $"myrunuodb_{type}.txt") - .Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - - try - { - return new StreamWriter(filePath); - } - catch - { - for (int i = 0; i < 100; ++i) - try - { - filePath = Path.Combine(Core.BaseDirectory, $"myrunuodb_{type}_{i}.txt") - .Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - return new StreamWriter(filePath); - } - catch - { - // ignored - } - } - - return null; - } - - public void DumpMobiles(DateTime endTime) - { - CheckConnection(); - - for (int i = m_Index; i < m_List.Count; ++i) - { - Mobile mob = (Mobile)m_List[i]; - - if (mob is PlayerMobile mobile) - mobile.ChangedMyRunUO = false; - - if (!mob.Deleted && mob.AccessLevel < Config.HiddenAccessLevel) - { - if (!Config.LoadDataInFile) - DeleteMobile(mob); - - InsertMobile(mob); - InsertSkills(mob); - InsertItems(mob); - } - else if (!Config.LoadDataInFile) - { - DeleteMobile(mob); - } - - ++m_Index; - - if (DateTime.UtcNow >= endTime) - break; - } - - if (m_Index == m_List.Count) - { - m_List.Clear(); - m_Stage = Stage.CollectingGuilds; - m_Index = 0; - - if (Config.LoadDataInFile) - { - m_OpSkills.Close(); - m_OpLayers.Close(); - m_OpMobiles.Close(); - - ExecuteNonQuery( - "LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'", - Config.DatabaseNonLocal ? "LOCAL " : "", m_MobilesPath); - ExecuteNonQuery( - "LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters_skills FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'", - Config.DatabaseNonLocal ? "LOCAL " : "", m_SkillsPath); - ExecuteNonQuery( - "LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters_layers FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'", - Config.DatabaseNonLocal ? "LOCAL " : "", m_LayersPath); - } - } - } - - public void CollectGuilds(DateTime endTime) - { - m_List.AddRange(BaseGuild.List.Values); - m_Stage = Stage.DumpingGuilds; - m_Index = 0; - } - - public void InsertGuild(Guild guild) - { - string guildType = "Standard"; - - switch (guild.Type) - { - case GuildType.Chaos: - guildType = "Chaos"; - break; - case GuildType.Order: - guildType = "Order"; - break; - } - - ExecuteNonQuery( - "INSERT INTO myrunuo_guilds (guild_id, guild_name, guild_abbreviation, guild_website, guild_charter, guild_type, guild_wars, guild_members, guild_master) VALUES ({0}, '{1}', {2}, {3}, {4}, '{5}', {6}, {7}, {8})", - guild.Id.ToString(), SafeString(guild.Name), - guild.Abbreviation == "none" ? "NULL" : "'" + SafeString(guild.Abbreviation) + "'", - guild.Website == null ? "NULL" : "'" + SafeString(guild.Website) + "'", - guild.Charter == null ? "NULL" : "'" + SafeString(guild.Charter) + "'", guildType, - guild.Enemies.Count.ToString(), guild.Members.Count.ToString(), guild.Leader.Serial.Value.ToString()); - } - - public void InsertWars(Guild guild) - { - List wars = guild.Enemies; - - string ourId = guild.Id.ToString(); - - for (int i = 0; i < wars.Count; ++i) - { - Guild them = wars[i]; - string theirId = them.Id.ToString(); - - ExecuteNonQueryIfNull( - string.Format( - "SELECT guild_1 FROM myrunuo_guilds_wars WHERE (guild_1={0} AND guild_2={1}) OR (guild_1={1} AND guild_2={0})", - ourId, theirId), - $"INSERT INTO myrunuo_guilds_wars (guild_1, guild_2) VALUES ({ourId}, {theirId})"); - } - } - - public void DumpGuilds(DateTime endTime) - { - CheckConnection(); - - for (int i = m_Index; i < m_List.Count; ++i) - { - Guild guild = (Guild)m_List[i]; - - if (!guild.Disbanded) - { - InsertGuild(guild); - InsertWars(guild); - } - - ++m_Index; - - if (DateTime.UtcNow >= endTime) - break; - } - - if (m_Index == m_List.Count) - { - m_List.Clear(); - m_Stage = Stage.Complete; - m_Index = 0; - } - } - - private enum Stage - { - CollectingMobiles, - DumpingMobiles, - CollectingGuilds, - DumpingGuilds, - Complete - } - } -} diff --git a/Scripts/Engines/MyRunUO/MyRunUOStatus.cs b/Scripts/Engines/MyRunUO/MyRunUOStatus.cs deleted file mode 100644 index 727b3a440..000000000 --- a/Scripts/Engines/MyRunUO/MyRunUOStatus.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections.Generic; -using Server.Commands; -using Server.Network; - -namespace Server.Engines.MyRunUO -{ - public class MyRunUOStatus - { - private static DatabaseCommandQueue m_Command; - - public static void Initialize() - { - if (Config.Enabled) - { - Timer.DelayCall(TimeSpan.FromSeconds(20.0), Config.StatusUpdateInterval, Begin); - - CommandSystem.Register("UpdateWebStatus", AccessLevel.Administrator, UpdateWebStatus_OnCommand); - } - } - - [Usage("UpdateWebStatus")] - [Description("Starts the process of updating the MyRunUO online status database.")] - public static void UpdateWebStatus_OnCommand(CommandEventArgs e) - { - if (m_Command == null || m_Command.HasCompleted) - { - Begin(); - e.Mobile.SendMessage("Web status update process has been started."); - } - else - { - e.Mobile.SendMessage("Web status database is already being updated."); - } - } - - public static void Begin() - { - if (m_Command?.HasCompleted == false) - return; - - Console.WriteLine("MyRunUO: Updating status database"); - - try - { - m_Command = new DatabaseCommandQueue("MyRunUO: Status database updated in {0:F1} seconds", - "MyRunUO Status Database Thread"); - - m_Command.Enqueue("DELETE FROM myrunuo_status"); - - List online = NetState.Instances; - - for (int i = 0; i < online.Count; ++i) - { - NetState ns = online[i]; - Mobile mob = ns.Mobile; - - if (mob != null) - m_Command.Enqueue( - $"INSERT INTO myrunuo_status (char_id) VALUES ({mob.Serial.Value.ToString()})"); - } - } - catch (Exception e) - { - Console.WriteLine("MyRunUO: Error updating status database"); - Console.WriteLine(e); - } - - m_Command?.Enqueue(null); - } - } -} diff --git a/Scripts/Engines/Reports/Objects/Charts/BarGraph.cs b/Scripts/Engines/Reports/Objects/Charts/BarGraph.cs deleted file mode 100644 index 9814480de..000000000 --- a/Scripts/Engines/Reports/Objects/Charts/BarGraph.cs +++ /dev/null @@ -1,307 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Server.Engines.Reports -{ - public enum BarGraphRenderMode - { - Bars, - Lines - } - - public class BarGraph : Chart - { - public BarGraph(string name, string fileName, int ticks, string xTitle, string yTitle, BarGraphRenderMode rm) - { - m_Name = name; - m_FileName = fileName; - Ticks = ticks; - this.xTitle = xTitle; - this.yTitle = yTitle; - RenderMode = rm; - } - - private BarGraph() - { - } - - public int Ticks{ get; set; } - - public BarGraphRenderMode RenderMode{ get; set; } - - public string xTitle{ get; set; } - - public string yTitle{ get; set; } - - public int FontSize{ get; set; } = 7; - - public int Interval{ get; set; } = 1; - - public BarRegion[] Regions{ get; set; } - - public override void SerializeAttributes(PersistanceWriter op) - { - base.SerializeAttributes(op); - - op.SetInt32("t", Ticks); - op.SetInt32("r", (int)RenderMode); - - op.SetString("x", xTitle); - op.SetString("y", yTitle); - - op.SetInt32("s", FontSize); - op.SetInt32("i", Interval); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - base.DeserializeAttributes(ip); - - Ticks = ip.GetInt32("t"); - RenderMode = (BarGraphRenderMode)ip.GetInt32("r"); - - xTitle = Utility.Intern(ip.GetString("x")); - yTitle = Utility.Intern(ip.GetString("y")); - - FontSize = ip.GetInt32("s"); - Interval = ip.GetInt32("i"); - } - - public static int LookupReportValue(Snapshot ss, string reportName, string valueName) - { - for (int j = 0; j < ss.Children.Count; ++j) - { - if (!(ss.Children[j] is Report report) || report.Name != reportName) - continue; - - for (int k = 0; k < report.Items.Count; ++k) - { - ReportItem item = report.Items[k]; - - if (item.Values[0].Value == valueName) - return Utility.ToInt32(item.Values[1].Value); - } - - break; - } - - return -1; - } - - public static BarGraph DailyAverage(SnapshotHistory history, string reportName, string valueName) - { - int[] totals = new int[24]; - int[] counts = new int[24]; - - int min = history.Snapshots.Count - 7 * 24; // averages over one week - - if (min < 0) - min = 0; - - for (int i = min; i < history.Snapshots.Count; ++i) - { - Snapshot ss = history.Snapshots[i]; - - int val = LookupReportValue(ss, reportName, valueName); - - if (val == -1) - continue; - - int hour = ss.TimeStamp.TimeOfDay.Hours; - - totals[hour] += val; - counts[hour]++; - } - - BarGraph barGraph = new BarGraph("Hourly average " + valueName, "graphs_" + valueName.ToLower() + "_avg", 10, - "Time", valueName, BarGraphRenderMode.Lines); - - barGraph.FontSize = 6; - - for (int i = 7; i <= totals.Length + 7; ++i) - { - int val; - - if (counts[i % totals.Length] == 0) - val = 0; - else - val = (totals[i % totals.Length] + counts[i % totals.Length] / 2) / counts[i % totals.Length]; - - int realHours = i % totals.Length; - int hours; - - if (realHours == 0) - hours = 12; - else if (realHours > 12) - hours = realHours - 12; - else - hours = realHours; - - barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val); - } - - return barGraph; - } - - public static BarGraph Growth(SnapshotHistory history, string reportName, string valueName) - { - BarGraph barGraph = new BarGraph("Growth of " + valueName + " over time", - "graphs_" + valueName.ToLower() + "_growth", 10, "Time", valueName, BarGraphRenderMode.Lines); - - barGraph.FontSize = 6; - barGraph.Interval = 7; - - DateTime startPeriod = history.Snapshots[0].TimeStamp.Date + TimeSpan.FromDays(1.0); - DateTime endPeriod = history.Snapshots[history.Snapshots.Count - 1].TimeStamp.Date; - - List regions = new List(); - - DateTime curDate = DateTime.MinValue; - int curPeak = -1; - int curLow = 1000; - int curTotl = 0; - int curCont = 0; - int curValu; - - for (int i = 0; i < history.Snapshots.Count; ++i) - { - Snapshot ss = history.Snapshots[i]; - DateTime timeStamp = ss.TimeStamp; - - if (timeStamp < startPeriod || timeStamp >= endPeriod) - continue; - - int val = LookupReportValue(ss, reportName, valueName); - - if (val == -1) - continue; - - DateTime thisDate = timeStamp.Date; - - if (curDate == DateTime.MinValue) - curDate = thisDate; - - curCont++; - curTotl += val; - curValu = curTotl / curCont; - - if (curDate != thisDate && curValu >= 0) - { - string mnthName = thisDate.ToString("MMMM"); - - if (regions.Count == 0) - { - regions.Add(new BarRegion(barGraph.Items.Count, barGraph.Items.Count, mnthName)); - } - else - { - BarRegion region = regions[regions.Count - 1]; - - if (region.m_Name == mnthName) - region.m_RangeTo = barGraph.Items.Count; - else - regions.Add(new BarRegion(barGraph.Items.Count, barGraph.Items.Count, mnthName)); - } - - barGraph.Items.Add(thisDate.Day.ToString(), curValu); - - curPeak = val; - curLow = val; - } - else - { - if (val > curPeak) - curPeak = val; - - if (val > 0 && val < curLow) - curLow = val; - } - - curDate = thisDate; - } - - barGraph.Regions = regions.ToArray(); - - return barGraph; - } - - public static BarGraph OverTime(SnapshotHistory history, string reportName, string valueName, int step, int max, - int ival) - { - BarGraph barGraph = new BarGraph(valueName + " over time", "graphs_" + valueName.ToLower() + "_ot", 10, "Time", - valueName, BarGraphRenderMode.Lines); - - TimeSpan ts = TimeSpan.FromHours(max * step - 0.5); - - DateTime mostRecent = history.Snapshots[history.Snapshots.Count - 1].TimeStamp; - DateTime minTime = mostRecent - ts; - - barGraph.FontSize = 6; - barGraph.Interval = ival; - - List regions = new List(); - - for (int i = 0; i < history.Snapshots.Count; ++i) - { - Snapshot ss = history.Snapshots[i]; - DateTime timeStamp = ss.TimeStamp; - - if (timeStamp < minTime) - continue; - - if (i % step != 0) - continue; - - int val = LookupReportValue(ss, reportName, valueName); - - if (val == -1) - continue; - - int realHours = timeStamp.TimeOfDay.Hours; - int hours; - - if (realHours == 0) - hours = 12; - else if (realHours > 12) - hours = realHours - 12; - else - hours = realHours; - - string dayName = timeStamp.DayOfWeek.ToString(); - - if (regions.Count == 0) - { - regions.Add(new BarRegion(barGraph.Items.Count, barGraph.Items.Count, dayName)); - } - else - { - BarRegion region = regions[regions.Count - 1]; - - if (region.m_Name == dayName) - region.m_RangeTo = barGraph.Items.Count; - else - regions.Add(new BarRegion(barGraph.Items.Count, barGraph.Items.Count, dayName)); - } - - barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val); - } - - barGraph.Regions = regions.ToArray(); - - return barGraph; - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("bg", Construct); - - private static PersistableObject Construct() - { - return new BarGraph(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Charts/Chart.cs b/Scripts/Engines/Reports/Objects/Charts/Chart.cs deleted file mode 100644 index 9509e4e7e..000000000 --- a/Scripts/Engines/Reports/Objects/Charts/Chart.cs +++ /dev/null @@ -1,52 +0,0 @@ -namespace Server.Engines.Reports -{ - public abstract class Chart : PersistableObject - { - protected string m_FileName; - protected ChartItemCollection m_Items; - protected string m_Name; - - public Chart() - { - m_Items = new ChartItemCollection(); - } - - public string Name - { - get => m_Name; - set => m_Name = value; - } - - public string FileName - { - get => m_FileName; - set => m_FileName = value; - } - - public ChartItemCollection Items => m_Items; - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetString("n", m_Name); - op.SetString("f", m_FileName); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - m_Name = Utility.Intern(ip.GetString("n")); - m_FileName = Utility.Intern(ip.GetString("f")); - } - - public override void SerializeChildren(PersistanceWriter op) - { - for (int i = 0; i < m_Items.Count; ++i) - m_Items[i].Serialize(op); - } - - public override void DeserializeChildren(PersistanceReader ip) - { - while (ip.HasChild) - m_Items.Add(ip.GetChild() as ChartItem); - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Charts/ChartItem.cs b/Scripts/Engines/Reports/Objects/Charts/ChartItem.cs deleted file mode 100644 index a3ba24b00..000000000 --- a/Scripts/Engines/Reports/Objects/Charts/ChartItem.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Server.Engines.Reports -{ - public class ChartItem : PersistableObject - { - private ChartItem() - { - } - - public ChartItem(string name, int value) - { - Name = name; - Value = value; - } - - public string Name{ get; set; } - - public int Value{ get; set; } - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetString("n", Name); - op.SetInt32("v", Value); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - Name = Utility.Intern(ip.GetString("n")); - Value = ip.GetInt32("v"); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("ci", Construct); - - private static PersistableObject Construct() - { - return new ChartItem(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Charts/ChartItemCollection.cs b/Scripts/Engines/Reports/Objects/Charts/ChartItemCollection.cs deleted file mode 100644 index b87df7344..000000000 --- a/Scripts/Engines/Reports/Objects/Charts/ChartItemCollection.cs +++ /dev/null @@ -1,187 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 1.1.4322.573 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.ChartItem. - /// - public class ChartItemCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.ChartItem at a specific position in the ChartItemCollection. - /// - public ChartItem this[int index] - { - get => (ChartItem)List[index]; - set => List[index] = value; - } - - public int Add(string name, int value) - { - return Add(new ChartItem(name, value)); - } - - /// - /// Append a Server.Engines.Reports.ChartItem entry to this collection. - /// - /// Server.Engines.Reports.ChartItem instance. - /// The position into which the new element was inserted. - public int Add(ChartItem value) - { - return List.Add(value); - } - - /// - /// Determines whether a specified Server.Engines.Reports.ChartItem instance is in this collection. - /// - /// Server.Engines.Reports.ChartItem instance to search for. - /// True if the Server.Engines.Reports.ChartItem instance is in the collection; otherwise false. - public bool Contains(ChartItem value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.ChartItem instance is in this collection. - /// - /// Server.Engines.Reports.ChartItem instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.ChartItem instance. If the object is not found, the - /// return value is -1. - /// - public int IndexOf(ChartItem value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.ChartItem instance from this collection. - /// - /// The Server.Engines.Reports.ChartItem instance to remove. - public void Remove(ChartItem value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.ChartItem instance. - /// - /// An Server.Engines.Reports.ChartItem's enumerator. - public new ChartItemCollectionEnumerator GetEnumerator() - { - return new ChartItemCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.ChartItem instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.ChartItem instance to insert. - public void Insert(int index, ChartItem value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.ChartItem. - /// - public class ChartItemCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private ChartItemCollection _collection; - - /// - /// Current element pointed to. - /// - private ChartItem _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal ChartItemCollectionEnumerator(ChartItemCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.ChartItem object in the enumerated ChartItemCollection currently indexed by this instance. - /// - public ChartItem Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Charts/PieChart.cs b/Scripts/Engines/Reports/Objects/Charts/PieChart.cs deleted file mode 100644 index 6bbc532cd..000000000 --- a/Scripts/Engines/Reports/Objects/Charts/PieChart.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Server.Engines.Reports -{ - public class PieChart : Chart - { - public PieChart(string name, string fileName, bool showPercents) - { - m_Name = name; - m_FileName = fileName; - ShowPercents = showPercents; - } - - private PieChart() - { - } - - public bool ShowPercents{ get; set; } - - public override void SerializeAttributes(PersistanceWriter op) - { - base.SerializeAttributes(op); - - op.SetBoolean("p", ShowPercents); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - base.DeserializeAttributes(ip); - - ShowPercents = ip.GetBoolean("p"); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("pc", Construct); - - private static PersistableObject Construct() - { - return new PieChart(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ItemValue.cs b/Scripts/Engines/Reports/Objects/Reports/ItemValue.cs deleted file mode 100644 index d2f045b48..000000000 --- a/Scripts/Engines/Reports/Objects/Reports/ItemValue.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace Server.Engines.Reports -{ - public class ItemValue : PersistableObject - { - private string m_Value; - - private ItemValue() - { - } - - public ItemValue(string value) : this(value, null) - { - } - - public ItemValue(string value, string format) - { - m_Value = value; - Format = format; - } - - public string Value - { - get => m_Value; - set => m_Value = value; - } - - public string Format{ get; set; } - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetString("v", m_Value); - op.SetString("f", Format); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - m_Value = ip.GetString("v"); - Format = Utility.Intern(ip.GetString("f")); - - if (Format == null) - Utility.Intern(ref m_Value); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("iv", Construct); - - private static PersistableObject Construct() - { - return new ItemValue(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ItemValueCollection.cs b/Scripts/Engines/Reports/Objects/Reports/ItemValueCollection.cs deleted file mode 100644 index 621d28b9d..000000000 --- a/Scripts/Engines/Reports/Objects/Reports/ItemValueCollection.cs +++ /dev/null @@ -1,192 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 1.1.4322.573 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.ItemValue. - /// - public class ItemValueCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.ItemValue at a specific position in the ItemValueCollection. - /// - public ItemValue this[int index] - { - get => (ItemValue)List[index]; - set => List[index] = value; - } - - public int Add(string value) - { - return Add(new ItemValue(value)); - } - - public int Add(string value, string format) - { - return Add(new ItemValue(value, format)); - } - - /// - /// Append a Server.Engines.Reports.ItemValue entry to this collection. - /// - /// Server.Engines.Reports.ItemValue instance. - /// The position into which the new element was inserted. - public int Add(ItemValue value) - { - return List.Add(value); - } - - /// - /// Determines whether a specified Server.Engines.Reports.ItemValue instance is in this collection. - /// - /// Server.Engines.Reports.ItemValue instance to search for. - /// True if the Server.Engines.Reports.ItemValue instance is in the collection; otherwise false. - public bool Contains(ItemValue value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.ItemValue instance is in this collection. - /// - /// Server.Engines.Reports.ItemValue instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.ItemValue instance. If the object is not found, the - /// return value is -1. - /// - public int IndexOf(ItemValue value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.ItemValue instance from this collection. - /// - /// The Server.Engines.Reports.ItemValue instance to remove. - public void Remove(ItemValue value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.ItemValue instance. - /// - /// An Server.Engines.Reports.ItemValue's enumerator. - public new ItemValueCollectionEnumerator GetEnumerator() - { - return new ItemValueCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.ItemValue instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.ItemValue instance to insert. - public void Insert(int index, ItemValue value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.ItemValue. - /// - public class ItemValueCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private ItemValueCollection _collection; - - /// - /// Current element pointed to. - /// - private ItemValue _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal ItemValueCollectionEnumerator(ItemValueCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.ItemValue object in the enumerated ItemValueCollection currently indexed by this instance. - /// - public ItemValue Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/Report.cs b/Scripts/Engines/Reports/Objects/Reports/Report.cs deleted file mode 100644 index 3eb8475d9..000000000 --- a/Scripts/Engines/Reports/Objects/Reports/Report.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Server.Engines.Reports -{ - public class Report : PersistableObject - { - private Report() : this(null, null) - { - } - - public Report(string name, string width) - { - Name = name; - Width = width; - Columns = new ReportColumnCollection(); - Items = new ReportItemCollection(); - } - - public string Name{ get; set; } - - public string Width{ get; set; } - - public ReportColumnCollection Columns{ get; } - - public ReportItemCollection Items{ get; } - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetString("n", Name); - op.SetString("w", Width); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - Name = Utility.Intern(ip.GetString("n")); - Width = Utility.Intern(ip.GetString("w")); - } - - public override void SerializeChildren(PersistanceWriter op) - { - for (int i = 0; i < Columns.Count; ++i) - Columns[i].Serialize(op); - - for (int i = 0; i < Items.Count; ++i) - Items[i].Serialize(op); - } - - public override void DeserializeChildren(PersistanceReader ip) - { - while (ip.HasChild) - { - PersistableObject child = ip.GetChild(); - - if (child is ReportColumn column) - Columns.Add(column); - else if (child is ReportItem item) - Items.Add(item); - } - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("rp", Construct); - - private static PersistableObject Construct() - { - return new Report(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ReportColumn.cs b/Scripts/Engines/Reports/Objects/Reports/ReportColumn.cs deleted file mode 100644 index aae4f3121..000000000 --- a/Scripts/Engines/Reports/Objects/Reports/ReportColumn.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace Server.Engines.Reports -{ - public class ReportColumn : PersistableObject - { - private ReportColumn() - { - } - - public ReportColumn(string width, string align) : this(width, align, null) - { - } - - public ReportColumn(string width, string align, string name) - { - Width = width; - Align = align; - Name = name; - } - - public string Width{ get; set; } - - public string Align{ get; set; } - - public string Name{ get; set; } - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetString("w", Width); - op.SetString("a", Align); - op.SetString("n", Name); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - Width = Utility.Intern(ip.GetString("w")); - Align = Utility.Intern(ip.GetString("a")); - Name = Utility.Intern(ip.GetString("n")); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("rc", Construct); - - private static PersistableObject Construct() - { - return new ReportColumn(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ReportColumnCollection.cs b/Scripts/Engines/Reports/Objects/Reports/ReportColumnCollection.cs deleted file mode 100644 index 198534736..000000000 --- a/Scripts/Engines/Reports/Objects/Reports/ReportColumnCollection.cs +++ /dev/null @@ -1,193 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 1.1.4322.573 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.ReportColumn. - /// - public class ReportColumnCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.ReportColumn at a specific position in the ReportColumnCollection. - /// - public ReportColumn this[int index] - { - get => (ReportColumn)List[index]; - set => List[index] = value; - } - - public int Add(string width, string align) - { - return Add(new ReportColumn(width, align)); - } - - public int Add(string width, string align, string name) - { - return Add(new ReportColumn(width, align, name)); - } - - /// - /// Append a Server.Engines.Reports.ReportColumn entry to this collection. - /// - /// Server.Engines.Reports.ReportColumn instance. - /// The position into which the new element was inserted. - public int Add(ReportColumn value) - { - return List.Add(value); - } - - /// - /// Determines whether a specified Server.Engines.Reports.ReportColumn instance is in this collection. - /// - /// Server.Engines.Reports.ReportColumn instance to search for. - /// True if the Server.Engines.Reports.ReportColumn instance is in the collection; otherwise false. - public bool Contains(ReportColumn value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.ReportColumn instance is in this collection. - /// - /// Server.Engines.Reports.ReportColumn instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.ReportColumn instance. If the object is not found, the - /// return value is -1. - /// - public int IndexOf(ReportColumn value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.ReportColumn instance from this collection. - /// - /// The Server.Engines.Reports.ReportColumn instance to remove. - public void Remove(ReportColumn value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.ReportColumn instance. - /// - /// An Server.Engines.Reports.ReportColumn's enumerator. - public new ReportColumnCollectionEnumerator GetEnumerator() - { - return new ReportColumnCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.ReportColumn instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.ReportColumn instance to insert. - public void Insert(int index, ReportColumn value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.ReportColumn. - /// - public class ReportColumnCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private ReportColumnCollection _collection; - - /// - /// Current element pointed to. - /// - private ReportColumn _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal ReportColumnCollectionEnumerator(ReportColumnCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.ReportColumn object in the enumerated ReportColumnCollection currently indexed by this - /// instance. - /// - public ReportColumn Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ReportItem.cs b/Scripts/Engines/Reports/Objects/Reports/ReportItem.cs deleted file mode 100644 index 336c6b2ea..000000000 --- a/Scripts/Engines/Reports/Objects/Reports/ReportItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Server.Engines.Reports -{ - public class ReportItem : PersistableObject - { - public ReportItem() - { - Values = new ItemValueCollection(); - } - - public ItemValueCollection Values{ get; } - - public override void SerializeChildren(PersistanceWriter op) - { - for (int i = 0; i < Values.Count; ++i) - Values[i].Serialize(op); - } - - public override void DeserializeChildren(PersistanceReader ip) - { - while (ip.HasChild) - Values.Add(ip.GetChild() as ItemValue); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("ri", Construct); - - private static PersistableObject Construct() - { - return new ReportItem(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ReportItemCollection.cs b/Scripts/Engines/Reports/Objects/Reports/ReportItemCollection.cs deleted file mode 100644 index 1bdee17c2..000000000 --- a/Scripts/Engines/Reports/Objects/Reports/ReportItemCollection.cs +++ /dev/null @@ -1,198 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 1.1.4322.573 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.ReportItem. - /// - public class ReportItemCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.ReportItem at a specific position in the ReportItemCollection. - /// - public ReportItem this[int index] - { - get => (ReportItem)List[index]; - set => List[index] = value; - } - - public int Add(string name, object value) - { - return Add(name, value, null); - } - - public int Add(string name, object value, string format) - { - ReportItem item = new ReportItem(); - - item.Values.Add(name); - item.Values.Add(value == null ? "" : value.ToString(), format); - - return Add(item); - } - - /// - /// Append a Server.Engines.Reports.ReportItem entry to this collection. - /// - /// Server.Engines.Reports.ReportItem instance. - /// The position into which the new element was inserted. - public int Add(ReportItem value) - { - return List.Add(value); - } - - /// - /// Determines whether a specified Server.Engines.Reports.ReportItem instance is in this collection. - /// - /// Server.Engines.Reports.ReportItem instance to search for. - /// True if the Server.Engines.Reports.ReportItem instance is in the collection; otherwise false. - public bool Contains(ReportItem value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.ReportItem instance is in this collection. - /// - /// Server.Engines.Reports.ReportItem instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.ReportItem instance. If the object is not found, the - /// return value is -1. - /// - public int IndexOf(ReportItem value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.ReportItem instance from this collection. - /// - /// The Server.Engines.Reports.ReportItem instance to remove. - public void Remove(ReportItem value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.ReportItem instance. - /// - /// An Server.Engines.Reports.ReportItem's enumerator. - public new ReportItemCollectionEnumerator GetEnumerator() - { - return new ReportItemCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.ReportItem instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.ReportItem instance to insert. - public void Insert(int index, ReportItem value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.ReportItem. - /// - public class ReportItemCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private ReportItemCollection _collection; - - /// - /// Current element pointed to. - /// - private ReportItem _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal ReportItemCollectionEnumerator(ReportItemCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.ReportItem object in the enumerated ReportItemCollection currently indexed by this - /// instance. - /// - public ReportItem Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Snapshots/Snapshot.cs b/Scripts/Engines/Reports/Objects/Snapshots/Snapshot.cs deleted file mode 100644 index 52f51d611..000000000 --- a/Scripts/Engines/Reports/Objects/Snapshots/Snapshot.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; - -namespace Server.Engines.Reports -{ - public class Snapshot : PersistableObject - { - public Snapshot() - { - Children = new ObjectCollection(); - } - - public DateTime TimeStamp{ get; set; } - - public ObjectCollection Children{ get; set; } - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetDateTime("t", TimeStamp); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - TimeStamp = ip.GetDateTime("t"); - } - - public override void SerializeChildren(PersistanceWriter op) - { - for (int i = 0; i < Children.Count; ++i) - Children[i].Serialize(op); - } - - public override void DeserializeChildren(PersistanceReader ip) - { - while (ip.HasChild) - Children.Add(ip.GetChild()); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("ss", Construct); - - private static PersistableObject Construct() - { - return new Snapshot(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Snapshots/SnapshotCollection.cs b/Scripts/Engines/Reports/Objects/Snapshots/SnapshotCollection.cs deleted file mode 100644 index ce1b715b6..000000000 --- a/Scripts/Engines/Reports/Objects/Snapshots/SnapshotCollection.cs +++ /dev/null @@ -1,182 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 1.1.4322.573 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.Snapshot. - /// - public class SnapshotCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.Snapshot at a specific position in the SnapshotCollection. - /// - public Snapshot this[int index] - { - get => (Snapshot)List[index]; - set => List[index] = value; - } - - /// - /// Append a Server.Engines.Reports.Snapshot entry to this collection. - /// - /// Server.Engines.Reports.Snapshot instance. - /// The position into which the new element was inserted. - public int Add(Snapshot value) - { - return List.Add(value); - } - - /// - /// Determines whether a specified Server.Engines.Reports.Snapshot instance is in this collection. - /// - /// Server.Engines.Reports.Snapshot instance to search for. - /// True if the Server.Engines.Reports.Snapshot instance is in the collection; otherwise false. - public bool Contains(Snapshot value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.Snapshot instance is in this collection. - /// - /// Server.Engines.Reports.Snapshot instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.Snapshot instance. If the object is not found, the - /// return value is -1. - /// - public int IndexOf(Snapshot value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.Snapshot instance from this collection. - /// - /// The Server.Engines.Reports.Snapshot instance to remove. - public void Remove(Snapshot value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.Snapshot instance. - /// - /// An Server.Engines.Reports.Snapshot's enumerator. - public new SnapshotCollectionEnumerator GetEnumerator() - { - return new SnapshotCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.Snapshot instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.Snapshot instance to insert. - public void Insert(int index, Snapshot value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.Snapshot. - /// - public class SnapshotCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private SnapshotCollection _collection; - - /// - /// Current element pointed to. - /// - private Snapshot _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal SnapshotCollectionEnumerator(SnapshotCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.Snapshot object in the enumerated SnapshotCollection currently indexed by this instance. - /// - public Snapshot Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Snapshots/SnapshotHistory.cs b/Scripts/Engines/Reports/Objects/Snapshots/SnapshotHistory.cs deleted file mode 100644 index f9d5f186d..000000000 --- a/Scripts/Engines/Reports/Objects/Snapshots/SnapshotHistory.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.IO; - -namespace Server.Engines.Reports -{ - public class SnapshotHistory : PersistableObject - { - public SnapshotHistory() - { - Snapshots = new SnapshotCollection(); - } - - public SnapshotCollection Snapshots{ get; set; } - - public void Save() - { - string path = Path.Combine(Core.BaseDirectory, "reportHistory.xml"); - PersistanceWriter pw = new XmlPersistanceWriter(path, "Stats"); - - pw.WriteDocument(this); - - pw.Close(); - } - - public void Load() - { - string path = Path.Combine(Core.BaseDirectory, "reportHistory.xml"); - - if (!File.Exists(path)) - return; - - PersistanceReader pr = new XmlPersistanceReader(path, "Stats"); - - pr.ReadDocument(this); - - pr.Close(); - } - - public override void SerializeChildren(PersistanceWriter op) - { - for (int i = 0; i < Snapshots.Count; ++i) - Snapshots[i].Serialize(op); - } - - public override void DeserializeChildren(PersistanceReader ip) - { - while (ip.HasChild) - Snapshots.Add(ip.GetChild() as Snapshot); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("sh", Construct); - - private static PersistableObject Construct() - { - return new SnapshotHistory(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/Info.cs b/Scripts/Engines/Reports/Objects/Staffing/Info.cs deleted file mode 100644 index 5f7d395d3..000000000 --- a/Scripts/Engines/Reports/Objects/Staffing/Info.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using Server.Accounting; - -namespace Server.Engines.Reports -{ - public abstract class BaseInfo : IComparable - { - private string m_Display; - - public BaseInfo(string account) - { - Account = account; - Pages = new PageInfoCollection(); - } - - public static TimeSpan SortRange{ get; set; } - - public string Account{ get; set; } - - public PageInfoCollection Pages{ get; set; } - - public string Display - { - get - { - if (m_Display != null) - return m_Display; - - if (Account != null) - { - IAccount acct = Accounts.GetAccount(Account); - - if (acct != null) - { - Mobile mob = null; - - for (int i = 0; i < acct.Length; ++i) - { - Mobile check = acct[i]; - - if (check != null && (mob == null || check.AccessLevel > mob.AccessLevel)) - mob = check; - } - - if (mob?.Name != null && mob.Name.Length > 0) - return m_Display = mob.Name; - } - } - - return m_Display = Account; - } - } - - public int CompareTo(BaseInfo cmp) - { - int v = cmp?.GetPageCount(cmp is StaffInfo ? PageResolution.Handled : PageResolution.None, - DateTime.UtcNow - SortRange, DateTime.UtcNow) ?? 0 - - GetPageCount(this is StaffInfo ? PageResolution.Handled : PageResolution.None, - DateTime.UtcNow - SortRange, DateTime.UtcNow); - - return v == 0 ? string.Compare(Display, cmp.Display) : v; - } - - public int GetPageCount(PageResolution res, DateTime min, DateTime max) - { - return StaffHistory.GetPageCount(Pages, res, min, max); - } - - public void Register(PageInfo page) - { - Pages.Add(page); - } - - public void Unregister(PageInfo page) - { - Pages.Remove(page); - } - } - - public class StaffInfo : BaseInfo - { - public StaffInfo(string account) : base(account) - { - } - } - - public class UserInfo : BaseInfo - { - public UserInfo(string account) : base(account) - { - } - } -} diff --git a/Scripts/Engines/Reports/Objects/Staffing/PageInfo.cs b/Scripts/Engines/Reports/Objects/Staffing/PageInfo.cs deleted file mode 100644 index 9b6ecabec..000000000 --- a/Scripts/Engines/Reports/Objects/Staffing/PageInfo.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using Server.Accounting; -using Server.Engines.Help; - -namespace Server.Engines.Reports -{ - public enum PageResolution - { - None, - Handled, - Deleted, - Logged, - Canceled - } - - public class PageInfo : PersistableObject - { - private StaffHistory m_History; - private StaffInfo m_Resolver; - private UserInfo m_Sender; - - private string m_SentBy; - - public PageInfo() - { - Responses = new ResponseInfoCollection(); - } - - public PageInfo(PageEntry entry) - { - PageType = entry.Type; - - TimeSent = entry.Sent; - m_SentBy = GetAccount(entry.Sender); - - Message = entry.Message; - Responses = new ResponseInfoCollection(); - } - - public StaffInfo Resolver - { - get => m_Resolver; - set - { - if (m_Resolver == value) - return; - - lock (StaffHistory.RenderLock) - { - m_Resolver?.Unregister(this); - - m_Resolver = value; - - m_Resolver?.Register(this); - } - } - } - - public UserInfo Sender - { - get => m_Sender; - set - { - if (m_Sender == value) - return; - - lock (StaffHistory.RenderLock) - { - m_Sender?.Unregister(this); - - m_Sender = value; - - m_Sender?.Register(this); - } - } - } - - public StaffHistory History - { - get => m_History; - set - { - if (m_History == value) - return; - - if (m_History != null) - { - Sender = null; - Resolver = null; - } - - m_History = value; - - if (m_History != null) - { - Sender = m_History.GetUserInfo(m_SentBy); - UpdateResolver(); - } - } - } - - public PageType PageType{ get; set; } - - public PageResolution Resolution{ get; private set; } - - public DateTime TimeSent{ get; set; } - - public DateTime TimeResolved{ get; private set; } - - public string SentBy - { - get => m_SentBy; - set - { - m_SentBy = value; - - if (m_History != null) - Sender = m_History.GetUserInfo(m_SentBy); - } - } - - public string ResolvedBy{ get; private set; } - - public string Message{ get; set; } - - public ResponseInfoCollection Responses{ get; set; } - - public void UpdateResolver() - { - PageResolution res = GetResolution(out string resolvedBy, out DateTime timeResolved); - - if (m_History != null && IsStaffResolution(res)) - Resolver = m_History.GetStaffInfo(resolvedBy); - else - Resolver = null; - - ResolvedBy = resolvedBy; - TimeResolved = timeResolved; - Resolution = res; - } - - public bool IsStaffResolution(PageResolution res) - { - return res == PageResolution.Handled; - } - - public static PageResolution ResFromResp(string resp) - { - switch (resp) - { - case "[Handled]": return PageResolution.Handled; - case "[Deleting]": return PageResolution.Deleted; - case "[Logout]": return PageResolution.Logged; - case "[Canceled]": return PageResolution.Canceled; - } - - return PageResolution.None; - } - - public PageResolution GetResolution(out string resolvedBy, out DateTime timeResolved) - { - for (int i = Responses.Count - 1; i >= 0; --i) - { - ResponseInfo resp = Responses[i]; - PageResolution res = ResFromResp(resp.Message); - - if (res != PageResolution.None) - { - resolvedBy = resp.SentBy; - timeResolved = resp.TimeStamp; - return res; - } - } - - resolvedBy = m_SentBy; - timeResolved = TimeSent; - return PageResolution.None; - } - - public static string GetAccount(Mobile mob) - { - return mob?.Account is Account acct ? acct.Username : null; - } - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetInt32("p", (int)PageType); - - op.SetDateTime("ts", TimeSent); - op.SetString("s", m_SentBy); - - op.SetString("m", Message); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - PageType = (PageType)ip.GetInt32("p"); - - TimeSent = ip.GetDateTime("ts"); - m_SentBy = ip.GetString("s"); - - Message = ip.GetString("m"); - } - - public override void SerializeChildren(PersistanceWriter op) - { - lock (this) - { - for (int i = 0; i < Responses.Count; ++i) - Responses[i].Serialize(op); - } - } - - public override void DeserializeChildren(PersistanceReader ip) - { - while (ip.HasChild) - Responses.Add(ip.GetChild() as ResponseInfo); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("pi", Construct); - - private static PersistableObject Construct() - { - return new PageInfo(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/PageInfoCollection.cs b/Scripts/Engines/Reports/Objects/Staffing/PageInfoCollection.cs deleted file mode 100644 index 96a76f9ba..000000000 --- a/Scripts/Engines/Reports/Objects/Staffing/PageInfoCollection.cs +++ /dev/null @@ -1,182 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 1.1.4322.573 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.PageInfo. - /// - public class PageInfoCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.PageInfo at a specific position in the PageInfoCollection. - /// - public PageInfo this[int index] - { - get => (PageInfo)List[index]; - set => List[index] = value; - } - - /// - /// Append a Server.Engines.Reports.PageInfo entry to this collection. - /// - /// Server.Engines.Reports.PageInfo instance. - /// The position into which the new element was inserted. - public int Add(PageInfo value) - { - return List.Add(value); - } - - /// - /// Determines whether a specified Server.Engines.Reports.PageInfo instance is in this collection. - /// - /// Server.Engines.Reports.PageInfo instance to search for. - /// True if the Server.Engines.Reports.PageInfo instance is in the collection; otherwise false. - public bool Contains(PageInfo value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.PageInfo instance is in this collection. - /// - /// Server.Engines.Reports.PageInfo instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.PageInfo instance. If the object is not found, the - /// return value is -1. - /// - public int IndexOf(PageInfo value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.PageInfo instance from this collection. - /// - /// The Server.Engines.Reports.PageInfo instance to remove. - public void Remove(PageInfo value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.PageInfo instance. - /// - /// An Server.Engines.Reports.PageInfo's enumerator. - public new PageInfoCollectionEnumerator GetEnumerator() - { - return new PageInfoCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.PageInfo instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.PageInfo instance to insert. - public void Insert(int index, PageInfo value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.PageInfo. - /// - public class PageInfoCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private PageInfoCollection _collection; - - /// - /// Current element pointed to. - /// - private PageInfo _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal PageInfoCollectionEnumerator(PageInfoCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.PageInfo object in the enumerated PageInfoCollection currently indexed by this instance. - /// - public PageInfo Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/QueueStatus.cs b/Scripts/Engines/Reports/Objects/Staffing/QueueStatus.cs deleted file mode 100644 index eb68b29ab..000000000 --- a/Scripts/Engines/Reports/Objects/Staffing/QueueStatus.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; - -namespace Server.Engines.Reports -{ - public class QueueStatus : PersistableObject - { - public QueueStatus() - { - } - - public QueueStatus(int count) - { - TimeStamp = DateTime.UtcNow; - Count = count; - } - - public DateTime TimeStamp{ get; set; } - - public int Count{ get; set; } - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetDateTime("t", TimeStamp); - op.SetInt32("c", Count); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - TimeStamp = ip.GetDateTime("t"); - Count = ip.GetInt32("c"); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("qs", Construct); - - private static PersistableObject Construct() - { - return new QueueStatus(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/QueueStatusCollection.cs b/Scripts/Engines/Reports/Objects/Staffing/QueueStatusCollection.cs deleted file mode 100644 index 7efc7f6dc..000000000 --- a/Scripts/Engines/Reports/Objects/Staffing/QueueStatusCollection.cs +++ /dev/null @@ -1,183 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 1.1.4322.573 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.QueueStatus. - /// - public class QueueStatusCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.QueueStatus at a specific position in the QueueStatusCollection. - /// - public QueueStatus this[int index] - { - get => (QueueStatus)List[index]; - set => List[index] = value; - } - - /// - /// Append a Server.Engines.Reports.QueueStatus entry to this collection. - /// - /// Server.Engines.Reports.QueueStatus instance. - /// The position into which the new element was inserted. - public int Add(QueueStatus value) - { - return List.Add(value); - } - - /// - /// Determines whether a specified Server.Engines.Reports.QueueStatus instance is in this collection. - /// - /// Server.Engines.Reports.QueueStatus instance to search for. - /// True if the Server.Engines.Reports.QueueStatus instance is in the collection; otherwise false. - public bool Contains(QueueStatus value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.QueueStatus instance is in this collection. - /// - /// Server.Engines.Reports.QueueStatus instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.QueueStatus instance. If the object is not found, the - /// return value is -1. - /// - public int IndexOf(QueueStatus value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.QueueStatus instance from this collection. - /// - /// The Server.Engines.Reports.QueueStatus instance to remove. - public void Remove(QueueStatus value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.QueueStatus instance. - /// - /// An Server.Engines.Reports.QueueStatus's enumerator. - public new QueueStatusCollectionEnumerator GetEnumerator() - { - return new QueueStatusCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.QueueStatus instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.QueueStatus instance to insert. - public void Insert(int index, QueueStatus value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.QueueStatus. - /// - public class QueueStatusCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private QueueStatusCollection _collection; - - /// - /// Current element pointed to. - /// - private QueueStatus _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal QueueStatusCollectionEnumerator(QueueStatusCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.QueueStatus object in the enumerated QueueStatusCollection currently indexed by this - /// instance. - /// - public QueueStatus Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/ResponseInfo.cs b/Scripts/Engines/Reports/Objects/Staffing/ResponseInfo.cs deleted file mode 100644 index 7eafcc5e8..000000000 --- a/Scripts/Engines/Reports/Objects/Staffing/ResponseInfo.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; - -namespace Server.Engines.Reports -{ - public class ResponseInfo : PersistableObject - { - public ResponseInfo() - { - } - - public ResponseInfo(string sentBy, string message) - { - TimeStamp = DateTime.UtcNow; - SentBy = sentBy; - Message = message; - } - - public DateTime TimeStamp{ get; set; } - - public string SentBy{ get; set; } - - public string Message{ get; set; } - - public override void SerializeAttributes(PersistanceWriter op) - { - op.SetDateTime("t", TimeStamp); - - op.SetString("s", SentBy); - op.SetString("m", Message); - } - - public override void DeserializeAttributes(PersistanceReader ip) - { - TimeStamp = ip.GetDateTime("t"); - - SentBy = ip.GetString("s"); - Message = ip.GetString("m"); - } - - #region Type Identification - - public static readonly PersistableType ThisTypeID = new PersistableType("rs", Construct); - - private static PersistableObject Construct() - { - return new ResponseInfo(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/ResponseInfoCollection.cs b/Scripts/Engines/Reports/Objects/Staffing/ResponseInfoCollection.cs deleted file mode 100644 index d3ab87e8b..000000000 --- a/Scripts/Engines/Reports/Objects/Staffing/ResponseInfoCollection.cs +++ /dev/null @@ -1,188 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version: 1.1.4322.573 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.ResponseInfo. - /// - public class ResponseInfoCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.ResponseInfo at a specific position in the ResponseInfoCollection. - /// - public ResponseInfo this[int index] - { - get => (ResponseInfo)List[index]; - set => List[index] = value; - } - - public int Add(string sentBy, string message) - { - return Add(new ResponseInfo(sentBy, message)); - } - - /// - /// Append a Server.Engines.Reports.ResponseInfo entry to this collection. - /// - /// Server.Engines.Reports.ResponseInfo instance. - /// The position into which the new element was inserted. - public int Add(ResponseInfo value) - { - return List.Add(value); - } - - /// - /// Determines whether a specified Server.Engines.Reports.ResponseInfo instance is in this collection. - /// - /// Server.Engines.Reports.ResponseInfo instance to search for. - /// True if the Server.Engines.Reports.ResponseInfo instance is in the collection; otherwise false. - public bool Contains(ResponseInfo value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.ResponseInfo instance is in this collection. - /// - /// Server.Engines.Reports.ResponseInfo instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.ResponseInfo instance. If the object is not found, the - /// return value is -1. - /// - public int IndexOf(ResponseInfo value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.ResponseInfo instance from this collection. - /// - /// The Server.Engines.Reports.ResponseInfo instance to remove. - public void Remove(ResponseInfo value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.ResponseInfo instance. - /// - /// An Server.Engines.Reports.ResponseInfo's enumerator. - public new ResponseInfoCollectionEnumerator GetEnumerator() - { - return new ResponseInfoCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.ResponseInfo instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.ResponseInfo instance to insert. - public void Insert(int index, ResponseInfo value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.ResponseInfo. - /// - public class ResponseInfoCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private ResponseInfoCollection _collection; - - /// - /// Current element pointed to. - /// - private ResponseInfo _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal ResponseInfoCollectionEnumerator(ResponseInfoCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.ResponseInfo object in the enumerated ResponseInfoCollection currently indexed by this - /// instance. - /// - public ResponseInfo Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/StaffHistory.cs b/Scripts/Engines/Reports/Objects/Staffing/StaffHistory.cs deleted file mode 100644 index 9352c4303..000000000 --- a/Scripts/Engines/Reports/Objects/Staffing/StaffHistory.cs +++ /dev/null @@ -1,399 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace Server.Engines.Reports -{ - public class StaffHistory : PersistableObject - { - public static readonly PersistableType ThisTypeID = new PersistableType("stfhst", Construct); - public static readonly object RenderLock = new object(); - public static readonly object SaveLock = new object(); - - public StaffHistory() - { - Pages = new PageInfoCollection(); - QueueStats = new QueueStatusCollection(); - - UserInfo = new Dictionary(StringComparer.OrdinalIgnoreCase); - StaffInfo = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - - public PageInfoCollection Pages{ get; set; } - - public QueueStatusCollection QueueStats{ get; set; } - - public Dictionary UserInfo{ get; set; } - - public Dictionary StaffInfo{ get; set; } - - public void AddPage(PageInfo info) - { - lock (SaveLock) - { - Pages.Add(info); - } - - info.History = this; - } - - public StaffInfo GetStaffInfo(string account) - { - lock (RenderLock) - { - if (string.IsNullOrEmpty(account)) - return null; - - if (!StaffInfo.TryGetValue(account, out StaffInfo info)) - StaffInfo[account] = info = new StaffInfo(account); - - return info; - } - } - - public UserInfo GetUserInfo(string account) - { - if (string.IsNullOrEmpty(account)) - return null; - - if (!UserInfo.TryGetValue(account, out UserInfo info)) - UserInfo[account] = info = new UserInfo(account); - - return info; - } - - public void Save() - { - lock (SaveLock) - { - string path = Path.Combine(Core.BaseDirectory, "staffHistory.xml"); - PersistanceWriter pw = new XmlPersistanceWriter(path, "Staff"); - - pw.WriteDocument(this); - - pw.Close(); - } - } - - public void Load() - { - string path = Path.Combine(Core.BaseDirectory, "staffHistory.xml"); - - if (!File.Exists(path)) - return; - - PersistanceReader pr = new XmlPersistanceReader(path, "Staff"); - - pr.ReadDocument(this); - - pr.Close(); - } - - public override void SerializeChildren(PersistanceWriter op) - { - for (int i = 0; i < Pages.Count; ++i) - Pages[i].Serialize(op); - - for (int i = 0; i < QueueStats.Count; ++i) - QueueStats[i].Serialize(op); - } - - public override void DeserializeChildren(PersistanceReader ip) - { - DateTime min = DateTime.UtcNow - TimeSpan.FromDays(8.0); - - while (ip.HasChild) - { - PersistableObject obj = ip.GetChild(); - - if (obj is PageInfo pageInfo) - { - pageInfo.UpdateResolver(); - - if (pageInfo.TimeSent >= min || pageInfo.TimeResolved >= min) - { - Pages.Add(pageInfo); - pageInfo.History = this; - } - else - { - pageInfo.Sender = null; - pageInfo.Resolver = null; - } - } - else if (obj is QueueStatus queueStatus) - { - if (queueStatus.TimeStamp >= min) - QueueStats.Add(queueStatus); - } - } - } - - public StaffInfo[] GetStaff() - { - StaffInfo[] staff = new StaffInfo[StaffInfo.Count]; - int index = 0; - - foreach (StaffInfo staffInfo in StaffInfo.Values) - staff[index++] = staffInfo; - - return staff; - } - - public void Render(ObjectCollection objects) - { - lock (RenderLock) - { - objects.Add(GraphQueueStatus()); - - StaffInfo[] staff = GetStaff(); - - BaseInfo.SortRange = TimeSpan.FromDays(7.0); - Array.Sort(staff); - - objects.Add(GraphHourlyPages(Pages, PageResolution.None, "New pages by hour", "graph_new_pages_hr")); - objects.Add(GraphHourlyPages(Pages, PageResolution.Handled, "Handled pages by hour", - "graph_handled_pages_hr")); - objects.Add(GraphHourlyPages(Pages, PageResolution.Deleted, "Deleted pages by hour", - "graph_deleted_pages_hr")); - objects.Add(GraphHourlyPages(Pages, PageResolution.Canceled, "Canceled pages by hour", - "graph_canceled_pages_hr")); - objects.Add(GraphHourlyPages(Pages, PageResolution.Logged, "Logged-out pages by hour", - "graph_logged_pages_hr")); - - BaseInfo.SortRange = TimeSpan.FromDays(1.0); - Array.Sort(staff); - - objects.Add(ReportTotalPages(staff, TimeSpan.FromDays(1.0), "1 Day")); - objects.AddRange(ChartTotalPages(staff, TimeSpan.FromDays(1.0), "1 Day", "graph_daily_pages")); - - BaseInfo.SortRange = TimeSpan.FromDays(7.0); - Array.Sort(staff); - - objects.Add(ReportTotalPages(staff, TimeSpan.FromDays(7.0), "1 Week")); - objects.AddRange(ChartTotalPages(staff, TimeSpan.FromDays(7.0), "1 Week", "graph_weekly_pages")); - - BaseInfo.SortRange = TimeSpan.FromDays(30.0); - Array.Sort(staff); - - objects.Add(ReportTotalPages(staff, TimeSpan.FromDays(30.0), "1 Month")); - objects.AddRange(ChartTotalPages(staff, TimeSpan.FromDays(30.0), "1 Month", "graph_monthly_pages")); - - for (int i = 0; i < staff.Length; ++i) - objects.Add(GraphHourlyPages(staff[i])); - } - } - - public static int GetPageCount(StaffInfo staff, DateTime min, DateTime max) - { - return GetPageCount(staff.Pages, PageResolution.Handled, min, max); - } - - public static int GetPageCount(PageInfoCollection pages, PageResolution res, DateTime min, DateTime max) - { - int count = 0; - - for (int i = 0; i < pages.Count; ++i) - { - if (res != PageResolution.None && pages[i].Resolution != res) - continue; - - DateTime ts = pages[i].TimeResolved; - - if (ts >= min && ts < max) - ++count; - } - - return count; - } - - private BarGraph GraphQueueStatus() - { - int[] totals = new int[24]; - int[] counts = new int[24]; - - DateTime max = DateTime.UtcNow; - DateTime min = max - TimeSpan.FromDays(7.0); - - for (int i = 0; i < QueueStats.Count; ++i) - { - DateTime ts = QueueStats[i].TimeStamp; - - if (ts >= min && ts < max) - { - TimeSpan time = ts.TimeOfDay; - - int hour = time.Hours; - - totals[hour] += QueueStats[i].Count; - counts[hour]++; - } - } - - BarGraph barGraph = new BarGraph("Average pages in queue", "graph_pagequeue_avg", 10, "Time", "Pages", - BarGraphRenderMode.Lines) { FontSize = 6 }; - - - for (int i = 7; i <= totals.Length + 7; ++i) - { - int val; - - if (counts[i % totals.Length] == 0) - val = 0; - else - val = (totals[i % totals.Length] + counts[i % totals.Length] / 2) / counts[i % totals.Length]; - - int realHours = i % totals.Length; - int hours; - - if (realHours == 0) - hours = 12; - else if (realHours > 12) - hours = realHours - 12; - else - hours = realHours; - - barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val); - } - - return barGraph; - } - - private BarGraph GraphHourlyPages(StaffInfo staff) - { - return GraphHourlyPages(staff.Pages, PageResolution.Handled, "Average pages handled by " + staff.Display, - "graphs_" + staff.Account.ToLower() + "_avg"); - } - - private BarGraph GraphHourlyPages(PageInfoCollection pages, PageResolution res, string title, string fname) - { - int[] totals = new int[24]; - int[] counts = new int[24]; - - DateTime[] dates = new DateTime[24]; - - DateTime max = DateTime.UtcNow; - DateTime min = max - TimeSpan.FromDays(7.0); - - bool sentStamp = res == PageResolution.None; - - for (int i = 0; i < pages.Count; ++i) - { - if (res != PageResolution.None && pages[i].Resolution != res) - continue; - - DateTime ts = sentStamp ? pages[i].TimeSent : pages[i].TimeResolved; - - if (ts >= min && ts < max) - { - DateTime date = ts.Date; - TimeSpan time = ts.TimeOfDay; - - int hour = time.Hours; - - totals[hour]++; - - if (dates[hour] != date) - { - counts[hour]++; - dates[hour] = date; - } - } - } - - BarGraph barGraph = new BarGraph(title, fname, 10, "Time", "Pages", BarGraphRenderMode.Lines) { FontSize = 6 }; - - - for (int i = 7; i <= totals.Length + 7; ++i) - { - int val; - - if (counts[i % totals.Length] == 0) - val = 0; - else - val = (totals[i % totals.Length] + counts[i % totals.Length] / 2) / counts[i % totals.Length]; - - int realHours = i % totals.Length; - int hours; - - if (realHours == 0) - hours = 12; - else if (realHours > 12) - hours = realHours - 12; - else - hours = realHours; - - barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val); - } - - return barGraph; - } - - private Report ReportTotalPages(StaffInfo[] staff, TimeSpan ts, string title) - { - DateTime max = DateTime.UtcNow; - DateTime min = max - ts; - - Report report = new Report(title + " Staff Report", "400"); - - report.Columns.Add("65%", "left", "Staff Name"); - report.Columns.Add("35%", "center", "Page Count"); - - for (int i = 0; i < staff.Length; ++i) - report.Items.Add(staff[i].Display, GetPageCount(staff[i], min, max)); - - return report; - } - - private PersistableObject[] ChartTotalPages(StaffInfo[] staff, TimeSpan ts, string title, string fname) - { - DateTime max = DateTime.UtcNow; - DateTime min = max - ts; - - PieChart staffChart = new PieChart(title + " Staff Chart", fname + "_staff", true); - - int other = 0; - - for (int i = 0; i < staff.Length; ++i) - { - int count = GetPageCount(staff[i], min, max); - - if (i < 12 && count > 0) - staffChart.Items.Add(staff[i].Display, count); - else - other += count; - } - - if (other > 0) - staffChart.Items.Add("Other", other); - - PieChart resChart = new PieChart(title + " Resolutions", fname + "_resol", true); - - int countTotal = GetPageCount(Pages, PageResolution.None, min, max); - int countHandled = GetPageCount(Pages, PageResolution.Handled, min, max); - int countDeleted = GetPageCount(Pages, PageResolution.Deleted, min, max); - int countCanceled = GetPageCount(Pages, PageResolution.Canceled, min, max); - int countLogged = GetPageCount(Pages, PageResolution.Logged, min, max); - int countUnres = countTotal - (countHandled + countDeleted + countCanceled + countLogged); - - resChart.Items.Add("Handled", countHandled); - resChart.Items.Add("Deleted", countDeleted); - resChart.Items.Add("Canceled", countCanceled); - resChart.Items.Add("Logged Out", countLogged); - resChart.Items.Add("Unresolved", countUnres); - - return new PersistableObject[] { staffChart, resChart }; - } - - #region Type Identification - - private static PersistableObject Construct() - { - return new StaffHistory(); - } - - public override PersistableType TypeID => ThisTypeID; - - #endregion - } -} diff --git a/Scripts/Engines/Reports/Persistance/PersistableObject.cs b/Scripts/Engines/Reports/Persistance/PersistableObject.cs deleted file mode 100644 index 0d26608f0..000000000 --- a/Scripts/Engines/Reports/Persistance/PersistableObject.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace Server.Engines.Reports -{ - public abstract class PersistableObject - { - public abstract PersistableType TypeID{ get; } - - public virtual void SerializeAttributes(PersistanceWriter op) - { - } - - public virtual void SerializeChildren(PersistanceWriter op) - { - } - - public void Serialize(PersistanceWriter op) - { - op.BeginObject(TypeID); - SerializeAttributes(op); - op.BeginChildren(); - SerializeChildren(op); - op.FinishChildren(); - op.FinishObject(); - } - - public virtual void DeserializeAttributes(PersistanceReader ip) - { - } - - public virtual void DeserializeChildren(PersistanceReader ip) - { - } - - public void Deserialize(PersistanceReader ip) - { - DeserializeAttributes(ip); - - if (ip.BeginChildren()) - { - DeserializeChildren(ip); - ip.FinishChildren(); - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Persistance/PersistableObjectCollection.cs b/Scripts/Engines/Reports/Persistance/PersistableObjectCollection.cs deleted file mode 100644 index 0d0c7e68d..000000000 --- a/Scripts/Engines/Reports/Persistance/PersistableObjectCollection.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System; -using System.Collections; - -namespace Server.Engines.Reports -{ - /// - /// Strongly typed collection of Server.Engines.Reports.PersistableObject. - /// - public class ObjectCollection : CollectionBase - { - /// - /// Gets or sets the value of the Server.Engines.Reports.PersistableObject at a specific position in the ObjectCollection. - /// - public PersistableObject this[int index] - { - get => (PersistableObject)List[index]; - set => List[index] = value; - } - - /// - /// Append a Server.Engines.Reports.PersistableObject entry to this collection. - /// - /// Server.Engines.Reports.PersistableObject instance. - /// The position into which the new element was inserted. - public int Add(PersistableObject value) - { - return List.Add(value); - } - - public void AddRange(PersistableObject[] col) - { - InnerList.AddRange(col); - } - - /// - /// Determines whether a specified Server.Engines.Reports.PersistableObject instance is in this collection. - /// - /// Server.Engines.Reports.PersistableObject instance to search for. - /// True if the Server.Engines.Reports.PersistableObject instance is in the collection; otherwise false. - public bool Contains(PersistableObject value) - { - return List.Contains(value); - } - - /// - /// Retrieve the index a specified Server.Engines.Reports.PersistableObject instance is in this collection. - /// - /// Server.Engines.Reports.PersistableObject instance to find. - /// - /// The zero-based index of the specified Server.Engines.Reports.PersistableObject instance. If the object is not - /// found, the return value is -1. - /// - public int IndexOf(PersistableObject value) - { - return List.IndexOf(value); - } - - /// - /// Removes a specified Server.Engines.Reports.PersistableObject instance from this collection. - /// - /// The Server.Engines.Reports.PersistableObject instance to remove. - public void Remove(PersistableObject value) - { - List.Remove(value); - } - - /// - /// Returns an enumerator that can iterate through the Server.Engines.Reports.PersistableObject instance. - /// - /// An Server.Engines.Reports.PersistableObject's enumerator. - public new ObjectCollectionEnumerator GetEnumerator() - { - return new ObjectCollectionEnumerator(this); - } - - /// - /// Insert a Server.Engines.Reports.PersistableObject instance into this collection at a specified index. - /// - /// Zero-based index. - /// The Server.Engines.Reports.PersistableObject instance to insert. - public void Insert(int index, PersistableObject value) - { - List.Insert(index, value); - } - - /// - /// Strongly typed enumerator of Server.Engines.Reports.PersistableObject. - /// - public class ObjectCollectionEnumerator : IEnumerator - { - /// - /// Collection to enumerate. - /// - private ObjectCollection _collection; - - /// - /// Current element pointed to. - /// - private PersistableObject _currentElement; - - /// - /// Current index - /// - private int _index; - - /// - /// Default constructor for enumerator. - /// - /// Instance of the collection to enumerate. - internal ObjectCollectionEnumerator(ObjectCollection collection) - { - _index = -1; - _collection = collection; - } - - /// - /// Gets the Server.Engines.Reports.PersistableObject object in the enumerated ObjectCollection currently indexed by this - /// instance. - /// - public PersistableObject Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Gets the current element in the collection. - /// - object IEnumerator.Current - { - get - { - if (_index == -1 - || _index >= _collection.Count) - throw new IndexOutOfRangeException("Enumerator not started."); - - return _currentElement; - } - } - - /// - /// Reset the cursor, so it points to the beginning of the enumerator. - /// - public void Reset() - { - _index = -1; - _currentElement = null; - } - - /// - /// Advances the enumerator to the next queue of the enumeration, if one is currently available. - /// - /// - /// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end - /// of the enumeration. - /// - public bool MoveNext() - { - if (_index - < _collection.Count - 1) - { - _index = _index + 1; - _currentElement = _collection[_index]; - return true; - } - - _index = _collection.Count; - return false; - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Persistance/PersistableType.cs b/Scripts/Engines/Reports/Persistance/PersistableType.cs deleted file mode 100644 index 4d985e5c0..000000000 --- a/Scripts/Engines/Reports/Persistance/PersistableType.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Server.Engines.Reports -{ - public delegate PersistableObject ConstructCallback(); - - public sealed class PersistableTypeRegistry - { - private static Dictionary m_Table; - - static PersistableTypeRegistry() - { - m_Table = new Dictionary(StringComparer.OrdinalIgnoreCase); - - Register(Report.ThisTypeID); - Register(BarGraph.ThisTypeID); - Register(PieChart.ThisTypeID); - Register(Snapshot.ThisTypeID); - Register(ItemValue.ThisTypeID); - Register(ChartItem.ThisTypeID); - Register(ReportItem.ThisTypeID); - Register(ReportColumn.ThisTypeID); - Register(SnapshotHistory.ThisTypeID); - - Register(PageInfo.ThisTypeID); - Register(QueueStatus.ThisTypeID); - Register(StaffHistory.ThisTypeID); - Register(ResponseInfo.ThisTypeID); - } - - public static PersistableType Find(string name) - { - m_Table.TryGetValue(name, out PersistableType value); - return value; - } - - public static void Register(PersistableType type) - { - if (type != null) - m_Table[type.Name] = type; - } - } - - public sealed class PersistableType - { - public PersistableType(string name, ConstructCallback constructor) - { - Name = name; - Constructor = constructor; - } - - public string Name{ get; } - - public ConstructCallback Constructor{ get; } - } -} diff --git a/Scripts/Engines/Reports/Persistance/PersistanceReader.cs b/Scripts/Engines/Reports/Persistance/PersistanceReader.cs deleted file mode 100644 index 877fe6ec8..000000000 --- a/Scripts/Engines/Reports/Persistance/PersistanceReader.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.IO; -using System.Xml; - -namespace Server.Engines.Reports -{ - public abstract class PersistanceReader - { - public abstract bool HasChild{ get; } - public abstract int GetInt32(string key); - public abstract bool GetBoolean(string key); - public abstract string GetString(string key); - public abstract DateTime GetDateTime(string key); - - public abstract bool BeginChildren(); - public abstract void FinishChildren(); - public abstract PersistableObject GetChild(); - - public abstract void ReadDocument(PersistableObject root); - public abstract void Close(); - } - - public class XmlPersistanceReader : PersistanceReader - { - private bool m_HasChild; - private StreamReader m_Reader; - private string m_Title; - - private bool m_WasEmptyElement; - private XmlTextReader m_Xml; - - public XmlPersistanceReader(string filePath, string title) - { - m_Reader = new StreamReader(filePath); - m_Xml = new XmlTextReader(m_Reader); - m_Xml.WhitespaceHandling = WhitespaceHandling.None; - m_Title = title; - } - - public override bool HasChild => m_HasChild; - - public override int GetInt32(string key) - { - return XmlConvert.ToInt32(m_Xml.GetAttribute(key) ?? ""); - } - - public override bool GetBoolean(string key) - { - return XmlConvert.ToBoolean(m_Xml.GetAttribute(key) ?? ""); - } - - public override string GetString(string key) - { - return m_Xml.GetAttribute(key); - } - - public override DateTime GetDateTime(string key) - { - string val = m_Xml.GetAttribute(key); - - if (val == null) - return DateTime.MinValue; - - return XmlConvert.ToDateTime(val, XmlDateTimeSerializationMode.Utc); - } - - public override bool BeginChildren() - { - m_HasChild = !m_WasEmptyElement; - - m_Xml.Read(); - - return m_HasChild; - } - - public override void FinishChildren() - { - m_Xml.Read(); - } - - public override PersistableObject GetChild() - { - PersistableType type = PersistableTypeRegistry.Find(m_Xml.Name); - PersistableObject obj = type.Constructor(); - - m_WasEmptyElement = m_Xml.IsEmptyElement; - - obj.Deserialize(this); - - m_HasChild = m_Xml.NodeType == XmlNodeType.Element; - - return obj; - } - - public override void ReadDocument(PersistableObject root) - { - Console.Write("Reports: {0}: Loading...", m_Title); - m_Xml.Read(); - m_Xml.Read(); - m_HasChild = !m_Xml.IsEmptyElement; - root.Deserialize(this); - Console.WriteLine("done"); - } - - public override void Close() - { - m_Xml.Close(); - m_Reader.Close(); - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Persistance/PersistanceWriter.cs b/Scripts/Engines/Reports/Persistance/PersistanceWriter.cs deleted file mode 100644 index 876598b0b..000000000 --- a/Scripts/Engines/Reports/Persistance/PersistanceWriter.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.IO; -using System.Xml; - -namespace Server.Engines.Reports -{ - public abstract class PersistanceWriter - { - public abstract void SetInt32(string key, int value); - public abstract void SetBoolean(string key, bool value); - public abstract void SetString(string key, string value); - public abstract void SetDateTime(string key, DateTime value); - - public abstract void BeginObject(PersistableType typeID); - public abstract void BeginChildren(); - public abstract void FinishChildren(); - public abstract void FinishObject(); - - public abstract void WriteDocument(PersistableObject root); - public abstract void Close(); - } - - public sealed class XmlPersistanceWriter : PersistanceWriter - { - private string m_RealFilePath; - private string m_TempFilePath; - private string m_Title; - - private StreamWriter m_Writer; - private XmlTextWriter m_Xml; - - public XmlPersistanceWriter(string filePath, string title) - { - m_RealFilePath = filePath; - m_TempFilePath = Path.ChangeExtension(filePath, ".tmp"); - - m_Writer = new StreamWriter(m_TempFilePath); - m_Xml = new XmlTextWriter(m_Writer); - - m_Title = title; - } - - public override void SetInt32(string key, int value) - { - m_Xml.WriteAttributeString(key, XmlConvert.ToString(value)); - } - - public override void SetBoolean(string key, bool value) - { - m_Xml.WriteAttributeString(key, XmlConvert.ToString(value)); - } - - public override void SetString(string key, string value) - { - if (value != null) - m_Xml.WriteAttributeString(key, value); - } - - public override void SetDateTime(string key, DateTime value) - { - if (value != DateTime.MinValue) - m_Xml.WriteAttributeString(key, XmlConvert.ToString(value, XmlDateTimeSerializationMode.Utc)); - } - - public override void BeginObject(PersistableType typeID) - { - m_Xml.WriteStartElement(typeID.Name); - } - - public override void BeginChildren() - { - } - - public override void FinishChildren() - { - } - - public override void FinishObject() - { - m_Xml.WriteEndElement(); - } - - public override void WriteDocument(PersistableObject root) - { - Console.WriteLine("Reports: {0}: Save started", m_Title); - - m_Xml.Formatting = Formatting.Indented; - m_Xml.IndentChar = '\t'; - m_Xml.Indentation = 1; - - m_Xml.WriteStartDocument(true); - - root.Serialize(this); - - Console.WriteLine("Reports: {0}: Save complete", m_Title); - } - - public override void Close() - { - m_Xml.Close(); - m_Writer.Close(); - - try - { - string renamed; - - if (File.Exists(m_RealFilePath)) - { - renamed = Path.ChangeExtension(m_RealFilePath, ".rem"); - File.Move(m_RealFilePath, renamed); - File.Move(m_TempFilePath, m_RealFilePath); - File.Delete(renamed); - } - else - { - File.Move(m_TempFilePath, m_RealFilePath); - } - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/BarGraphRenderer.cs b/Scripts/Engines/Reports/Rendering/BarGraphRenderer.cs deleted file mode 100644 index ad5e8c2da..000000000 --- a/Scripts/Engines/Reports/Rendering/BarGraphRenderer.cs +++ /dev/null @@ -1,934 +0,0 @@ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Windows.Forms; - -namespace Server.Engines.Reports -{ - // Modified from MS sample - - //********************************************************************* - // - // BarGraph Class - // - // This class uses GDI+ to render Bar Chart. - // - //********************************************************************* - - public class BarRegion - { - public string m_Name; - public int m_RangeFrom, m_RangeTo; - - public BarRegion(int rangeFrom, int rangeTo, string name) - { - m_RangeFrom = rangeFrom; - m_RangeTo = rangeTo; - m_Name = name; - } - } - - public class BarGraphRenderer : ChartRenderer - { - private const float _graphLegendSpacer = 15F; - private const float _labelFontSize = 7f; - private const int _legendFontSize = 9; - private const float _legendRectangleSize = 10F; - private const float _spacer = 5F; - - // Overall related members - private Color _backColor; - - // Graph related members - private float _barWidth; - private float _bottomBuffer; // Space from bottom to x axis - private Color _fontColor; - private float _graphHeight; - private float _graphWidth; - - //********************************************************************* - // - // This method draws all the bars for the graph. - // - //********************************************************************* - - public int _interval; - - // Legend related members - private float _legendWidth; - private string _longestLabel = string.Empty; // Used to calculate legend width - private string _longestTickValue = string.Empty; // Used to calculate max value width - private float _maxLabelWidth; - private float _maxTickValueWidth; // Used to calculate left offset of bar graph - private float _maxValue; // = final tick value * tick count - - public BarRegion[] _regions; - private float _scaleFactor; // = _maxValue / _graphHeight - private float _spaceBtwBars; // For now same as _barWidth - private float _topBuffer; // Space from top to the top of y axis - private float _totalHeight; - private float _totalWidth; - private float _xOrigin; // x position where graph starts drawing - - private string _xTitle, _yTitle; - private float _yOrigin; // y position where graph starts drawing - private float _yTickValue; // Value for each tick = _maxValue/_yTickCount - - public BarGraphRenderer() - { - AssignDefaultSettings(); - } - - public BarGraphRenderer(Color bgColor) - { - AssignDefaultSettings(); - BackgroundColor = bgColor; - } - - public string FontFamily{ get; set; } - - public BarGraphRenderMode RenderMode{ get; set; } - - public Color BackgroundColor - { - set => _backColor = value; - } - - public int BottomBuffer - { - set => _bottomBuffer = Convert.ToSingle(value); - } - - public Color FontColor - { - set => _fontColor = value; - } - - public int Height - { - get => Convert.ToInt32(_totalHeight); - set => _totalHeight = Convert.ToSingle(value); - } - - public int Width - { - get => Convert.ToInt32(_totalWidth); - set => _totalWidth = Convert.ToSingle(value); - } - - public bool ShowLegend{ get; set; } - - public bool ShowData{ get; set; } - - public int TopBuffer - { - set => _topBuffer = Convert.ToSingle(value); - } - - public string VerticalLabel{ get; set; } - - public int VerticalTickCount{ get; set; } - - public void SetTitles(string xTitle, string yTitle) - { - _xTitle = xTitle; - _yTitle = yTitle; - } - - //********************************************************************* - // - // This method collects all data points and calculate all the necessary dimensions - // to draw the bar graph. It is the method called before invoking the Draw() method. - // labels is the x values. - // values is the y values. - // - //********************************************************************* - - public void CollectDataPoints(string[] labels, string[] values) - { - if (labels.Length == values.Length) - { - for (int i = 0; i < labels.Length; i++) - { - float temp = Convert.ToSingle(values[i]); - string shortLbl = MakeShortLabel(labels[i]); - - // For now put 0.0 for start position and sweep size - DataPoints.Add(new DataItem(shortLbl, labels[i], temp, 0.0f, 0.0f, GetColor(i))); - - // Find max value from data; this is only temporary _maxValue - if (_maxValue < temp) _maxValue = temp; - - // Find the longest description - if (ShowLegend) - { - string currentLbl = labels[i] + " (" + shortLbl + ")"; - float currentWidth = CalculateImgFontWidth(currentLbl, _legendFontSize, FontFamily); - if (_maxLabelWidth < currentWidth) - { - _longestLabel = currentLbl; - _maxLabelWidth = currentWidth; - } - } - } - - CalculateTickAndMax(); - CalculateGraphDimension(); - CalculateBarWidth(DataPoints.Count, _graphWidth); - CalculateSweepValues(); - } - else - { - throw new Exception("X data count is different from Y data count"); - } - } - - //********************************************************************* - // - // Same as above; called when user doesn't care about the x values - // - //********************************************************************* - - public void CollectDataPoints(string[] values) - { - string[] labels = values; - CollectDataPoints(labels, values); - } - - public void DrawRegions(Graphics gfx) - { - if (_regions == null) - return; - - using (StringFormat textFormat = new StringFormat()) - { - textFormat.Alignment = StringAlignment.Center; - textFormat.LineAlignment = StringAlignment.Center; - - using (Font font = new Font(FontFamily, _labelFontSize)) - { - using (Brush textBrush = new SolidBrush(_fontColor)) - { - using (Pen solidPen = new Pen(_fontColor)) - { - using (Pen lightPen = new Pen(Color.FromArgb(128, _fontColor))) - { - float labelWidth = _barWidth + _spaceBtwBars; - - for (int i = 0; i < _regions.Length; ++i) - { - BarRegion reg = _regions[i]; - - RectangleF rc = new RectangleF(_xOrigin + reg.m_RangeFrom * labelWidth, _yOrigin, - (reg.m_RangeTo - reg.m_RangeFrom + 1) * labelWidth, _graphHeight); - - if (rc.X + rc.Width > _xOrigin + _graphWidth) - rc.Width = _xOrigin + _graphWidth - rc.X; - - using (SolidBrush brsh = new SolidBrush(Color.FromArgb(48, GetColor(i)))) - { - gfx.FillRectangle(brsh, rc); - } - - rc.Offset((rc.Width - 200.0f) * 0.5f, -16.0f); - rc.Width = 200.0f; - rc.Height = 20.0f; - - gfx.DrawString(reg.m_Name, font, textBrush, rc, textFormat); - } - } - } - } - } - } - } - - //********************************************************************* - // - // This method returns a bar graph bitmap to the calling function. It is called after - // all dimensions and data points are calculated. - // - //********************************************************************* - - public override Bitmap Draw() - { - int height = Convert.ToInt32(_totalHeight); - int width = Convert.ToInt32(_totalWidth); - - Bitmap bmp = new Bitmap(width, height); - - using (Graphics graph = Graphics.FromImage(bmp)) - { - graph.CompositingQuality = CompositingQuality.HighQuality; - graph.SmoothingMode = SmoothingMode.AntiAlias; - - using (SolidBrush brsh = new SolidBrush(_backColor)) - { - graph.FillRectangle(brsh, -1, -1, bmp.Width + 1, bmp.Height + 1); - } - - DrawRegions(graph); - DrawVerticalLabelArea(graph); - DrawXLabelBack(graph); - DrawBars(graph); - DrawXLabelArea(graph); - - if (ShowLegend) - DrawLegend(graph); - } - - return bmp; - } - - private void DrawBars(Graphics graph) - { - SolidBrush brsFont = null; - Font valFont = null; - StringFormat sfFormat = null; - - try - { - brsFont = new SolidBrush(_fontColor); - valFont = new Font(FontFamily, _labelFontSize); - sfFormat = new StringFormat(); - sfFormat.Alignment = StringAlignment.Center; - int i = 0; - - PointF[] linePoints = null; - - if (RenderMode == BarGraphRenderMode.Lines) - linePoints = new PointF[DataPoints.Count]; - - int pointIndex = 0; - - // Draw bars and the value above each bar - using (Pen pen = new Pen(_fontColor, 0.15f)) - { - using (SolidBrush whiteBrsh = new SolidBrush(Color.FromArgb(128, Color.White))) - { - foreach (DataItem item in DataPoints) - using (SolidBrush barBrush = new SolidBrush(item.ItemColor)) - { - float itemY = _yOrigin + _graphHeight - item.SweepSize; - - if (RenderMode == BarGraphRenderMode.Lines) - { - linePoints[pointIndex++] = new PointF(_xOrigin + item.StartPos + _barWidth / 2, itemY); - } - else if (RenderMode == BarGraphRenderMode.Bars) - { - float ox = _xOrigin + item.StartPos; - float oy = itemY; - float ow = _barWidth; - float oh = item.SweepSize; - float of = 9.5f; - - PointF[] pts = - { - new PointF(ox, oy), - new PointF(ox + ow, oy), - new PointF(ox + of, oy + of), - new PointF(ox + of + ow, oy + of), - new PointF(ox, oy + oh), - new PointF(ox + of, oy + of + oh), - new PointF(ox + of + ow, oy + of + oh) - }; - - graph.FillPolygon(barBrush, new[] { pts[2], pts[3], pts[6], pts[5] }); - - using (SolidBrush ltBrsh = new SolidBrush(ControlPaint.Light(item.ItemColor, 0.1f))) - { - graph.FillPolygon(ltBrsh, new[] { pts[0], pts[2], pts[5], pts[4] }); - } - - using (SolidBrush drkBrush = new SolidBrush(ControlPaint.Dark(item.ItemColor, 0.05f))) - { - graph.FillPolygon(drkBrush, new[] { pts[0], pts[1], pts[3], pts[2] }); - } - - graph.DrawLine(pen, pts[0], pts[1]); - graph.DrawLine(pen, pts[0], pts[2]); - graph.DrawLine(pen, pts[1], pts[3]); - graph.DrawLine(pen, pts[2], pts[3]); - graph.DrawLine(pen, pts[2], pts[5]); - graph.DrawLine(pen, pts[0], pts[4]); - graph.DrawLine(pen, pts[4], pts[5]); - graph.DrawLine(pen, pts[5], pts[6]); - graph.DrawLine(pen, pts[3], pts[6]); - - // Draw data value - if (ShowData && i % _interval == 0) - { - float sectionWidth = _barWidth + _spaceBtwBars; - float startX = - _xOrigin + i * sectionWidth + - sectionWidth / 2; // This draws the value on center of the bar - float startY = - itemY - 2f - valFont.Height; // Positioned on top of each bar by 2 pixels - RectangleF recVal = new RectangleF(startX - sectionWidth * _interval / 2, startY, - sectionWidth * _interval, valFont.Height); - SizeF sz = graph.MeasureString(item.Value.ToString("#,###.##"), valFont, recVal.Size, - sfFormat); - //using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 180, 255, 255, 255 ) ) ) - // graph.FillRectangle( brsh, new RectangleF(recVal.X+((recVal.Width-sz.Width)/2),recVal.Y+((recVal.Height-sz.Height)/2),sz.Width+4,sz.Height) ); - - //graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, sfFormat); - - for (int box = -1; box <= 1; ++box) - for (int boy = -1; boy <= 1; ++boy) - { - if (box == 0 && boy == 0) - continue; - - RectangleF rco = new RectangleF(recVal.X + box, recVal.Y + boy, recVal.Width, - recVal.Height); - graph.DrawString(item.Value.ToString("#,###.##"), valFont, whiteBrsh, rco, - sfFormat); - } - - graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, - sfFormat); - } - } - - i++; - } - - if (RenderMode == BarGraphRenderMode.Lines) - { - if (linePoints.Length >= 2) - using (Pen linePen = new Pen(Color.FromArgb(220, Color.Red), 2.5f)) - { - graph.DrawCurve(linePen, linePoints, 0.5f); - } - - using (Pen linePen = new Pen(Color.FromArgb(40, _fontColor), 0.8f)) - { - for (int j = 0; j < linePoints.Length; ++j) - { - graph.DrawLine(linePen, linePoints[j], - new PointF(linePoints[j].X, _yOrigin + _graphHeight)); - - DataItem item = DataPoints[j]; - float itemY = _yOrigin + _graphHeight - item.SweepSize; - - // Draw data value - if (ShowData && j % _interval == 0) - { - graph.FillEllipse(brsFont, - new RectangleF(linePoints[j].X - 2.0f, linePoints[j].Y - 2.0f, 4.0f, 4.0f)); - - float sectionWidth = _barWidth + _spaceBtwBars; - float startX = - _xOrigin + j * sectionWidth + - sectionWidth / 2; // This draws the value on center of the bar - float startY = - itemY - 2f - valFont.Height; // Positioned on top of each bar by 2 pixels - RectangleF recVal = new RectangleF(startX - sectionWidth * _interval / 2, startY, - sectionWidth * _interval, valFont.Height); - SizeF sz = graph.MeasureString(item.Value.ToString("#,###.##"), valFont, recVal.Size, - sfFormat); - //using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 48, 255, 255, 255 ) ) ) - // graph.FillRectangle( brsh, new RectangleF(recVal.X+((recVal.Width-sz.Width)/2),recVal.Y+((recVal.Height-sz.Height)/2),sz.Width+4,sz.Height) ); - - for (int box = -1; box <= 1; ++box) - for (int boy = -1; boy <= 1; ++boy) - { - if (box == 0 && boy == 0) - continue; - - RectangleF rco = new RectangleF(recVal.X + box, recVal.Y + boy, recVal.Width, - recVal.Height); - graph.DrawString(item.Value.ToString("#,###.##"), valFont, whiteBrsh, rco, - sfFormat); - } - - graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, - sfFormat); - } - } - } - } - } - } - } - finally - { - brsFont?.Dispose(); - valFont?.Dispose(); - sfFormat?.Dispose(); - } - } - - //********************************************************************* - // - // This method draws the y label, tick marks, tick values, and the y axis. - // - //********************************************************************* - - private void DrawVerticalLabelArea(Graphics graph) - { - Font lblFont = null; - SolidBrush brs = null; - StringFormat lblFormat = null; - Pen pen = null; - StringFormat sfVLabel = null; - - float fo = _yTitle == null ? 0.0f : 20.0f; - - try - { - brs = new SolidBrush(_fontColor); - lblFormat = new StringFormat(); - pen = new Pen(_fontColor); - - if (_yTitle != null) - { - sfVLabel = new StringFormat(); - sfVLabel.Alignment = StringAlignment.Center; - sfVLabel.LineAlignment = StringAlignment.Center; - sfVLabel.FormatFlags = StringFormatFlags.DirectionVertical; - - lblFont = new Font(FontFamily, _labelFontSize + 4.0f); - graph.DrawString(_yTitle, lblFont, brs, new RectangleF(0.0f, _yOrigin, 20.0f, _graphHeight), sfVLabel); - lblFont.Dispose(); - } - - sfVLabel = new StringFormat(); - lblFormat.Alignment = StringAlignment.Far; - lblFormat.FormatFlags |= StringFormatFlags.NoClip; - - // Draw vertical label at the top of y-axis and place it in the middle top of y-axis - lblFont = new Font(FontFamily, _labelFontSize + 2.0f, FontStyle.Bold); - RectangleF recVLabel = - new RectangleF(0, _yOrigin - 2 * _spacer - lblFont.Height, _xOrigin * 2, lblFont.Height); - sfVLabel.Alignment = StringAlignment.Center; - sfVLabel.FormatFlags |= StringFormatFlags.NoClip; - //graph.DrawRectangle(Pens.Black,Rectangle.Truncate(recVLabel)); - graph.DrawString(VerticalLabel, lblFont, brs, recVLabel, sfVLabel); - lblFont.Dispose(); - - lblFont = new Font(FontFamily, _labelFontSize); - // Draw all tick values and tick marks - using (Pen smallPen = new Pen(Color.FromArgb(96, _fontColor), 0.8f)) - { - for (int i = 0; i < VerticalTickCount; i++) - { - float currentY = _topBuffer + i * _yTickValue / _scaleFactor; // Position for tick mark - float labelY = currentY - lblFont.Height / 2.0f; // Place label in the middle of tick - RectangleF lblRec = new RectangleF(_spacer + fo - 6, labelY, _maxTickValueWidth, lblFont.Height); - - float currentTick = _maxValue - i * _yTickValue; // Calculate tick value from top to bottom - graph.DrawString(currentTick.ToString("#,###.##"), lblFont, brs, lblRec, - lblFormat); // Draw tick value - graph.DrawLine(pen, _xOrigin, currentY, _xOrigin - 4.0f, currentY); // Draw tick mark - - graph.DrawLine(smallPen, _xOrigin, currentY, _xOrigin + _graphWidth, currentY); - } - } - - // Draw y axis - graph.DrawLine(pen, _xOrigin, _yOrigin, _xOrigin, _yOrigin + _graphHeight); - } - finally - { - lblFont?.Dispose(); - brs?.Dispose(); - lblFormat?.Dispose(); - pen?.Dispose(); - sfVLabel?.Dispose(); - } - } - - //********************************************************************* - // - // This method draws x axis and all x labels - // - //********************************************************************* - - private void DrawXLabelBack(Graphics graph) - { - Font lblFont = null; - SolidBrush brs = null; - StringFormat lblFormat = null; - Pen pen = null; - - try - { - lblFont = new Font(FontFamily, _labelFontSize); - brs = new SolidBrush(_fontColor); - lblFormat = new StringFormat(); - pen = new Pen(_fontColor); - - lblFormat.Alignment = StringAlignment.Center; - - // Draw x axis - graph.DrawLine(pen, _xOrigin, _yOrigin + _graphHeight, _xOrigin + _graphWidth, _yOrigin + _graphHeight); - } - finally - { - lblFont?.Dispose(); - brs?.Dispose(); - lblFormat?.Dispose(); - pen?.Dispose(); - } - } - - private void DrawXLabelArea(Graphics graph) - { - Font lblFont = null; - SolidBrush brs = null; - StringFormat lblFormat = null; - Pen pen = null; - - try - { - brs = new SolidBrush(_fontColor); - pen = new Pen(_fontColor); - - if (_xTitle != null) - { - lblFormat = new StringFormat(); - lblFormat.Alignment = StringAlignment.Center; - lblFormat.LineAlignment = StringAlignment.Center; - // sfVLabel.FormatFlags=StringFormatFlags.DirectionVertical; - - lblFont = new Font(FontFamily, _labelFontSize + 2.0f, FontStyle.Bold); - graph.DrawString(_xTitle, lblFont, brs, - new RectangleF(_xOrigin, - _yOrigin + _graphHeight + 14.0f + (RenderMode == BarGraphRenderMode.Bars ? 10.0f : 0.0f) + - (DataPoints.Count / _interval > 24 ? 16.0f : 0.0f), _graphWidth, 20.0f), lblFormat); - } - - lblFont = new Font(FontFamily, _labelFontSize); - lblFormat = new StringFormat(); - lblFormat.Alignment = StringAlignment.Center; - lblFormat.FormatFlags |= StringFormatFlags.NoClip; - lblFormat.Trimming = StringTrimming.None; - //lblFormat.FormatFlags |= StringFormatFlags.NoWrap; - - float of = 0.0f; - - if (RenderMode == BarGraphRenderMode.Bars) - { - of = 10.0f; - - // Draw x axis - graph.DrawLine(pen, _xOrigin + of, _yOrigin + _graphHeight + of, _xOrigin + _graphWidth + of, - _yOrigin + _graphHeight + of); - - graph.DrawLine(pen, _xOrigin, _yOrigin + _graphHeight, _xOrigin + of, _yOrigin + _graphHeight + of); - graph.DrawLine(pen, _xOrigin + _graphWidth, _yOrigin + _graphHeight, _xOrigin + of + _graphWidth, - _yOrigin + _graphHeight + of); - } - - float currentX; - float currentY = _yOrigin + _graphHeight + 2.0f; // All x labels are drawn 2 pixels below x-axis - float labelWidth = _barWidth + _spaceBtwBars; // Fits exactly below the bar - int i = 0; - - // Draw x labels - foreach (DataItem item in DataPoints) - { - if (i % _interval == 0) - { - currentX = _xOrigin + i * labelWidth + of + labelWidth / 2; - RectangleF recLbl = new RectangleF(currentX - labelWidth * _interval / 2, currentY + of, - labelWidth * _interval, lblFont.Height * 2); - string lblString = ShowLegend ? item.Label : item.Description; // Decide what to show: short or long - - graph.DrawString(lblString, lblFont, brs, recLbl, lblFormat); - } - - i++; - } - } - finally - { - lblFont?.Dispose(); - brs?.Dispose(); - lblFormat?.Dispose(); - pen?.Dispose(); - } - } - - //********************************************************************* - // - // This method determines where to place the legend box. - // It draws the legend border, legend description, and legend color code. - // - //********************************************************************* - - private void DrawLegend(Graphics graph) - { - Font lblFont = null; - SolidBrush brs = null; - StringFormat lblFormat = null; - Pen pen = null; - - try - { - lblFont = new Font(FontFamily, _legendFontSize); - brs = new SolidBrush(_fontColor); - lblFormat = new StringFormat(); - pen = new Pen(_fontColor); - lblFormat.Alignment = StringAlignment.Near; - - // Calculate Legend drawing start point - float startX = _xOrigin + _graphWidth + _graphLegendSpacer; - float startY = _yOrigin; - - float xColorCode = startX + _spacer; - float xLegendText = xColorCode + _legendRectangleSize + _spacer; - float legendHeight = 0.0f; - for (int i = 0; i < DataPoints.Count; i++) - { - DataItem point = DataPoints[i]; - string text = point.Description + " (" + point.Label + ")"; - float currentY = startY + _spacer + i * (lblFont.Height + _spacer); - legendHeight += lblFont.Height + _spacer; - - // Draw legend description - graph.DrawString(text, lblFont, brs, xLegendText, currentY, lblFormat); - - // Draw color code - using (SolidBrush brsh = new SolidBrush(DataPoints[i].ItemColor)) - { - graph.FillRectangle(brsh, xColorCode, currentY + 3f, _legendRectangleSize, _legendRectangleSize); - } - } - - // Draw legend border - graph.DrawRectangle(pen, startX, startY, _legendWidth, legendHeight + _spacer); - } - finally - { - lblFont?.Dispose(); - brs?.Dispose(); - lblFormat?.Dispose(); - pen?.Dispose(); - } - } - - //********************************************************************* - // - // This method calculates all measurement aspects of the bar graph from the given data points - // - //********************************************************************* - - private void CalculateGraphDimension() - { - FindLongestTickValue(); - - // Need to add another character for spacing; this is not used for drawing, just for calculation - _longestTickValue += "0"; - //_maxTickValueWidth = CalculateImgFontWidth(_longestTickValue, _labelFontSize, FontFamily); - _maxTickValueWidth = 0.0f; - - - float currentTick; - string tickString; - for (int i = 0; i < VerticalTickCount; i++) - { - currentTick = _maxValue - i * _yTickValue; - tickString = currentTick.ToString("#,###.##"); - - float measured = CalculateImgFontWidth(tickString, _labelFontSize, FontFamily); - - if (measured > _maxTickValueWidth) - _maxTickValueWidth = measured; - } - - float leftOffset = _spacer + _maxTickValueWidth + (_yTitle == null ? 0.0f : 20.0f); - float rtOffset = 0.0f; - - if (ShowLegend) - { - _legendWidth = _spacer + _legendRectangleSize + _spacer + _maxLabelWidth + _spacer; - rtOffset = _graphLegendSpacer + _legendWidth + _spacer; - } - else - { - rtOffset = _spacer; // Make graph in the middle - } - - if (RenderMode == BarGraphRenderMode.Bars) - rtOffset += 10.0f; - - rtOffset += 10.0f; - - _graphHeight = - _totalHeight - _topBuffer - _bottomBuffer - - (_xTitle == null ? 0.0f : 20.0f); // Buffer spaces are used to print labels - _graphWidth = _totalWidth - leftOffset - rtOffset; - _xOrigin = leftOffset; - _yOrigin = _topBuffer; - - // Once the correct _maxValue is determined, then calculate _scaleFactor - _scaleFactor = _maxValue / _graphHeight; - } - - //********************************************************************* - // - // This method determines the longest tick value from the given data points. - // The result is needed to calculate the correct graph dimension. - // - //********************************************************************* - - private void FindLongestTickValue() - { - float currentTick; - string tickString; - for (int i = 0; i < VerticalTickCount; i++) - { - currentTick = _maxValue - i * _yTickValue; - tickString = currentTick.ToString("#,###.##"); - if (_longestTickValue.Length < tickString.Length) - _longestTickValue = tickString; - } - } - - //********************************************************************* - // - // This method calculates the image width in pixel for a given text - // - //********************************************************************* - - private float CalculateImgFontWidth(string text, float size, string family) - { - Bitmap bmp = null; - Graphics graph = null; - Font font = null; - - try - { - font = new Font(family, size); - - // Calculate the size of the string. - bmp = new Bitmap(1, 1, PixelFormat.Format32bppArgb); - graph = Graphics.FromImage(bmp); - SizeF oSize = graph.MeasureString(text, font); - oSize.Width = 4 + (float)Math.Ceiling(oSize.Width); - - return oSize.Width; - } - finally - { - graph?.Dispose(); - bmp?.Dispose(); - font?.Dispose(); - } - } - - //********************************************************************* - // - // This method creates abbreviation from long description; used for making legend - // - //********************************************************************* - - private string MakeShortLabel(string text) - { - string label = text; - if (text.Length > 2) - { - int midPostition = Convert.ToInt32(Math.Floor(text.Length / 2.0)); - label = text.Substring(0, 1) + text.Substring(midPostition, 1) + text.Substring(text.Length - 1, 1); - } - - return label; - } - - //********************************************************************* - // - // This method calculates the max value and each tick mark value for the bar graph. - // - //********************************************************************* - - private void CalculateTickAndMax() - { - float tempMax = 0.0f; - - // Give graph some head room first about 10% of current max - _maxValue *= 1.1f; - - if (_maxValue != 0.0f) - { - // Find a rounded value nearest to the current max value - // Calculate this max first to give enough space to draw value on each bar - double exp = Convert.ToDouble(Math.Floor(Math.Log10(_maxValue))); - tempMax = Convert.ToSingle(Math.Ceiling(_maxValue / Math.Pow(10, exp)) * Math.Pow(10, exp)); - } - else - { - tempMax = 1.0f; - } - - // Once max value is calculated, tick value can be determined; tick value should be a whole number - _yTickValue = tempMax / VerticalTickCount; - double expTick = Convert.ToDouble(Math.Floor(Math.Log10(_yTickValue))); - _yTickValue = Convert.ToSingle(Math.Ceiling(_yTickValue / Math.Pow(10, expTick)) * Math.Pow(10, expTick)); - - // Re-calculate the max value with the new tick value - _maxValue = _yTickValue * VerticalTickCount; - } - - //********************************************************************* - // - // This method calculates the height for each bar in the graph - // - //********************************************************************* - - private void CalculateSweepValues() - { - // Called when all values and scale factor are known - // All values calculated here are relative from (_xOrigin, _yOrigin) - int i = 0; - foreach (DataItem item in DataPoints) - { - // This implementation does not support negative value - if (item.Value >= 0) item.SweepSize = item.Value / _scaleFactor; - - // (_spaceBtwBars/2) makes half white space for the first bar - item.StartPos = _spaceBtwBars / 2 + i * (_barWidth + _spaceBtwBars); - i++; - } - } - - //********************************************************************* - // - // This method calculates the width for each bar in the graph - // - //********************************************************************* - - private void CalculateBarWidth(int dataCount, float barGraphWidth) - { - // White space between each bar is the same as bar width itself - _barWidth = barGraphWidth / (dataCount * 2); // Each bar has 1 white space - //_barWidth =/* (float)Math.Floor(*/_barWidth/*)*/; - _spaceBtwBars = _barWidth; - } - - //********************************************************************* - // - // This method assigns default value to the bar graph properties and is only - // called from BarGraph constructors - // - //********************************************************************* - - private void AssignDefaultSettings() - { - // default values - _totalWidth = 680f; - _totalHeight = 450f; - FontFamily = "Verdana"; - _backColor = Color.White; - _fontColor = Color.Black; - _topBuffer = 30f; - _bottomBuffer = 30f; - VerticalTickCount = 2; - ShowLegend = false; - ShowData = false; - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/ChartRenderer.cs b/Scripts/Engines/Reports/Rendering/ChartRenderer.cs deleted file mode 100644 index 5ae6b20a7..000000000 --- a/Scripts/Engines/Reports/Rendering/ChartRenderer.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Drawing; - -namespace Server.Engines.Reports -{ - //********************************************************************* - // - // Chart Class - // - // Base class implementation for BarChart and PieChart - // - //********************************************************************* - - public abstract class ChartRenderer - { - private const int _colorLimit = 9; - - private Color[] _color = - { - Color.Firebrick, - Color.SkyBlue, - Color.MediumSeaGreen, - Color.MediumOrchid, - Color.Chocolate, - Color.SlateBlue, - Color.LightPink, - Color.LightGreen, - Color.Khaki - }; - - public ChartItemsCollection DataPoints{ get; set; } = new ChartItemsCollection(); - - // Represent collection of all data points for the chart - - // The implementation of this method is provided by derived classes - public abstract Bitmap Draw(); - - public void SetColor(int index, Color NewColor) - { - if (index < _colorLimit) - _color[index] = NewColor; - else - throw new Exception("Color Limit is " + _colorLimit); - } - - public Color GetColor(int index) - { - //return _color[index%_colorLimit]; - - if (index < _colorLimit) return _color[index]; - - return _color[(index + 2) % _colorLimit]; - //throw new Exception("Color Limit is " + _colorLimit); - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/DataItem.cs b/Scripts/Engines/Reports/Rendering/DataItem.cs deleted file mode 100644 index f3fa982b1..000000000 --- a/Scripts/Engines/Reports/Rendering/DataItem.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections; -using System.Drawing; - -namespace Server.Engines.Reports -{ - public class DataItem - { - private DataItem() - { - } - - public DataItem(string label, string desc, float data, float start, float sweep, Color clr) - { - Label = label; - Description = desc; - Value = data; - StartPos = start; - SweepSize = sweep; - ItemColor = clr; - } - - public string Label{ get; set; } - - public string Description{ get; set; } - - public float Value{ get; set; } - - public Color ItemColor{ get; set; } - - public float StartPos{ get; set; } - - public float SweepSize{ get; set; } - } - - public class ChartItemsCollection : CollectionBase - { - public DataItem this[int index] - { - get => (DataItem)List[index]; - set => List[index] = value; - } - - public int Add(DataItem value) - { - return List.Add(value); - } - - public int IndexOf(DataItem value) - { - return List.IndexOf(value); - } - - public bool Contains(DataItem value) - { - return List.Contains(value); - } - - public void Remove(DataItem value) - { - List.Remove(value); - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/HtmlRenderer.cs b/Scripts/Engines/Reports/Rendering/HtmlRenderer.cs deleted file mode 100644 index c982c058f..000000000 --- a/Scripts/Engines/Reports/Rendering/HtmlRenderer.cs +++ /dev/null @@ -1,546 +0,0 @@ -using System; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using System.Web.UI; -using HtmlTag = System.Web.UI.HtmlTextWriterTag; -using HtmlAttr = System.Web.UI.HtmlTextWriterAttribute; - -namespace Server.Engines.Reports -{ - public class HtmlRenderer - { - private const string ShardTitle = "Shard"; - - private static readonly string FtpHost = null; - - private static readonly string FtpUsername = null; - private static readonly string FtpPassword = null; - - private static readonly string FtpStatsDirectory = null; - private static readonly string FtpStaffDirectory = null; - private ObjectCollection m_Objects; - private string m_OutputDirectory; - - private DateTime m_TimeStamp; - private string m_Title; - private string m_Type; - - private HtmlRenderer(string outputDirectory) - { - m_Type = outputDirectory; - m_Title = m_Type == "staff" ? "Staff" : "Stats"; - m_OutputDirectory = Path.Combine(Core.BaseDirectory, "output"); - - if (!Directory.Exists(m_OutputDirectory)) - Directory.CreateDirectory(m_OutputDirectory); - - m_OutputDirectory = Path.Combine(m_OutputDirectory, outputDirectory); - - if (!Directory.Exists(m_OutputDirectory)) - Directory.CreateDirectory(m_OutputDirectory); - } - - public HtmlRenderer(string outputDirectory, Snapshot ss, SnapshotHistory history) : this(outputDirectory) - { - m_TimeStamp = ss.TimeStamp; - - m_Objects = new ObjectCollection(); - - for (int i = 0; i < ss.Children.Count; ++i) - m_Objects.Add(ss.Children[i]); - - m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Clients", 1, 100, 6)); - m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Items", 24, 9, 1)); - m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Players", 24, 9, 1)); - m_Objects.Add(BarGraph.OverTime(history, "General Stats", "NPCs", 24, 9, 1)); - m_Objects.Add(BarGraph.DailyAverage(history, "General Stats", "Clients")); - m_Objects.Add(BarGraph.Growth(history, "General Stats", "Clients")); - } - - public HtmlRenderer(string outputDirectory, StaffHistory history) : this(outputDirectory) - { - m_TimeStamp = DateTime.UtcNow; - - m_Objects = new ObjectCollection(); - - history.Render(m_Objects); - } - - public void Render() - { - Console.WriteLine("Reports: {0}: Render started", m_Title); - - RenderFull(); - - for (int i = 0; i < m_Objects.Count; ++i) - RenderSingle(m_Objects[i]); - - Console.WriteLine("Reports: {0}: Render complete", m_Title); - } - - public void Upload() - { - if (FtpHost == null) - return; - - Console.WriteLine("Reports: {0}: Upload started", m_Title); - - string filePath = Path.Combine(m_OutputDirectory, "upload.ftp"); - - using (StreamWriter op = new StreamWriter(filePath)) - { - op.WriteLine("open \"{0}\"", FtpHost); - op.WriteLine(FtpUsername); - op.WriteLine(FtpPassword); - op.WriteLine("cd \"{0}\"", m_Type == "staff" ? FtpStaffDirectory : FtpStatsDirectory); - op.WriteLine("mput \"{0}\"", Path.Combine(m_OutputDirectory, "*.html")); - op.WriteLine("mput \"{0}\"", Path.Combine(m_OutputDirectory, "*.css")); - op.WriteLine("binary"); - op.WriteLine("mput \"{0}\"", Path.Combine(m_OutputDirectory, "*.png")); - op.WriteLine("disconnect"); - op.Write("quit"); - } - - ProcessStartInfo psi = new ProcessStartInfo(); - - psi.FileName = "ftp"; - psi.Arguments = $"-i -s:\"{filePath}\""; - - psi.CreateNoWindow = true; - psi.WindowStyle = ProcessWindowStyle.Hidden; - //psi.UseShellExecute = true; - - try - { - Process p = Process.Start(psi); - - p?.WaitForExit(); - } - catch - { - // ignored - } - - Console.WriteLine("Reports: {0}: Upload complete", m_Title); - - try - { - File.Delete(filePath); - } - catch - { - // ignored - } - } - - public void RenderFull() - { - string filePath = Path.Combine(m_OutputDirectory, "reports.html"); - - using (StreamWriter op = new StreamWriter(filePath)) - { - using (HtmlTextWriter html = new HtmlTextWriter(op, "\t")) - { - RenderFull(html); - } - } - - string cssPath = Path.Combine(m_OutputDirectory, "styles.css"); - - if (File.Exists(cssPath)) - return; - - using (StreamWriter css = new StreamWriter(cssPath)) - { - css.WriteLine("body { background-color: #FFFFFF; font-family: verdana, arial; font-size: 11px; }"); - css.WriteLine("a { color: #28435E; }"); - css.WriteLine("a:hover { color: #4878A9; }"); - css.WriteLine("td.header { background-color: #9696AA; font-weight: bold; font-size: 12px; }"); - css.WriteLine("td.lentry { background-color: #D7D7EB; width: 10%; }"); - css.WriteLine("td.rentry { background-color: #FFFFFF; width: 90%; }"); - css.WriteLine("td.entry { background-color: #FFFFFF; }"); - css.WriteLine("td { font-size: 11px; }"); - css.Write(".tbl-border { background-color: #46465A; }"); - } - } - - public void RenderFull(HtmlTextWriter html) - { - html.RenderBeginTag(HtmlTag.Html); - - html.RenderBeginTag(HtmlTag.Head); - - html.RenderBeginTag(HtmlTag.Title); - html.Write("{0} Statistics", ShardTitle); - html.RenderEndTag(); - - html.AddAttribute("rel", "stylesheet"); - html.AddAttribute(HtmlAttr.Type, "text/css"); - html.AddAttribute(HtmlAttr.Href, "styles.css"); - html.RenderBeginTag(HtmlTag.Link); - html.RenderEndTag(); - - html.RenderEndTag(); - - html.RenderBeginTag(HtmlTag.Body); - - for (int i = 0; i < m_Objects.Count; ++i) - { - RenderDirect(m_Objects[i], html); - html.Write("

"); - } - - html.RenderBeginTag(HtmlTag.Center); - TimeZone tz = TimeZone.CurrentTimeZone; - - html.Write("Snapshot taken at {0:d} {0:t}. All times are {1}.", m_TimeStamp, tz.StandardName); - html.RenderEndTag(); - - html.RenderEndTag(); - - html.RenderEndTag(); - } - - public static string SafeFileName(string name) - { - return name.ToLower().Replace(' ', '_'); - } - - public void RenderSingle(PersistableObject obj) - { - string filePath = Path.Combine(m_OutputDirectory, SafeFileName(FindNameFrom(obj)) + ".html"); - - using (StreamWriter op = new StreamWriter(filePath)) - { - using (HtmlTextWriter html = new HtmlTextWriter(op, "\t")) - { - RenderSingle(obj, html); - } - } - } - - private string FindNameFrom(PersistableObject obj) - { - if (obj is Report report) - return report.Name; - if (obj is Chart chart) - return chart.Name; - - return "Invalid"; - } - - public void RenderSingle(PersistableObject obj, HtmlTextWriter html) - { - html.RenderBeginTag(HtmlTag.Html); - - html.RenderBeginTag(HtmlTag.Head); - - html.RenderBeginTag(HtmlTag.Title); - html.Write("{0} Statistics - {1}", ShardTitle, FindNameFrom(obj)); - html.RenderEndTag(); - - html.AddAttribute("rel", "stylesheet"); - html.AddAttribute(HtmlAttr.Type, "text/css"); - html.AddAttribute(HtmlAttr.Href, "styles.css"); - html.RenderBeginTag(HtmlTag.Link); - html.RenderEndTag(); - - html.RenderEndTag(); - - html.RenderBeginTag(HtmlTag.Body); - - html.RenderBeginTag(HtmlTag.Center); - - RenderDirect(obj, html); - - html.Write("
"); - - TimeZone tz = TimeZone.CurrentTimeZone; - - html.Write("Snapshot taken at {0:d} {0:t}. All times are {1}.", m_TimeStamp, tz.StandardName); - html.RenderEndTag(); - - html.RenderEndTag(); - - html.RenderEndTag(); - } - - public void RenderDirect(PersistableObject obj, HtmlTextWriter html) - { - if (obj is Report report) - RenderReport(report, html); - else if (obj is BarGraph graph) - RenderBarGraph(graph, html); - else if (obj is PieChart chart) - RenderPieChart(chart, html); - } - - private void RenderPieChart(PieChart chart, HtmlTextWriter html) - { - PieChartRenderer pieChart = new PieChartRenderer(Color.White); - - pieChart.ShowPercents = chart.ShowPercents; - - string[] labels = new string[chart.Items.Count]; - string[] values = new string[chart.Items.Count]; - - for (int i = 0; i < chart.Items.Count; ++i) - { - ChartItem item = chart.Items[i]; - - labels[i] = item.Name; - values[i] = item.Value.ToString(); - } - - pieChart.CollectDataPoints(labels, values); - - Bitmap bmp = pieChart.Draw(); - - string fileName = chart.FileName + ".png"; - bmp.Save(Path.Combine(m_OutputDirectory, fileName), ImageFormat.Png); - - html.Write(""); - - html.AddAttribute(HtmlAttr.Cellpadding, "0"); - html.AddAttribute(HtmlAttr.Cellspacing, "0"); - html.AddAttribute(HtmlAttr.Border, "0"); - html.RenderBeginTag(HtmlTag.Table); - - html.RenderBeginTag(HtmlTag.Tr); - html.AddAttribute(HtmlAttr.Class, "tbl-border"); - html.RenderBeginTag(HtmlTag.Td); - - html.AddAttribute(HtmlAttr.Width, "100%"); - html.AddAttribute(HtmlAttr.Cellpadding, "4"); - html.AddAttribute(HtmlAttr.Cellspacing, "1"); - html.RenderBeginTag(HtmlTag.Table); - - html.RenderBeginTag(HtmlTag.Tr); - - html.AddAttribute(HtmlAttr.Colspan, "10"); - html.AddAttribute(HtmlAttr.Width, "100%"); - html.AddAttribute(HtmlAttr.Align, "center"); - html.AddAttribute(HtmlAttr.Class, "header"); - html.RenderBeginTag(HtmlTag.Td); - html.Write(chart.Name); - html.RenderEndTag(); - html.RenderEndTag(); - - html.RenderBeginTag(HtmlTag.Tr); - - html.AddAttribute(HtmlAttr.Colspan, "10"); - html.AddAttribute(HtmlAttr.Width, "100%"); - html.AddAttribute(HtmlAttr.Align, "center"); - html.AddAttribute(HtmlAttr.Class, "entry"); - html.RenderBeginTag(HtmlTag.Td); - - html.AddAttribute(HtmlAttr.Width, bmp.Width.ToString()); - html.AddAttribute(HtmlAttr.Height, bmp.Height.ToString()); - html.AddAttribute(HtmlAttr.Src, fileName); - html.RenderBeginTag(HtmlTag.Img); - html.RenderEndTag(); - - html.RenderEndTag(); - html.RenderEndTag(); - - html.RenderEndTag(); - html.RenderEndTag(); - html.RenderEndTag(); - html.RenderEndTag(); - - bmp.Dispose(); - } - - private void RenderBarGraph(BarGraph graph, HtmlTextWriter html) - { - BarGraphRenderer barGraph = new BarGraphRenderer(Color.White); - - barGraph.RenderMode = graph.RenderMode; - - barGraph._regions = graph.Regions; - barGraph.SetTitles(graph.xTitle, null); - - if (graph.yTitle != null) - barGraph.VerticalLabel = graph.yTitle; - - barGraph.FontColor = Color.Black; - barGraph.ShowData = graph.Interval == 1; - barGraph.VerticalTickCount = graph.Ticks; - - string[] labels = new string[graph.Items.Count]; - string[] values = new string[graph.Items.Count]; - - for (int i = 0; i < graph.Items.Count; ++i) - { - ChartItem item = graph.Items[i]; - - labels[i] = item.Name; - values[i] = item.Value.ToString(); - } - - barGraph._interval = graph.Interval; - barGraph.CollectDataPoints(labels, values); - - Bitmap bmp = barGraph.Draw(); - - string fileName = graph.FileName + ".png"; - bmp.Save(Path.Combine(m_OutputDirectory, fileName), ImageFormat.Png); - - html.Write(""); - - html.AddAttribute(HtmlAttr.Cellpadding, "0"); - html.AddAttribute(HtmlAttr.Cellspacing, "0"); - html.AddAttribute(HtmlAttr.Border, "0"); - html.RenderBeginTag(HtmlTag.Table); - - html.RenderBeginTag(HtmlTag.Tr); - html.AddAttribute(HtmlAttr.Class, "tbl-border"); - html.RenderBeginTag(HtmlTag.Td); - - html.AddAttribute(HtmlAttr.Width, "100%"); - html.AddAttribute(HtmlAttr.Cellpadding, "4"); - html.AddAttribute(HtmlAttr.Cellspacing, "1"); - html.RenderBeginTag(HtmlTag.Table); - - html.RenderBeginTag(HtmlTag.Tr); - - html.AddAttribute(HtmlAttr.Colspan, "10"); - html.AddAttribute(HtmlAttr.Width, "100%"); - html.AddAttribute(HtmlAttr.Align, "center"); - html.AddAttribute(HtmlAttr.Class, "header"); - html.RenderBeginTag(HtmlTag.Td); - html.Write(graph.Name); - html.RenderEndTag(); - html.RenderEndTag(); - - html.RenderBeginTag(HtmlTag.Tr); - - html.AddAttribute(HtmlAttr.Colspan, "10"); - html.AddAttribute(HtmlAttr.Width, "100%"); - html.AddAttribute(HtmlAttr.Align, "center"); - html.AddAttribute(HtmlAttr.Class, "entry"); - html.RenderBeginTag(HtmlTag.Td); - - html.AddAttribute(HtmlAttr.Width, bmp.Width.ToString()); - html.AddAttribute(HtmlAttr.Height, bmp.Height.ToString()); - html.AddAttribute(HtmlAttr.Src, fileName); - html.RenderBeginTag(HtmlTag.Img); - html.RenderEndTag(); - - html.RenderEndTag(); - html.RenderEndTag(); - - html.RenderEndTag(); - html.RenderEndTag(); - html.RenderEndTag(); - html.RenderEndTag(); - - bmp.Dispose(); - } - - private void RenderReport(Report report, HtmlTextWriter html) - { - html.AddAttribute(HtmlAttr.Width, report.Width); - html.AddAttribute(HtmlAttr.Cellpadding, "0"); - html.AddAttribute(HtmlAttr.Cellspacing, "0"); - html.AddAttribute(HtmlAttr.Border, "0"); - html.RenderBeginTag(HtmlTag.Table); - - html.RenderBeginTag(HtmlTag.Tr); - html.AddAttribute(HtmlAttr.Class, "tbl-border"); - html.RenderBeginTag(HtmlTag.Td); - - html.AddAttribute(HtmlAttr.Width, "100%"); - html.AddAttribute(HtmlAttr.Cellpadding, "4"); - html.AddAttribute(HtmlAttr.Cellspacing, "1"); - html.RenderBeginTag(HtmlTag.Table); - - html.RenderBeginTag(HtmlTag.Tr); - html.AddAttribute(HtmlAttr.Colspan, "10"); - html.AddAttribute(HtmlAttr.Width, "100%"); - html.AddAttribute(HtmlAttr.Align, "center"); - html.AddAttribute(HtmlAttr.Class, "header"); - html.RenderBeginTag(HtmlTag.Td); - html.Write(report.Name); - html.RenderEndTag(); - html.RenderEndTag(); - - bool isNamed = false; - - for (int i = 0; i < report.Columns.Count && !isNamed; ++i) - isNamed = report.Columns[i].Name != null; - - if (isNamed) - { - html.RenderBeginTag(HtmlTag.Tr); - - for (int i = 0; i < report.Columns.Count; ++i) - { - ReportColumn column = report.Columns[i]; - - html.AddAttribute(HtmlAttr.Class, "header"); - html.AddAttribute(HtmlAttr.Width, column.Width); - html.AddAttribute(HtmlAttr.Align, column.Align); - html.RenderBeginTag(HtmlTag.Td); - - html.Write(column.Name); - - html.RenderEndTag(); - } - - html.RenderEndTag(); - } - - for (int i = 0; i < report.Items.Count; ++i) - { - ReportItem item = report.Items[i]; - - html.RenderBeginTag(HtmlTag.Tr); - - for (int j = 0; j < item.Values.Count; ++j) - { - if (!isNamed && j == 0) - html.AddAttribute(HtmlAttr.Width, report.Columns[j].Width); - - html.AddAttribute(HtmlAttr.Align, report.Columns[j].Align); - html.AddAttribute(HtmlAttr.Class, "entry"); - html.RenderBeginTag(HtmlTag.Td); - - if (item.Values[j].Format == null) - html.Write(item.Values[j].Value); - else - html.Write(int.Parse(item.Values[j].Value).ToString(item.Values[j].Format)); - - html.RenderEndTag(); - } - - html.RenderEndTag(); - } - - html.RenderEndTag(); - html.RenderEndTag(); - html.RenderEndTag(); - html.RenderEndTag(); - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/PieChartRenderer.cs b/Scripts/Engines/Reports/Rendering/PieChartRenderer.cs deleted file mode 100644 index 9ecf48e04..000000000 --- a/Scripts/Engines/Reports/Rendering/PieChartRenderer.cs +++ /dev/null @@ -1,249 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; - -namespace Server.Engines.Reports -{ - // Modified from MS sample - - //********************************************************************* - // - // PieChart Class - // - // This class uses GDI+ to render Pie Chart. - // - //********************************************************************* - - public class PieChartRenderer : ChartRenderer - { - private const int _bufferSpace = 125; - private Color _backgroundColor; - private Color _borderColor; - private List _chartItems; - private int _legendFontHeight; - private float _legendFontSize; - private string _legendFontStyle; - private int _legendHeight; - private int _legendWidth; - private int _perimeter; - private float _total; - - public PieChartRenderer() : this(Color.White) - { - } - - public PieChartRenderer(Color bgColor) - { - _chartItems = new List(); - _perimeter = 250; - _backgroundColor = bgColor; - _borderColor = Color.FromArgb(63, 63, 63); - _legendFontSize = 8; - _legendFontStyle = "Verdana"; - } - - public bool ShowPercents{ get; set; } - - //********************************************************************* - // - // This method collects all data points and calculate all the necessary dimensions - // to draw the chart. It is the first method called before invoking the Draw() method. - // - //********************************************************************* - - public void CollectDataPoints(string[] xValues, string[] yValues) - { - _total = 0.0f; - - for (int i = 0; i < xValues.Length; i++) - { - float ftemp = Convert.ToSingle(yValues[i]); - _chartItems.Add(new DataItem(xValues[i], xValues.ToString(), ftemp, 0, 0, Color.AliceBlue)); - _total += ftemp; - } - - float nextStartPos = 0.0f; - int counter = 0; - foreach (DataItem item in _chartItems) - { - item.StartPos = nextStartPos; - item.SweepSize = item.Value / _total * 360; - nextStartPos = item.StartPos + item.SweepSize; - item.ItemColor = GetColor(counter++); - } - - CalculateLegendWidthHeight(); - } - - //********************************************************************* - // - // This method returns a bitmap to the calling function. This is the method - // that actually draws the pie chart and the legend with it. - // - //********************************************************************* - - public override Bitmap Draw() - { - int perimeter = _perimeter; - Rectangle pieRect = new Rectangle(0, 0, perimeter, perimeter - 1); - Bitmap bmp = new Bitmap(perimeter + _legendWidth, perimeter); - Font fnt = null; - Pen pen = null; - Graphics grp = null; - StringFormat sf = null, sfp = null; - - try - { - grp = Graphics.FromImage(bmp); - grp.CompositingQuality = CompositingQuality.HighQuality; - grp.SmoothingMode = SmoothingMode.AntiAlias; - sf = new StringFormat(); - - //Paint Back ground - using (SolidBrush brsh = new SolidBrush(_backgroundColor)) - { - grp.FillRectangle(brsh, -1, -1, perimeter + _legendWidth + 1, perimeter + 1); - } - - //Align text to the right - sf.Alignment = StringAlignment.Far; - - //Draw all wedges and legends - for (int i = 0; i < _chartItems.Count; i++) - { - DataItem item = _chartItems[i]; - SolidBrush brs = null; - try - { - brs = new SolidBrush(item.ItemColor); - grp.FillPie(brs, pieRect, item.StartPos, item.SweepSize); - - //grp.DrawPie(new Pen(_borderColor,1.2f),pieRect,item.StartPos,item.SweepSize); - - if (fnt == null) - fnt = new Font(_legendFontStyle, _legendFontSize); - - if (ShowPercents && item.SweepSize > 10) - { - if (sfp == null) - { - sfp = new StringFormat(); - sfp.Alignment = StringAlignment.Center; - sfp.LineAlignment = StringAlignment.Center; - } - - float perc = item.SweepSize * 100.0f / 360.0f; - string percString = $"{perc:F0}%"; - - float px = pieRect.X + pieRect.Width / 2; - float py = pieRect.Y + pieRect.Height / 2; - - double angle = item.StartPos + item.SweepSize / 2; - double rads = angle / 180.0 * Math.PI; - - px += (float)(Math.Cos(rads) * perimeter / 3); - py += (float)(Math.Sin(rads) * perimeter / 3); - - grp.DrawString(percString, fnt, Brushes.Gray, - new RectangleF(px - 30 - 1, py - 20, 60, 40), sfp); - - grp.DrawString(percString, fnt, Brushes.Gray, - new RectangleF(px - 30 + 1, py - 20, 60, 40), sfp); - - grp.DrawString(percString, fnt, Brushes.Gray, - new RectangleF(px - 30, py - 20 - 1, 60, 40), sfp); - - grp.DrawString(percString, fnt, Brushes.Gray, - new RectangleF(px - 30, py - 20 + 1, 60, 40), sfp); - - - grp.DrawString(percString, fnt, Brushes.White, - new RectangleF(px - 30, py - 20, 60, 40), sfp); - } - - if (pen == null) - pen = new Pen(_borderColor, 0.5f); - - grp.FillRectangle(brs, perimeter + _bufferSpace, i * _legendFontHeight + 15, 10, 10); - grp.DrawRectangle(pen, perimeter + _bufferSpace, i * _legendFontHeight + 15, 10, 10); - - grp.DrawString(item.Label, fnt, - Brushes.Black, perimeter + _bufferSpace + 20, i * _legendFontHeight + 13); - - grp.DrawString(item.Value.ToString("#,###.##"), fnt, - Brushes.Black, perimeter + _bufferSpace + 200, i * _legendFontHeight + 13, sf); - } - finally - { - brs?.Dispose(); - } - } - - for (int i = 0; i < _chartItems.Count; i++) - { - DataItem item = _chartItems[i]; - try - { - grp.DrawPie(new Pen(_borderColor, 0.5f), pieRect, item.StartPos, item.SweepSize); - } - catch - { - // ignored - } - } - - //draws the border around Pie - using (Pen pen2 = new Pen(_borderColor, 2)) - { - grp.DrawEllipse(pen2, pieRect); - } - - //draw border around legend - using (Pen pen1 = new Pen(_borderColor, 1)) - { - grp.DrawRectangle(pen1, perimeter + _bufferSpace - 10, 10, 220, - _chartItems.Count * _legendFontHeight + 25); - } - - //Draw Total under legend - using (Font fntb = new Font(_legendFontStyle, _legendFontSize, FontStyle.Bold)) - { - grp.DrawString("Total", fntb, - Brushes.Black, perimeter + _bufferSpace + 30, (_chartItems.Count + 1) * _legendFontHeight, sf); - grp.DrawString(_total.ToString("#,###.##"), fntb, - Brushes.Black, perimeter + _bufferSpace + 200, (_chartItems.Count + 1) * _legendFontHeight, sf); - } - - grp.SmoothingMode = SmoothingMode.AntiAlias; - } - finally - { - sf.Dispose(); - grp.Dispose(); - sfp?.Dispose(); - fnt?.Dispose(); - pen?.Dispose(); - } - - return bmp; - } - - //********************************************************************* - // - // This method calculates the space required to draw the chart legend. - // - //********************************************************************* - - private void CalculateLegendWidthHeight() - { - Font fontLegend = new Font(_legendFontStyle, _legendFontSize); - _legendFontHeight = fontLegend.Height + 3; - _legendHeight = fontLegend.Height * (_chartItems.Count + 1); - if (_legendHeight > _perimeter) _perimeter = _legendHeight; - - _legendWidth = _perimeter + _bufferSpace; - fontLegend.Dispose(); - } - } -} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Reports.cs b/Scripts/Engines/Reports/Reports.cs deleted file mode 100644 index 2b7d08eaf..000000000 --- a/Scripts/Engines/Reports/Reports.cs +++ /dev/null @@ -1,547 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using Server.Accounting; -using Server.Engines.ConPVP; -using Server.Engines.Help; -using Server.Factions; -using Server.Mobiles; -using Server.Network; - -namespace Server.Engines.Reports -{ - public class Reports - { - public static bool Enabled = false; - - private static DateTime m_GenerateTime; - - private static SnapshotHistory m_StatsHistory; - - public static StaffHistory StaffHistory{ get; private set; } - - public static void Initialize() - { - if (!Enabled) - return; - - m_StatsHistory = new SnapshotHistory(); - m_StatsHistory.Load(); - - StaffHistory = new StaffHistory(); - StaffHistory.Load(); - - DateTime now = DateTime.UtcNow; - - DateTime date = now.Date; - TimeSpan timeOfDay = now.TimeOfDay; - - m_GenerateTime = date + TimeSpan.FromHours(Math.Ceiling(timeOfDay.TotalHours)); - - Timer.DelayCall(TimeSpan.FromMinutes(0.5), TimeSpan.FromMinutes(0.5), CheckRegenerate); - } - - public static void CheckRegenerate() - { - if (DateTime.UtcNow < m_GenerateTime) - return; - - Generate(); - m_GenerateTime += TimeSpan.FromHours(1.0); - } - - public static void Generate() - { - Snapshot ss = new Snapshot(); - - ss.TimeStamp = DateTime.UtcNow; - - FillSnapshot(ss); - - m_StatsHistory.Snapshots.Add(ss); - StaffHistory.QueueStats.Add(new QueueStatus(PageQueue.List.Count)); - - ThreadPool.QueueUserWorkItem(UpdateOutput, ss); - } - - private static void UpdateOutput(object state) - { - m_StatsHistory.Save(); - StaffHistory.Save(); - - HtmlRenderer renderer = new HtmlRenderer("stats", (Snapshot)state, m_StatsHistory); - renderer.Render(); - renderer.Upload(); - - renderer = new HtmlRenderer("staff", StaffHistory); - renderer.Render(); - renderer.Upload(); - } - - public static void FillSnapshot(Snapshot ss) - { - ss.Children.Add(CompileGeneralStats()); - ss.Children.Add(CompilePCByDL()); - ss.Children.Add(CompileTop15()); - ss.Children.Add(CompileDislikedArenas()); - ss.Children.Add(CompileStatChart()); - - PersistableObject[] obs = CompileSkillReports(); - - for (int i = 0; i < obs.Length; ++i) - ss.Children.Add(obs[i]); - - obs = CompileFactionReports(); - - for (int i = 0; i < obs.Length; ++i) - ss.Children.Add(obs[i]); - } - - public static Report CompileGeneralStats() - { - Report report = new Report("General Stats", "200"); - - report.Columns.Add("50%", "left"); - report.Columns.Add("50%", "left"); - - int npcs = 0, players = 0; - - foreach (Mobile mob in World.Mobiles.Values) - if (mob.Player) - ++players; - else - ++npcs; - - report.Items.Add("NPCs", npcs, "N0"); - report.Items.Add("Players", players, "N0"); - report.Items.Add("Clients", NetState.Instances.Count, "N0"); - report.Items.Add("Accounts", Accounts.Count, "N0"); - report.Items.Add("Items", World.Items.Count, "N0"); - - return report; - } - - private static Chart CompilePCByDL() - { - BarGraph chart = new BarGraph("Player Count By Dueling Level", "graphs_pc_by_dl", 5, "Dueling Level", "Players", - BarGraphRenderMode.Bars); - - int lastLevel = -1; - ChartItem lastItem = null; - - Ladder ladder = Ladder.Instance; - - if (ladder == null) - return chart; - - List entries = ladder.Entries; - - for (int i = entries.Count - 1; i >= 0; --i) - { - LadderEntry entry = entries[i]; - int level = Ladder.GetLevel(entry.Experience); - - if (lastItem == null || level != lastLevel) - { - chart.Items.Add(lastItem = new ChartItem(level.ToString(), 1)); - lastLevel = level; - } - else - { - lastItem.Value++; - } - } - - return chart; - } - - private static Report CompileTop15() - { - Report report = new Report("Top 15 Duelists", "80%"); - - report.Columns.Add("6%", "center", "Rank"); - report.Columns.Add("6%", "center", "Level"); - report.Columns.Add("6%", "center", "Guild"); - report.Columns.Add("70%", "left", "Name"); - report.Columns.Add("6%", "center", "Wins"); - report.Columns.Add("6%", "center", "Losses"); - - Ladder ladder = Ladder.Instance; - - if (ladder != null) - { - List entries = ladder.Entries; - - for (int i = 0; i < entries.Count && i < 15; ++i) - { - LadderEntry entry = entries[i]; - int level = Ladder.GetLevel(entry.Experience); - string guild = ""; - - if (entry.Mobile.Guild != null) - guild = entry.Mobile.Guild.Abbreviation; - - ReportItem item = new ReportItem(); - - item.Values.Add(LadderGump.Rank(entry.Index + 1)); - item.Values.Add(level.ToString(), "N0"); - item.Values.Add(guild); - item.Values.Add(entry.Mobile.Name); - item.Values.Add(entry.Wins.ToString(), "N0"); - item.Values.Add(entry.Losses.ToString(), "N0"); - - report.Items.Add(item); - } - } - - return report; - } - - private static Chart CompileDislikedArenas() - { - PieChart chart = new PieChart("Most Disliked Arenas", "graphs_arenas_disliked", false); - - Preferences prefs = Preferences.Instance; - - if (prefs == null) - return chart; - - List arenas = Arena.Arenas; - - for (int i = 0; i < arenas.Count; ++i) - { - Arena arena = arenas[i]; - - string name = arena.Name; - - if (name != null) - chart.Items.Add(name, 0); - } - - List entries = prefs.Entries; - - for (int i = 0; i < entries.Count; ++i) - { - PreferencesEntry entry = entries[i]; - List list = entry.Disliked; - - for (int j = 0; j < list.Count; ++j) - { - string disliked = list[j]; - - for (int k = 0; k < chart.Items.Count; ++k) - { - ChartItem item = chart.Items[k]; - - if (item.Name == disliked) - { - ++item.Value; - break; - } - } - } - } - - return chart; - } - - public static Chart CompileStatChart() - { - PieChart chart = new PieChart("Stat Distribution", "graphs_strdexint_distrib", true); - - ChartItem strItem = new ChartItem("Strength", 0); - ChartItem dexItem = new ChartItem("Dexterity", 0); - ChartItem intItem = new ChartItem("Intelligence", 0); - - foreach (Mobile mob in World.Mobiles.Values) - if (mob.RawStatTotal == mob.StatCap && mob is PlayerMobile) - { - strItem.Value += mob.RawStr; - dexItem.Value += mob.RawDex; - intItem.Value += mob.RawInt; - } - - chart.Items.Add(strItem); - chart.Items.Add(dexItem); - chart.Items.Add(intItem); - - return chart; - } - - public static SkillDistribution[] GetSkillDistribution() - { - int skip = Core.ML ? 0 : Core.SE ? 1 : Core.AOS ? 3 : 6; - - SkillDistribution[] distribs = new SkillDistribution[SkillInfo.Table.Length - skip]; - - for (int i = 0; i < distribs.Length; ++i) - distribs[i] = new SkillDistribution(SkillInfo.Table[i]); - - foreach (Mobile mob in World.Mobiles.Values) - if (mob.SkillsTotal >= 1500 && mob.SkillsTotal <= 7200 && mob is PlayerMobile) - { - Skills skills = mob.Skills; - - for (int i = 0; i < skills.Length - skip; ++i) - { - Skill skill = skills[i]; - - if (skill.BaseFixedPoint >= 1000) - distribs[i].m_NumberOfGMs++; - } - } - - return distribs; - } - - public static PersistableObject[] CompileSkillReports() - { - SkillDistribution[] distribs = GetSkillDistribution(); - - Array.Sort(distribs); - - return new PersistableObject[] { CompileSkillChart(distribs), CompileSkillReport(distribs) }; - } - - public static Report CompileSkillReport(SkillDistribution[] distribs) - { - Report report = new Report("Skill Report", "300"); - - report.Columns.Add("70%", "left", "Name"); - report.Columns.Add("30%", "center", "GMs"); - - for (int i = 0; i < distribs.Length; ++i) - report.Items.Add(distribs[i].m_Skill.Name, distribs[i].m_NumberOfGMs, "N0"); - - return report; - } - - public static Chart CompileSkillChart(SkillDistribution[] distribs) - { - PieChart chart = new PieChart("GM Skill Distribution", "graphs_skill_distrib", true); - - for (int i = 0; i < 12; ++i) - chart.Items.Add(distribs[i].m_Skill.Name, distribs[i].m_NumberOfGMs); - - int rem = 0; - - for (int i = 12; i < distribs.Length; ++i) - rem += distribs[i].m_NumberOfGMs; - - chart.Items.Add("Other", rem); - - return chart; - } - - public static PersistableObject[] CompileFactionReports() - { - return new PersistableObject[] - { - CompileFactionMembershipChart(), CompileFactionReport(), CompileFactionTownReport(), CompileSigilReport(), - CompileFactionLeaderboard() - }; - } - - public static Chart CompileFactionMembershipChart() - { - PieChart chart = new PieChart("Faction Membership", "graphs_faction_membership", true); - - List factions = Faction.Factions; - - for (int i = 0; i < factions.Count; ++i) - chart.Items.Add(factions[i].Definition.FriendlyName, factions[i].Members.Count); - - return chart; - } - - public static Report CompileFactionLeaderboard() - { - Report report = new Report("Faction Leaderboard", "60%"); - - report.Columns.Add("28%", "center", "Name"); - report.Columns.Add("28%", "center", "Faction"); - report.Columns.Add("28%", "center", "Office"); - report.Columns.Add("16%", "center", "Kill Points"); - - List list = new List(); - - List factions = Faction.Factions; - - for (int i = 0; i < factions.Count; ++i) - { - Faction faction = factions[i]; - - list.AddRange(faction.Members); - } - - list.Sort(); - list.Reverse(); - - for (int i = 0; i < list.Count && i < 15; ++i) - { - PlayerState pl = list[i]; - - string office; - - if (pl.Faction.Commander == pl.Mobile) - office = "Commanding Lord"; - else if (pl.Finance != null) - office = $"{pl.Finance.Definition.FriendlyName} Finance Minister"; - else if (pl.Sheriff != null) - office = $"{pl.Sheriff.Definition.FriendlyName} Sheriff"; - else - office = ""; - - ReportItem item = new ReportItem(); - - item.Values.Add(pl.Mobile.Name); - item.Values.Add(pl.Faction.Definition.FriendlyName); - item.Values.Add(office); - item.Values.Add(pl.KillPoints.ToString(), "N0"); - - report.Items.Add(item); - } - - return report; - } - - public static Report CompileFactionReport() - { - Report report = new Report("Faction Statistics", "80%"); - - report.Columns.Add("20%", "center", "Name"); - report.Columns.Add("20%", "center", "Commander"); - report.Columns.Add("15%", "center", "Members"); - report.Columns.Add("15%", "center", "Merchants"); - report.Columns.Add("15%", "center", "Kill Points"); - report.Columns.Add("15%", "center", "Silver"); - - List factions = Faction.Factions; - - for (int i = 0; i < factions.Count; ++i) - { - Faction faction = factions[i]; - List members = faction.Members; - - int totalKillPoints = 0; - int totalMerchants = 0; - - for (int j = 0; j < members.Count; ++j) - { - totalKillPoints += members[j].KillPoints; - - if (members[j].MerchantTitle != MerchantTitle.None) - ++totalMerchants; - } - - ReportItem item = new ReportItem(); - - item.Values.Add(faction.Definition.FriendlyName); - item.Values.Add(faction.Commander == null ? "" : faction.Commander.Name); - item.Values.Add(faction.Members.Count.ToString(), "N0"); - item.Values.Add(totalMerchants.ToString(), "N0"); - item.Values.Add(totalKillPoints.ToString(), "N0"); - item.Values.Add(faction.Silver.ToString(), "N0"); - - report.Items.Add(item); - } - - return report; - } - - public static Report CompileSigilReport() - { - Report report = new Report("Faction Town Sigils", "50%"); - - report.Columns.Add("35%", "center", "Town"); - report.Columns.Add("35%", "center", "Controller"); - report.Columns.Add("30%", "center", "Capturable"); - - List sigils = Sigil.Sigils; - - for (int i = 0; i < sigils.Count; ++i) - { - Sigil sigil = sigils[i]; - - string controller = "Unknown"; - - if (sigil.RootParent is Mobile mob) - { - Faction faction = Faction.Find(mob); - - if (faction != null) - controller = faction.Definition.FriendlyName; - } - else if (sigil.LastMonolith?.Faction != null) - { - controller = sigil.LastMonolith.Faction.Definition.FriendlyName; - } - - ReportItem item = new ReportItem(); - - item.Values.Add(sigil.Town == null ? "" : sigil.Town.Definition.FriendlyName); - item.Values.Add(controller); - item.Values.Add(sigil.IsPurifying ? "No" : "Yes"); - - report.Items.Add(item); - } - - return report; - } - - public static Report CompileFactionTownReport() - { - Report report = new Report("Faction Towns", "80%"); - - report.Columns.Add("20%", "center", "Name"); - report.Columns.Add("20%", "center", "Owner"); - report.Columns.Add("17%", "center", "Sheriff"); - report.Columns.Add("17%", "center", "Finance Minister"); - report.Columns.Add("13%", "center", "Silver"); - report.Columns.Add("13%", "center", "Prices"); - - List towns = Town.Towns; - - for (int i = 0; i < towns.Count; ++i) - { - Town town = towns[i]; - - string prices = "Normal"; - - if (town.Tax < 0) - prices = town.Tax + "%"; - else if (town.Tax > 0) - prices = "+" + town.Tax + "%"; - - ReportItem item = new ReportItem(); - - item.Values.Add(town.Definition.FriendlyName); - item.Values.Add(town.Owner == null ? "Neutral" : town.Owner.Definition.FriendlyName); - item.Values.Add(town.Sheriff == null ? "" : town.Sheriff.Name); - item.Values.Add(town.Finance == null ? "" : town.Finance.Name); - item.Values.Add(town.Silver.ToString(), "N0"); - item.Values.Add(prices); - - report.Items.Add(item); - } - - return report; - } - - public class SkillDistribution : IComparable - { - public int m_NumberOfGMs; - public SkillInfo m_Skill; - - public SkillDistribution(SkillInfo skill) - { - m_Skill = skill; - } - - public int CompareTo(SkillDistribution sd) - { - return sd?.m_NumberOfGMs ?? 0 - m_NumberOfGMs; - } - } - } -} diff --git a/Scripts/Gumps/AdminGump.cs b/Scripts/Gumps/AdminGump.cs index a7ad3b44f..01f1f25b6 100644 --- a/Scripts/Gumps/AdminGump.cs +++ b/Scripts/Gumps/AdminGump.cs @@ -209,38 +209,6 @@ namespace Server.Gumps sb.Append((maxIOCP - curIOCP) * 100 / maxIOCP); sb.Append("%"); - List pools = BufferPool.Pools; - - lock (pools) - { - for (int i = 0; i < pools.Count; ++i) - { - BufferPool pool = pools[i]; - pool.GetInfo(out string name, out int freeCount, out _, - out int currentCapacity, out int bufferSize, out int misses); - - if (sb.Length > 0) - sb.Append("

"); - - sb.Append(name); - sb.Append("
Size: "); - sb.Append(FormatByteAmount(bufferSize)); - sb.Append("
Capacity: "); - sb.Append(currentCapacity); - sb.Append(" ("); - sb.Append(misses); - sb.Append(" misses)
Available: "); - sb.Append(freeCount); - sb.Append("
Usage: "); - sb.Append((currentCapacity - freeCount) * 100 / currentCapacity); - sb.Append("% : "); - sb.Append(FormatByteAmount((currentCapacity - freeCount) * bufferSize)); - sb.Append(" of "); - sb.Append(FormatByteAmount(currentCapacity * bufferSize)); - } - } - - AddLabel(20, 200, LabelHue, "Pooling:"); AddHtml(20, 220, 380, 150, sb.ToString(), true, true); diff --git a/Scripts/Items/Armor/BaseArmor.cs b/Scripts/Items/Armor/BaseArmor.cs index c46c0c399..7ff3bdfdf 100644 --- a/Scripts/Items/Armor/BaseArmor.cs +++ b/Scripts/Items/Armor/BaseArmor.cs @@ -6,7 +6,6 @@ using Server.Factions; using Server.Network; using AMA = Server.Items.ArmorMeditationAllowance; using AMT = Server.Items.ArmorMaterialType; -using ABT = Server.Items.ArmorBodyType; namespace Server.Items { diff --git a/Scripts/Misc/Assistants.cs b/Scripts/Misc/Assistants.cs index a6172e18d..b93429e0b 100644 --- a/Scripts/Misc/Assistants.cs +++ b/Scripts/Misc/Assistants.cs @@ -88,11 +88,11 @@ namespace Server.Misc public static void Initialize() { - if (Settings.Enabled) +/* if (Settings.Enabled) { EventSink.Login += EventSink_Login; ProtocolExtensions.Register(0xFF, true, OnHandshakeResponse); - } + }*/ } private static void EventSink_Login(LoginEventArgs e) diff --git a/Scripts/Misc/Broadcasts.cs b/Scripts/Misc/Broadcasts.cs index 59e39472b..65d5f79a3 100644 --- a/Scripts/Misc/Broadcasts.cs +++ b/Scripts/Misc/Broadcasts.cs @@ -22,14 +22,14 @@ namespace Server.Misc public static void EventSink_Shutdown(ShutdownEventArgs e) { - try +/* try { World.Broadcast(0x35, true, "The server has shut down."); } catch { // ignored - } + }*/ } } -} \ No newline at end of file +} diff --git a/Scripts/Misc/DataPath.cs b/Scripts/Misc/DataPath.cs index 2914455b7..7830c89f1 100644 --- a/Scripts/Misc/DataPath.cs +++ b/Scripts/Misc/DataPath.cs @@ -1,6 +1,4 @@ using System; -using System.IO; -using Microsoft.Win32; namespace Server.Misc { @@ -12,7 +10,8 @@ namespace Server.Misc * Example: * private static string CustomPath = @"C:\Program Files\Ultima Online"; */ - private static string CustomPath = null; + private static string CustomPath = @"C:\Ultima Online Classic"; + // private static string CustomPath = @"/Users/kamronbatman/UOC"; /* The following is a list of files which a required for proper execution: * @@ -69,7 +68,8 @@ namespace Server.Misc private static string GetPath(string subName, string keyName) { - try + return null; + /*try { string keyString; @@ -102,7 +102,7 @@ namespace Server.Misc catch { return null; - } + }*/ } } -} \ No newline at end of file +} diff --git a/Scripts/Misc/DoorGenerator.cs b/Scripts/Misc/DoorGenerator.cs index a0cf69ea4..5ad35ea67 100644 --- a/Scripts/Misc/DoorGenerator.cs +++ b/Scripts/Misc/DoorGenerator.cs @@ -349,7 +349,6 @@ namespace Server { World.Broadcast(0x35, true, "Generating doors, please wait."); - NetState.FlushAll(); NetState.Pause(); m_Map = Map.Trammel; @@ -555,4 +554,4 @@ namespace Server } } } -} \ No newline at end of file +} diff --git a/Scripts/Misc/Emitter.cs b/Scripts/Misc/Emitter.cs index 67369af61..ceaca1f69 100644 --- a/Scripts/Misc/Emitter.cs +++ b/Scripts/Misc/Emitter.cs @@ -13,45 +13,24 @@ namespace Server private AssemblyBuilder m_AssemblyBuilder; private ModuleBuilder m_ModuleBuilder; - public AssemblyEmitter( string assemblyName, bool canSave ) + public AssemblyEmitter( string assemblyName ) { m_AssemblyName = assemblyName; m_AppDomain = AppDomain.CurrentDomain; - m_AssemblyBuilder = m_AppDomain.DefineDynamicAssembly( + m_AssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( new AssemblyName( assemblyName ), - canSave ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run + AssemblyBuilderAccess.Run ); - if ( canSave ) - { - m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule( - assemblyName, - $"{assemblyName.ToLower()}.dll", - false - ); - } - else - { - m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule( - assemblyName, - false - ); - } + m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule(assemblyName); } public TypeBuilder DefineType( string typeName, TypeAttributes attrs, Type parentType ) { return m_ModuleBuilder.DefineType( typeName, attrs, parentType ); } - - public void Save() - { - m_AssemblyBuilder.Save( - $"{m_AssemblyName.ToLower()}.dll" - ); - } } public class MethodEmitter diff --git a/Scripts/Misc/ProfanityProtection.cs b/Scripts/Misc/ProfanityProtection.cs index 57c47db75..08e37dcec 100644 --- a/Scripts/Misc/ProfanityProtection.cs +++ b/Scripts/Misc/ProfanityProtection.cs @@ -96,9 +96,7 @@ namespace Server.Misc return true; case ProfanityAction.Disconnect: { - NetState ns = from.NetState; - - ns?.Dispose(); + from.NetState?.Dispose(); return false; } diff --git a/Scripts/Misc/ServerList.cs b/Scripts/Misc/ServerList.cs index be4298ebe..469fc8d84 100644 --- a/Scripts/Misc/ServerList.cs +++ b/Scripts/Misc/ServerList.cs @@ -80,8 +80,9 @@ namespace Server.Misc e.AddServer(ServerName, new IPEndPoint(localAddress, localPort)); } - catch + catch (Exception er) { + Console.WriteLine(er); e.Rejected = true; } } @@ -206,4 +207,4 @@ namespace Server.Misc } } } -} \ No newline at end of file +} diff --git a/Scripts/Misc/SocketOptions.cs b/Scripts/Misc/SocketOptions.cs index 8abfebbdb..330962b3d 100644 --- a/Scripts/Misc/SocketOptions.cs +++ b/Scripts/Misc/SocketOptions.cs @@ -1,3 +1,4 @@ +using System; using System.Net; using System.Net.Sockets; using Server.Network; @@ -7,7 +8,6 @@ namespace Server public class SocketOptions { private const bool NagleEnabled = false; // Should the Nagle algorithm be enabled? This may reduce performance - private const int CoalesceBufferSize = 512; // MSS that the core will use when buffering packets private static IPEndPoint[] m_ListenerEndPoints = { @@ -20,11 +20,13 @@ namespace Server public static void Initialize() { - SendQueue.CoalesceBufferSize = CoalesceBufferSize; - EventSink.SocketConnect += EventSink_SocketConnect; + } - Listener.EndPoints = m_ListenerEndPoints; + public static void RegisterListeners() + { + for (int i = 0; i < m_ListenerEndPoints.Length; i++) + Core.MessagePump.AddListener(m_ListenerEndPoints[i]); } private static void EventSink_SocketConnect(SocketConnectEventArgs e) @@ -36,4 +38,4 @@ namespace Server e.Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1); // RunUO uses its own algorithm } } -} \ No newline at end of file +} diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs index f950be625..12a8a58d5 100644 --- a/Scripts/Mobiles/PlayerMobile.cs +++ b/Scripts/Mobiles/PlayerMobile.cs @@ -10,7 +10,6 @@ using Server.Engines.Craft; using Server.Engines.Help; using Server.Engines.MLQuests; using Server.Engines.MLQuests.Gumps; -using Server.Engines.MyRunUO; using Server.Engines.PartySystem; using Server.Engines.Quests; using Server.Ethics; @@ -155,15 +154,12 @@ namespace Server.Mobiles m_GuildRank = RankDefinition.Lowest; ChampionTitles = new ChampionTitleInfo(); - - InvalidateMyRunUO(); } public PlayerMobile(Serial s) : base(s) { VisibilityList = new List(); m_AntiMacroTable = new Dictionary>(); - InvalidateMyRunUO(); } [CommandProperty(AccessLevel.GameMaster)] @@ -943,9 +939,6 @@ namespace Server.Mobiles if ((flag & MobileDelta.Stat) != 0) ValidateEquipment(); - - if ((flag & (MobileDelta.Name | MobileDelta.Hue)) != 0) - InvalidateMyRunUO(); } private static void OnLogout(LogoutEventArgs e) @@ -1100,8 +1093,6 @@ namespace Server.Mobiles if (NetState != null) CheckLightLevels(false); - - InvalidateMyRunUO(); } public override void OnItemRemoved(Item item) @@ -1117,8 +1108,6 @@ namespace Server.Mobiles if (NetState != null) CheckLightLevels(false); - - InvalidateMyRunUO(); } private void AddArmorRating(ref double rating, Item armor) @@ -3095,11 +3084,7 @@ namespace Server.Mobiles public bool PublicMyRunUO { get => GetFlag(PlayerFlag.PublicMyRunUO); - set - { - SetFlag(PlayerFlag.PublicMyRunUO, value); - InvalidateMyRunUO(); - } + set => SetFlag(PlayerFlag.PublicMyRunUO, value); } [CommandProperty(AccessLevel.GameMaster)] @@ -3868,45 +3853,29 @@ namespace Server.Mobiles public bool ChangedMyRunUO{ get; set; } - public void InvalidateMyRunUO() - { - if (!Deleted && !ChangedMyRunUO) - { - ChangedMyRunUO = true; - MyRunUO.QueueMobileUpdate(this); - } - } - public override void OnKillsChange(int oldValue) { if (Young && Kills > oldValue) ((Account)Account)?.RemoveYoungStatus(0); - - InvalidateMyRunUO(); } public override void OnGenderChanged(bool oldFemale) { - InvalidateMyRunUO(); } public override void OnGuildChange(BaseGuild oldGuild) { - InvalidateMyRunUO(); } public override void OnGuildTitleChange(string oldTitle) { - InvalidateMyRunUO(); } public override void OnKarmaChange(int oldValue) { - InvalidateMyRunUO(); } public override void OnFameChange(int oldValue) { - InvalidateMyRunUO(); } public override void OnSkillChange(SkillName skill, double oldBase) @@ -3918,31 +3887,21 @@ namespace Server.Mobiles if (MLQuestSystem.Enabled) MLQuestSystem.HandleSkillGain(this, skill); - - InvalidateMyRunUO(); } public override void OnAccessLevelChanged(AccessLevel oldLevel) { - if (AccessLevel == AccessLevel.Player) - IgnoreMobiles = false; - else - IgnoreMobiles = true; - - InvalidateMyRunUO(); + IgnoreMobiles = AccessLevel != AccessLevel.Player; } public override void OnRawStatChange(StatType stat, int oldValue) { - InvalidateMyRunUO(); } public override void OnDelete() { ReceivedHonorContext?.Cancel(); SentHonorContext?.Cancel(); - - InvalidateMyRunUO(); } #endregion @@ -3979,17 +3938,17 @@ namespace Server.Mobiles return running ? RunFoot : WalkFoot; } - public static bool MovementThrottle_Callback(NetState ns) + public static TimeSpan MovementThrottle_Callback(NetState ns) { if (!(ns.Mobile is PlayerMobile pm) || !pm.UsesFastwalkPrevention) - return true; + return TimeSpan.Zero; if (!pm.m_HasMoved) { // has not yet moved pm.m_NextMovementTime = Core.TickCount; pm.m_HasMoved = true; - return true; + return TimeSpan.Zero; } long ts = pm.m_NextMovementTime - Core.TickCount; @@ -3998,10 +3957,10 @@ namespace Server.Mobiles { // been a while since we've last moved pm.m_NextMovementTime = Core.TickCount; - return true; + return TimeSpan.Zero; } - return ts < FastwalkThreshold; + return ts < FastwalkThreshold ? TimeSpan.Zero : TimeSpan.FromTicks(ts); } #endregion diff --git a/Scripts/Mobiles/Townfolk/BrideGroom.cs b/Scripts/Mobiles/Townfolk/BrideGroom.cs index 41e6701b4..4fc438c14 100644 --- a/Scripts/Mobiles/Townfolk/BrideGroom.cs +++ b/Scripts/Mobiles/Townfolk/BrideGroom.cs @@ -1,5 +1,4 @@ using Server.Items; -using EDI = Server.Mobiles.EscortDestinationInfo; namespace Server.Mobiles { diff --git a/Scripts/Mobiles/Townfolk/EscortableMage.cs b/Scripts/Mobiles/Townfolk/EscortableMage.cs index cec9a7150..77a8254bd 100644 --- a/Scripts/Mobiles/Townfolk/EscortableMage.cs +++ b/Scripts/Mobiles/Townfolk/EscortableMage.cs @@ -1,5 +1,4 @@ using Server.Items; -using EDI = Server.Mobiles.EscortDestinationInfo; namespace Server.Mobiles { diff --git a/Scripts/Mobiles/Townfolk/Merchant.cs b/Scripts/Mobiles/Townfolk/Merchant.cs index 94ca2fe94..6bd1a8a82 100644 --- a/Scripts/Mobiles/Townfolk/Merchant.cs +++ b/Scripts/Mobiles/Townfolk/Merchant.cs @@ -1,5 +1,4 @@ using Server.Items; -using EDI = Server.Mobiles.EscortDestinationInfo; namespace Server.Mobiles { diff --git a/Scripts/Mobiles/Townfolk/Messenger.cs b/Scripts/Mobiles/Townfolk/Messenger.cs index 99b8b8108..0adc41431 100644 --- a/Scripts/Mobiles/Townfolk/Messenger.cs +++ b/Scripts/Mobiles/Townfolk/Messenger.cs @@ -1,5 +1,4 @@ using Server.Items; -using EDI = Server.Mobiles.EscortDestinationInfo; namespace Server.Mobiles { diff --git a/Scripts/Mobiles/Townfolk/Noble.cs b/Scripts/Mobiles/Townfolk/Noble.cs index 95a7d8510..63d91038e 100644 --- a/Scripts/Mobiles/Townfolk/Noble.cs +++ b/Scripts/Mobiles/Townfolk/Noble.cs @@ -1,5 +1,4 @@ using Server.Items; -using EDI = Server.Mobiles.EscortDestinationInfo; namespace Server.Mobiles { diff --git a/Scripts/Mobiles/Townfolk/Peasant.cs b/Scripts/Mobiles/Townfolk/Peasant.cs index 6ab91394e..02aa17a87 100644 --- a/Scripts/Mobiles/Townfolk/Peasant.cs +++ b/Scripts/Mobiles/Townfolk/Peasant.cs @@ -1,5 +1,4 @@ using Server.Items; -using EDI = Server.Mobiles.EscortDestinationInfo; namespace Server.Mobiles { diff --git a/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs b/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs index 3d766024b..31dc9214f 100644 --- a/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs +++ b/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs @@ -1,5 +1,4 @@ using Server.Items; -using EDI = Server.Mobiles.EscortDestinationInfo; namespace Server.Mobiles { diff --git a/Scripts/Multis/HouseFoundation.cs b/Scripts/Multis/HouseFoundation.cs index 1fc86d488..186b9faed 100644 --- a/Scripts/Multis/HouseFoundation.cs +++ b/Scripts/Multis/HouseFoundation.cs @@ -1,8 +1,11 @@ using System; +using System.Buffers; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Threading; +using System.Threading.Tasks; using Server.Gumps; using Server.Items; using Server.Mobiles; @@ -2197,14 +2200,8 @@ namespace Server.Multis { public const int MaxItemsPerStairBuffer = 750; - private static BufferPool m_PlaneBufferPool = new BufferPool("Housing Plane Buffers", 9, 0x400); - private static BufferPool m_StairBufferPool = new BufferPool("Housing Stair Buffers", 6, MaxItemsPerStairBuffer * 5); - private static BufferPool m_DeflatedBufferPool = new BufferPool("Housing Deflated Buffers", 1, 0x2000); - - private static Queue m_SendQueue; - private static object m_SendQueueSyncRoot; + private static ConcurrentQueue m_SendQueue; private static AutoResetEvent m_Sync; - private static Thread m_Thread; private byte[][] m_PlaneBuffers; @@ -2214,13 +2211,10 @@ namespace Server.Multis static DesignStateDetailed() { - m_SendQueue = new Queue(); - m_SendQueueSyncRoot = ((ICollection)m_SendQueue).SyncRoot; + m_SendQueue = new ConcurrentQueue(); m_Sync = new AutoResetEvent(false); - m_Thread = new Thread(CompressionThread); - m_Thread.Name = "Housing Compression Thread"; - m_Thread.Start(); + Task.Run(ProcessCompression); } public DesignStateDetailed(uint serial, int revision, int xMin, int yMin, int xMax, int yMax, MultiTileEntry[] tiles) @@ -2243,19 +2237,13 @@ namespace Server.Multis m_PlaneBuffers = new byte[9][]; - lock (m_PlaneBufferPool) - { - for (int i = 0; i < m_PlaneBuffers.Length; ++i) - m_PlaneBuffers[i] = m_PlaneBufferPool.AcquireBuffer(); - } + for (int i = 0; i < m_PlaneBuffers.Length; ++i) + m_PlaneBuffers[i] = ArrayPool.Shared.Rent(0x400); m_StairBuffers = new byte[6][]; - lock (m_StairBufferPool) - { - for (int i = 0; i < m_StairBuffers.Length; ++i) - m_StairBuffers[i] = m_StairBufferPool.AcquireBuffer(); - } + for (int i = 0; i < m_StairBuffers.Length; ++i) + m_StairBuffers[i] = ArrayPool.Shared.Rent(MaxItemsPerStairBuffer * 5); Clear(m_PlaneBuffers[0], width * height * 2); @@ -2357,17 +2345,13 @@ namespace Server.Multis int planeCount = 0; - byte[] m_DeflatedBuffer; - lock (m_DeflatedBufferPool) - { - m_DeflatedBuffer = m_DeflatedBufferPool.AcquireBuffer(); - } + byte[] m_DeflatedBuffer = ArrayPool.Shared.Rent(0x2000); for (int i = 0; i < m_PlaneBuffers.Length; ++i) { if (!m_PlaneUsed[i]) { - m_PlaneBufferPool.ReleaseBuffer(m_PlaneBuffers[i]); + ArrayPool.Shared.Return(m_PlaneBuffers[i]); continue; } @@ -2402,10 +2386,7 @@ namespace Server.Multis Write(m_DeflatedBuffer, 0, deflatedLength); totalLength += 4 + deflatedLength; - lock (m_PlaneBufferPool) - { - m_PlaneBufferPool.ReleaseBuffer(inflatedBuffer); - } + ArrayPool.Shared.Return(inflatedBuffer); } int totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer; @@ -2443,16 +2424,10 @@ namespace Server.Multis totalLength += 4 + deflatedLength; } - lock (m_StairBufferPool) - { - for (int i = 0; i < m_StairBuffers.Length; ++i) - m_StairBufferPool.ReleaseBuffer(m_StairBuffers[i]); - } + for (int i = 0; i < m_StairBuffers.Length; ++i) + ArrayPool.Shared.Return(m_StairBuffers[i]); - lock (m_DeflatedBufferPool) - { - m_DeflatedBufferPool.ReleaseBuffer(m_DeflatedBuffer); - } + ArrayPool.Shared.Return(m_DeflatedBuffer); m_Stream.Seek(15, SeekOrigin.Begin); @@ -2504,28 +2479,16 @@ namespace Server.Multis buffer[i] = 0; } - public static void CompressionThread() + public static void ProcessCompression() { while (!Core.Closing) { m_Sync.WaitOne(); - int count; + int count = m_SendQueue.Count; - lock (m_SendQueueSyncRoot) + while (count > 0 && m_SendQueue.TryDequeue(out SendQueueEntry sqe)) { - count = m_SendQueue.Count; - } - - while (count > 0) - { - SendQueueEntry sqe; - - lock (m_SendQueueSyncRoot) - { - sqe = m_SendQueue.Dequeue(); - } - try { Packet p; @@ -2568,23 +2531,15 @@ namespace Server.Multis } finally { - lock (m_SendQueueSyncRoot) - { - count = m_SendQueue.Count; - } + count = m_SendQueue.Count; } - - //sqe.m_NetState.Send( new DesignStateDetailed( sqe.m_Serial, sqe.m_Revision, sqe.m_xMin, sqe.m_yMin, sqe.m_xMax, sqe.m_yMax, sqe.m_Tiles ) ); } } } public static void SendDetails(NetState ns, HouseFoundation house, DesignState state) { - lock (m_SendQueueSyncRoot) - { - m_SendQueue.Enqueue(new SendQueueEntry(ns, house, state)); - } + m_SendQueue.Enqueue(new SendQueueEntry(ns, house, state)); m_Sync.Set(); } diff --git a/Scripts/Properties/AssemblyInfo.cs b/Scripts/Properties/AssemblyInfo.cs deleted file mode 100644 index 3a630d815..000000000 --- a/Scripts/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("RunUO Scripts Assembly")] -[assembly: AssemblyDescription("RunUO Scripts Assembly")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("RunUO")] -[assembly: AssemblyProduct("RunUO")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("07fe114c-a456-42f8-82fd-251c9b78cd49")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.0.0.1")] -[assembly: AssemblyFileVersion("0.0.0.1")] \ No newline at end of file diff --git a/Scripts/Properties/PublishProfiles/Linux.pubxml b/Scripts/Properties/PublishProfiles/Linux.pubxml new file mode 100644 index 000000000..a0558d267 --- /dev/null +++ b/Scripts/Properties/PublishProfiles/Linux.pubxml @@ -0,0 +1,13 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.0 + ../Assemblies + + diff --git a/Scripts/Properties/PublishProfiles/OSX.pubxml b/Scripts/Properties/PublishProfiles/OSX.pubxml new file mode 100644 index 000000000..a0558d267 --- /dev/null +++ b/Scripts/Properties/PublishProfiles/OSX.pubxml @@ -0,0 +1,13 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.0 + ../Assemblies + + diff --git a/Scripts/Properties/PublishProfiles/Windows.pubxml b/Scripts/Properties/PublishProfiles/Windows.pubxml new file mode 100644 index 000000000..a0558d267 --- /dev/null +++ b/Scripts/Properties/PublishProfiles/Windows.pubxml @@ -0,0 +1,13 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.0 + ../Assemblies + + diff --git a/Scripts/Scripts.csproj b/Scripts/Scripts.csproj index b68d69801..ed53cd761 100644 --- a/Scripts/Scripts.csproj +++ b/Scripts/Scripts.csproj @@ -1,3325 +1,39 @@  - - - Debug - AnyCPU - {DAE872E6-6899-427C-A75D-AD52526EBCDA} - Library - false - Scripts.CS - v4.7 - 512 - - - - - true - full - false - Output\ - TRACE;DEBUG;NEWTIMERS;NEWPARENT - prompt - 4 - false - false - - - pdbonly - true - Output\ - TRACE;NEWTIMERS;NEWPARENT - prompt - 4 - false - false - + Server + netcoreapp3.0 - - true - Output\ - TRACE;DEBUG;NEWTIMERS;NEWPARENT - full - x64 - prompt - MinimumRecommendedRules.ruleset - false - false + + NETCORE;NETSTANDARD + Scripts.CS - - Output\ - TRACE;NEWTIMERS;NEWPARENT + + true true - pdbonly + ..\Assemblies\ + ..\Assemblies\ + + true + x64 + + + TRACE;DEBUG + true + false + ..\Assemblies\ + ..\Assemblies\ + + true x64 - prompt - MinimumRecommendedRules.ruleset - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {0b33ceeb-88e1-49a6-8d7d-af6a5a357087} - Server + false + false - - - - \ No newline at end of file diff --git a/Server/AssemblyInfo.cs b/Server/AssemblyInfo.cs deleted file mode 100644 index d28a05c87..000000000 --- a/Server/AssemblyInfo.cs +++ /dev/null @@ -1,80 +0,0 @@ -/*************************************************************************** - * AssemblyInfo.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System.Reflection; -using System.Runtime.InteropServices; - -// -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -// -[assembly: AssemblyTitle("RunUO Server Core")] //Having just RunUO there is reundant, ie, RunUO.exe with the word 'RunUO' under it -[assembly: AssemblyDescription("UO Server Software")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("RunUO")] -[assembly: AssemblyProduct("RunUO")] -[assembly: AssemblyCopyright("Copyright � 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly: AssemblyVersion("2.7.0.*")] - -// -// In order to sign your assembly you must specify a key to use. Refer to the -// Microsoft .NET Framework documentation for more information on assembly signing. -// -// Use the attributes below to control which key is used for signing. -// -// Notes: -// (*) If no key is specified, the assembly is not signed. -// (*) KeyName refers to a key that has been installed in the Crypto Service -// Provider (CSP) on your machine. KeyFile refers to a file which contains -// a key. -// (*) If the KeyFile and the KeyName values are both specified, the -// following processing occurs: -// (1) If the KeyName can be found in the CSP, that key is used. -// (2) If the KeyName does not exist and the KeyFile does exist, the key -// in the KeyFile is installed into the CSP and used. -// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. -// When specifying the KeyFile, the location of the KeyFile should be -// relative to the project output directory which is -// %Project Directory%\obj\. For example, if your KeyFile is -// located in the project directory, you would specify the AssemblyKeyFile -// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] -// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework -// documentation for more information on this. -// -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] - -[assembly: ComVisible(false)] \ No newline at end of file diff --git a/Server/Diagnostics/PacketProfile.cs b/Server/Diagnostics/PacketProfile.cs index e85c7d89d..54f349dcf 100644 --- a/Server/Diagnostics/PacketProfile.cs +++ b/Server/Diagnostics/PacketProfile.cs @@ -28,8 +28,7 @@ namespace Server.Diagnostics { public abstract class BasePacketProfile : BaseProfile { - protected BasePacketProfile(string name) - : base(name) + protected BasePacketProfile(string name) : base(name) { } @@ -37,7 +36,7 @@ namespace Server.Diagnostics public double AverageLength => (double)TotalLength / Math.Max(1, Count); - public void Finish(int length) + public void Finish(long length) { Finish(); diff --git a/Server/EventLog.cs b/Server/EventLog.cs deleted file mode 100644 index 86599716b..000000000 --- a/Server/EventLog.cs +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * EventLog.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System.Diagnostics; -using DiagELog = System.Diagnostics.EventLog; - -namespace Server -{ - public static class EventLog - { - static EventLog() - { - if (!DiagELog.SourceExists("RunUO")) DiagELog.CreateEventSource("RunUO", "Application"); - } - - public static void Error(int eventID, string text) - { - DiagELog.WriteEntry("RunUO", text, EventLogEntryType.Error, eventID); - } - - public static void Error(int eventID, string format, params object[] args) - { - Error(eventID, string.Format(format, args)); - } - - public static void Warning(int eventID, string text) - { - DiagELog.WriteEntry("RunUO", text, EventLogEntryType.Warning, eventID); - } - - public static void Warning(int eventID, string format, params object[] args) - { - Warning(eventID, string.Format(format, args)); - } - - public static void Inform(int eventID, string text) - { - DiagELog.WriteEntry("RunUO", text, EventLogEntryType.Information, eventID); - } - - public static void Inform(int eventID, string format, params object[] args) - { - Inform(eventID, string.Format(format, args)); - } - } -} \ No newline at end of file diff --git a/Server/EventSink.cs b/Server/EventSink.cs index ba31ba159..d447e4228 100644 --- a/Server/EventSink.cs +++ b/Server/EventSink.cs @@ -608,10 +608,10 @@ namespace Server public void AddServer(string name, IPEndPoint address) { - AddServer(name, 0, TimeZone.CurrentTimeZone, address); + AddServer(name, 0, TimeZoneInfo.Local, address); } - public void AddServer(string name, int fullPercent, TimeZone tz, IPEndPoint address) + public void AddServer(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address) { Servers.Add(new ServerInfo(name, fullPercent, tz, address)); } @@ -1129,4 +1129,4 @@ namespace Server QuestGumpRequest = null; } } -} \ No newline at end of file +} diff --git a/Server/Main.cs b/Server/Main.cs index e5bf0daaa..798c523a4 100644 --- a/Server/Main.cs +++ b/Server/Main.cs @@ -112,12 +112,10 @@ namespace Server public static bool Service{ get; private set; } - public static bool Debug{ get; private set; } + public static bool Debug { get; private set; } internal static bool HaltOnWarning{ get; private set; } - internal static bool VBdotNet{ get; private set; } - public static List DataDirectories{ get; } = new List(); public static Assembly Assembly{ get; set; } @@ -199,9 +197,6 @@ namespace Server if (HaltOnWarning) Utility.Separate(sb, "-haltonwarning", " "); - if (VBdotNet) - Utility.Separate(sb, "-vb", " "); - if (_UseHRT) Utility.Separate(sb, "-usehrt", " "); @@ -270,7 +265,8 @@ namespace Server { try { - foreach (Listener l in MessagePump.Listeners) l.Dispose(); + foreach (Listener l in MessagePump.Listeners) + l.Dispose(); } catch { @@ -322,7 +318,7 @@ namespace Server Closing = true; - Console.Write("Exiting..."); + Console.WriteLine("Exiting..."); World.WaitForWriteCompletion(); @@ -355,8 +351,6 @@ namespace Server m_Cache = false; else if (Insensitive.Equals(a, "-haltonwarning")) HaltOnWarning = true; - else if (Insensitive.Equals(a, "-vb")) - VBdotNet = true; else if (Insensitive.Equals(a, "-usehrt")) _UseHRT = true; @@ -398,10 +392,14 @@ namespace Server Version ver = Assembly.GetName().Version; // Added to help future code support on forums, as a 'check' people can ask for to it see if they recompiled core or not - Console.WriteLine("RunUO - [https://github.com/runuo/] Version {0}.{1}.{2}.{3}", ver.Major, ver.Minor, ver.Build, + Console.WriteLine("ModernUO - [https://github.com/kamronbatman/ModernUO] Version {0}.{1}.{2}.{3}", ver.Major, ver.Minor, ver.Build, ver.Revision); +#if NETCORE + Console.WriteLine("Core: Running on {0}", RuntimeInformation.FrameworkDescription); +#else Console.WriteLine("Core: Running on .NET Framework Version {0}.{1}.{2}", Environment.Version.Major, Environment.Version.Minor, Environment.Version.Build); +#endif string s = Arguments; @@ -440,18 +438,8 @@ namespace Server Console.WriteLine("RandomImpl: {0} ({1})", RandomImpl.Type.Name, RandomImpl.IsHardwareRNG ? "Hardware" : "Software"); - while (!ScriptCompiler.Compile(Debug, m_Cache)) - { - Console.WriteLine("Scripts: One or more scripts failed to compile or no script files were found."); - - if (Service) - return; - - Console.WriteLine(" - Press return to exit, or R to try again."); - - if (Console.ReadKey(true).Key != ConsoleKey.R) - return; - } + // Load Assembly Scripts.CS.dll + ScriptCompiler.LoadScripts(); ScriptCompiler.Invoke("Configure"); @@ -460,7 +448,10 @@ namespace Server ScriptCompiler.Invoke("Initialize"); - MessagePump messagePump = MessagePump = new MessagePump(); + // Start accepting new connections + MessagePump = new MessagePump(); + + ScriptCompiler.Invoke("RegisterListeners"); timerThread.Start(); @@ -488,16 +479,15 @@ namespace Server Task.Run(() => Mobile.ProcessDeltaQueue()), Task.Run(() => Item.ProcessDeltaQueue()), Task.Run(() => Timer.Slice()), - Task.Run(() => messagePump.Slice()) + Task.Run(() => MessagePump.DoWork()) ); - - NetState.FlushAll(); NetState.ProcessDisposedQueue(); Slice?.Invoke(); - if (sample++ % sampleInterval != 0) continue; + if (sample++ % sampleInterval != 0) + continue; long now = TickCount; m_CyclesPerSecond[m_CycleIndex++ % m_CyclesPerSecond.Length] = ticksPerSecond / (now - last); @@ -596,7 +586,7 @@ namespace Server internal static extern bool SetConsoleCtrlHandler(ConsoleEventHandler callback, bool add); } - #region Expansions +#region Expansions public static Expansion Expansion{ get; set; } @@ -620,7 +610,7 @@ namespace Server public static bool TOL => Expansion >= Expansion.TOL; - #endregion +#endregion } public class FileLogger : TextWriter diff --git a/Server/Mobile.cs b/Server/Mobile.cs index 87aae8bc3..4b06f948b 100644 --- a/Server/Mobile.cs +++ b/Server/Mobile.cs @@ -1448,13 +1448,7 @@ namespace Server [CommandProperty(AccessLevel.GameMaster, AccessLevel.Owner)] public NetState NetState { - get - { - if (m_NetState != null && m_NetState.Socket == null && !m_NetState.IsDisposing) - NetState = null; - - return m_NetState; - } + get => m_NetState?.Socket != null && !m_NetState.IsDisposing ? m_NetState : null; set { if (m_NetState != value) diff --git a/Server/Network/BufferPool.cs b/Server/Network/BufferPool.cs deleted file mode 100644 index 84157ddcf..000000000 --- a/Server/Network/BufferPool.cs +++ /dev/null @@ -1,106 +0,0 @@ -/*************************************************************************** - * BufferPool.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System.Collections.Generic; - -namespace Server.Network -{ - public class BufferPool - { - private int m_BufferSize; - - private Queue m_FreeBuffers; - - private int m_InitialCapacity; - - private int m_Misses; - - private string m_Name; - - public BufferPool(string name, int initialCapacity, int bufferSize) - { - m_Name = name; - - m_InitialCapacity = initialCapacity; - m_BufferSize = bufferSize; - - m_FreeBuffers = new Queue(initialCapacity); - - for (int i = 0; i < initialCapacity; ++i) - m_FreeBuffers.Enqueue(new byte[bufferSize]); - - lock (Pools) - { - Pools.Add(this); - } - } - - public static List Pools{ get; set; } = new List(); - - public void GetInfo(out string name, out int freeCount, out int initialCapacity, out int currentCapacity, - out int bufferSize, out int misses) - { - lock (this) - { - name = m_Name; - freeCount = m_FreeBuffers.Count; - initialCapacity = m_InitialCapacity; - currentCapacity = m_InitialCapacity * (1 + m_Misses); - bufferSize = m_BufferSize; - misses = m_Misses; - } - } - - public byte[] AcquireBuffer() - { - lock (this) - { - if (m_FreeBuffers.Count > 0) - return m_FreeBuffers.Dequeue(); - - ++m_Misses; - - for (int i = 0; i < m_InitialCapacity; ++i) - m_FreeBuffers.Enqueue(new byte[m_BufferSize]); - - return m_FreeBuffers.Dequeue(); - } - } - - public void ReleaseBuffer(byte[] buffer) - { - if (buffer == null) - return; - - lock (this) - { - m_FreeBuffers.Enqueue(buffer); - } - } - - public void Free() - { - lock (Pools) - { - Pools.Remove(this); - } - } - } -} \ No newline at end of file diff --git a/Server/Network/ByteQueue.cs b/Server/Network/ByteQueue.cs deleted file mode 100644 index b5dae23fb..000000000 --- a/Server/Network/ByteQueue.cs +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************** - * ByteQueue.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System; - -namespace Server.Network -{ - public class ByteQueue - { - private byte[] m_Buffer; - private int m_Head; - private int m_Tail; - - public ByteQueue() - { - m_Buffer = new byte[2048]; - } - - public int Length{ get; private set; } - - public void Clear() - { - m_Head = 0; - m_Tail = 0; - Length = 0; - } - - private void SetCapacity(int capacity) - { - byte[] newBuffer = new byte[capacity]; - - if (Length > 0) - { - if (m_Head < m_Tail) - { - Buffer.BlockCopy(m_Buffer, m_Head, newBuffer, 0, Length); - } - else - { - Buffer.BlockCopy(m_Buffer, m_Head, newBuffer, 0, m_Buffer.Length - m_Head); - Buffer.BlockCopy(m_Buffer, 0, newBuffer, m_Buffer.Length - m_Head, m_Tail); - } - } - - m_Head = 0; - m_Tail = Length; - m_Buffer = newBuffer; - } - - public byte GetPacketID() - { - if (Length >= 1) - return m_Buffer[m_Head]; - - return 0xFF; - } - - public int GetPacketLength() - { - if (Length >= 3) - return (m_Buffer[(m_Head + 1) % m_Buffer.Length] << 8) | m_Buffer[(m_Head + 2) % m_Buffer.Length]; - - return 0; - } - - public int Dequeue(byte[] buffer, int offset, int size) - { - if (size > Length) - size = Length; - - if (size == 0) - return 0; - - if (m_Head < m_Tail) - { - Buffer.BlockCopy(m_Buffer, m_Head, buffer, offset, size); - } - else - { - int rightLength = m_Buffer.Length - m_Head; - - if (rightLength >= size) - { - Buffer.BlockCopy(m_Buffer, m_Head, buffer, offset, size); - } - else - { - Buffer.BlockCopy(m_Buffer, m_Head, buffer, offset, rightLength); - Buffer.BlockCopy(m_Buffer, 0, buffer, offset + rightLength, size - rightLength); - } - } - - m_Head = (m_Head + size) % m_Buffer.Length; - Length -= size; - - if (Length == 0) - { - m_Head = 0; - m_Tail = 0; - } - - return size; - } - - public void Enqueue(byte[] buffer, int offset, int size) - { - if (Length + size > m_Buffer.Length) - SetCapacity((Length + size + 2047) & ~2047); - - if (m_Head < m_Tail) - { - int rightLength = m_Buffer.Length - m_Tail; - - if (rightLength >= size) - { - Buffer.BlockCopy(buffer, offset, m_Buffer, m_Tail, size); - } - else - { - Buffer.BlockCopy(buffer, offset, m_Buffer, m_Tail, rightLength); - Buffer.BlockCopy(buffer, offset + rightLength, m_Buffer, 0, size - rightLength); - } - } - else - { - Buffer.BlockCopy(buffer, offset, m_Buffer, m_Tail, size); - } - - m_Tail = (m_Tail + size) % m_Buffer.Length; - Length += size; - } - } -} \ No newline at end of file diff --git a/Server/Network/EncodedPacketHandler.cs b/Server/Network/EncodedPacketHandler.cs index 533cc7643..c400b5bbe 100644 --- a/Server/Network/EncodedPacketHandler.cs +++ b/Server/Network/EncodedPacketHandler.cs @@ -37,4 +37,4 @@ namespace Server.Network public bool Ingame{ get; } } -} \ No newline at end of file +} diff --git a/Server/Network/EncodedReader.cs b/Server/Network/EncodedReader.cs index 5caf631e5..cbca5ea66 100644 --- a/Server/Network/EncodedReader.cs +++ b/Server/Network/EncodedReader.cs @@ -20,7 +20,7 @@ namespace Server.Network { - public class EncodedReader + public ref struct EncodedReader { private PacketReader m_Reader; @@ -29,47 +29,20 @@ namespace Server.Network m_Reader = reader; } - public byte[] Buffer => m_Reader.Buffer; - public void Trace(NetState state) { m_Reader.Trace(state); } - public int ReadInt32() - { - if (m_Reader.ReadByte() != 0) - return 0; + public int ReadInt32() => m_Reader.ReadByte() != 0 ? 0 : m_Reader.ReadInt32(); - return m_Reader.ReadInt32(); - } + public Point3D ReadPoint3D() => m_Reader.ReadByte() != 3 ? Point3D.Zero : + new Point3D(m_Reader.ReadInt16(), m_Reader.ReadInt16(), m_Reader.ReadByte()); - public Point3D ReadPoint3D() - { - if (m_Reader.ReadByte() != 3) - return Point3D.Zero; + public string ReadUnicodeStringSafe() => m_Reader.ReadByte() != 2 ? string.Empty : + m_Reader.ReadUnicodeStringSafe(m_Reader.ReadUInt16()); - return new Point3D(m_Reader.ReadInt16(), m_Reader.ReadInt16(), m_Reader.ReadByte()); - } - - public string ReadUnicodeStringSafe() - { - if (m_Reader.ReadByte() != 2) - return ""; - - int length = m_Reader.ReadUInt16(); - - return m_Reader.ReadUnicodeStringSafe(length); - } - - public string ReadUnicodeString() - { - if (m_Reader.ReadByte() != 2) - return ""; - - int length = m_Reader.ReadUInt16(); - - return m_Reader.ReadUnicodeString(length); - } + public string ReadUnicodeString() => m_Reader.ReadByte() != 2 ? string.Empty : + m_Reader.ReadUnicodeString(m_Reader.ReadUInt16()); } -} \ No newline at end of file +} diff --git a/Server/Network/Listener.cs b/Server/Network/Listener.cs index 13a9afef9..93077fca2 100644 --- a/Server/Network/Listener.cs +++ b/Server/Network/Listener.cs @@ -19,58 +19,35 @@ ***************************************************************************/ using System; -using System.Collections; -using System.Collections.Generic; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading; +using System.Threading.Tasks; namespace Server.Network { - public class Listener : IDisposable + public class Listener { - private Socket m_Listener; - - private Queue m_Accepted; - private object m_AcceptedSyncRoot; - - private SocketAsyncEventArgs m_EventArgs; - - private static Socket[] m_EmptySockets = new Socket[0]; - - public static IPEndPoint[] EndPoints{ get; set; } - + private Socket m_Socket; + private IPEndPoint m_EndPoint; public Listener(IPEndPoint ipep) { - m_Accepted = new Queue(); - m_AcceptedSyncRoot = ((ICollection)m_Accepted).SyncRoot; +#pragma warning disable IDE0068 // Use recommended dispose pattern + m_Socket = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); +#pragma warning restore IDE0068 // Use recommended dispose pattern - m_Listener = Bind(ipep); - - if (m_Listener == null) - return; - - DisplayListener(); - - m_EventArgs = new SocketAsyncEventArgs(); - m_EventArgs.Completed += Accept_Completion; - Accept_Start(); + m_Socket.LingerState.Enabled = false; + m_Socket.ExclusiveAddressUse = false; + m_EndPoint = ipep; } - private Socket Bind(IPEndPoint ipep) + public virtual async Task Start(MessagePump pump) { - Socket s = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - try { - s.LingerState.Enabled = false; - s.ExclusiveAddressUse = false; - - s.Bind(ipep); - s.Listen(8); - - return s; + m_Socket.Bind(m_EndPoint); + m_Socket.Listen(8); } catch (Exception e) { @@ -79,12 +56,12 @@ namespace Server.Network if (se.ErrorCode == 10048) { // WSAEADDRINUSE - Console.WriteLine("Listener Failed: {0}:{1} (In Use)", ipep.Address, ipep.Port); + Console.WriteLine("Listener Failed: {0}:{1} (In Use)", m_EndPoint.Address, m_EndPoint.Port); } else if (se.ErrorCode == 10049) { // WSAEADDRNOTAVAIL - Console.WriteLine("Listener Failed: {0}:{1} (Unavailable)", ipep.Address, ipep.Port); + Console.WriteLine("Listener Failed: {0}:{1} (Unavailable)", m_EndPoint.Address, m_EndPoint.Port); } else { @@ -93,13 +70,35 @@ namespace Server.Network } } - return null; + m_Socket = null; + return; + } + + DisplayListener(); + + while (true) + { + Socket s; + try + { + s = await m_Socket.AcceptAsync().ConfigureAwait(false); + } + catch (SocketException ex) + { + NetState.TraceException(ex); + continue; + } + + if (VerifySocket(s)) + _ = new NetState(s, pump); + else + Release(s); } } private void DisplayListener() { - if (!(m_Listener.LocalEndPoint is IPEndPoint ipep)) + if (!(m_Socket.LocalEndPoint is IPEndPoint ipep)) return; if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any)) @@ -112,17 +111,6 @@ namespace Server.Network if (ipep.AddressFamily == unicast.Address.AddressFamily) Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port); } - - /* - try { - Console.WriteLine( "Listening: {0}:{1}", IPAddress.Loopback, ipep.Port ); - IPHostEntry iphe = Dns.GetHostEntry( Dns.GetHostName() ); - IPAddress[] ip = iphe.AddressList; - for ( int i = 0; i < ip.Length; ++i ) - Console.WriteLine( "Listening: {0}:{1}", ip[i], ipep.Port ); - } - catch { } - */ } else { @@ -130,49 +118,6 @@ namespace Server.Network } } - private void Accept_Start() - { - bool result; - - do - { - try - { - result = !m_Listener.AcceptAsync(m_EventArgs); - } - catch (SocketException ex) - { - NetState.TraceException(ex); - break; - } - catch (ObjectDisposedException) - { - break; - } - - if (result) - Accept_Process(m_EventArgs); - } while (result); - } - - private void Accept_Completion(object sender, SocketAsyncEventArgs e) - { - Accept_Process(e); - - Accept_Start(); - } - - private void Accept_Process(SocketAsyncEventArgs e) - { - if (e.SocketError == SocketError.Success && VerifySocket(e.AcceptSocket)) - Enqueue(e.AcceptSocket); - else - Release(e.AcceptSocket); - - e.AcceptSocket = null; - } - - private bool VerifySocket(Socket socket) { try @@ -191,16 +136,6 @@ namespace Server.Network } } - private void Enqueue(Socket socket) - { - lock (m_AcceptedSyncRoot) - { - m_Accepted.Enqueue(socket); - } - - Core.Set(); - } - private void Release(Socket socket) { try @@ -220,37 +155,20 @@ namespace Server.Network { NetState.TraceException(ex); } - } - public Socket[] Slice() - { - Socket[] array; - - lock (m_AcceptedSyncRoot) + try { - if (m_Accepted.Count == 0) - return m_EmptySockets; - - array = m_Accepted.ToArray(); - m_Accepted.Clear(); + socket.Dispose(); } - - return array; - } - - public void Dispose(bool disposing) - { - if (disposing) + catch (SocketException ex) { - Socket socket = Interlocked.Exchange(ref m_Listener, null); - - socket?.Close(); + NetState.TraceException(ex); } } public void Dispose() { - Dispose(true); + Interlocked.Exchange(ref m_Socket, null)?.Close(); GC.SuppressFinalize(this); } } diff --git a/Server/Network/MessagePump.cs b/Server/Network/MessagePump.cs index e1d324f81..f9c735fdf 100644 --- a/Server/Network/MessagePump.cs +++ b/Server/Network/MessagePump.cs @@ -1,3 +1,4 @@ + /*************************************************************************** * MessagePump.cs * ------------------- @@ -19,271 +20,57 @@ ***************************************************************************/ using System; +using System.Buffers; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Net; -using System.Net.Sockets; -using System.Threading; -using Server.Diagnostics; namespace Server.Network { public class MessagePump { - private const int BufferSize = 4096; - private BufferPool m_Buffers = new BufferPool("Processor", 4, BufferSize); - private Queue m_Queue; - private Queue m_Throttled; - private Queue m_WorkingQueue; + private ConcurrentQueue m_WorkQueue = new ConcurrentQueue(); + public Listener[] Listeners => new Listener[0]; - public MessagePump() + public void AddListener(IPEndPoint ipep) { - IPEndPoint[] ipep = Listener.EndPoints; - - Listeners = new Listener[ipep.Length]; - - bool success = false; - - do - { - for (int i = 0; i < ipep.Length; i++) - { - Listener l = new Listener(ipep[i]); - if (!success) - success = true; - Listeners[i] = l; - } - - if (!success) - { - Console.WriteLine("Retrying..."); - Thread.Sleep(10000); - } - } while (!success); - - m_Queue = new Queue(); - m_WorkingQueue = new Queue(); - m_Throttled = new Queue(); + Listener[] listeners = new Listener[Listeners.Length + 1]; + Array.Copy(Listeners, listeners, Listeners.Length); + Listener listener = new Listener(ipep); + _ = listener.Start(this); + listeners[Listeners.Length] = listener; } - public Listener[] Listeners{ get; set; } - - public void AddListener(Listener l) + public void QueueWork(NetState ns, in ReadOnlySequence seq, OnPacketReceive onReceive) { - Listener[] old = Listeners; - - Listeners = new Listener[old.Length + 1]; - - for (int i = 0; i < old.Length; ++i) - Listeners[i] = old[i]; - - Listeners[old.Length] = l; - } - - private void CheckListener() - { - for (int j = 0; j < Listeners.Length; ++j) - { - Socket[] accepted = Listeners[j].Slice(); - - for (int i = 0; i < accepted.Length; ++i) - { - NetState ns = new NetState(accepted[i], this); - ns.Start(); - - if (ns.Running) - Console.WriteLine("Client: {0}: Connected. [{1} Online]", ns, NetState.Instances.Count); - } - } - } - - public void OnReceive(NetState ns) - { - lock (this) - { - m_Queue.Enqueue(ns); - } - + m_WorkQueue.Enqueue(new Work(ns, seq, onReceive)); Core.Set(); } - public void Slice() + public void DoWork() { - CheckListener(); - - lock (this) + int count = m_WorkQueue.Count; + while (count-- > 0) { - Queue temp = m_WorkingQueue; - m_WorkingQueue = m_Queue; - m_Queue = temp; - } + if (!m_WorkQueue.TryDequeue(out Work work)) + break; - while (m_WorkingQueue.Count > 0) - { - NetState ns = m_WorkingQueue.Dequeue(); - - if (ns.Running) - HandleReceive(ns); - } - - lock (this) - { - while (m_Throttled.Count > 0) - m_Queue.Enqueue(m_Throttled.Dequeue()); + work.OnReceive(work.State, new PacketReader(work.Sequence)); } } - private bool HandleSeed(NetState ns, ByteQueue buffer) + // TODO: Optimize this with a pool + private class Work { - if (buffer.GetPacketID() == 0xEF) + public NetState State; + public ReadOnlySequence Sequence; + public OnPacketReceive OnReceive; + + public Work(NetState ns, in ReadOnlySequence seq, OnPacketReceive onReceive) { - // new packet in client 6.0.5.0 replaces the traditional seed method with a seed packet - // 0xEF = 239 = multicast IP, so this should never appear in a normal seed. So this is backwards compatible with older clients. - ns.Seeded = true; - return true; - } - - if (buffer.Length >= 4) - { - byte[] m_Peek = new byte[4]; - - buffer.Dequeue(m_Peek, 0, 4); - - int seed = (m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]; - - if (seed == 0) - { - Console.WriteLine("Login: {0}: Invalid client detected, disconnecting", ns); - ns.Dispose(); - return false; - } - - ns.m_Seed = seed; - ns.Seeded = true; - return true; - } - - return false; - } - - private bool CheckEncrypted(NetState ns, int packetID) - { - if (!ns.SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 && - packetID != 0x91 && packetID != 0xA4 && packetID != 0xEF) - { - Console.WriteLine("Client: {0}: Encrypted client detected, disconnecting", ns); - ns.Dispose(); - return true; - } - - return false; - } - - public void HandleReceive(NetState ns) - { - ByteQueue buffer = ns.Buffer; - - if (buffer == null || buffer.Length <= 0) - return; - - lock (buffer) - { - if (!ns.Seeded) - if (!HandleSeed(ns, buffer)) - return; - - int length = buffer.Length; - - while (length > 0 && ns.Running) - { - int packetID = buffer.GetPacketID(); - - if (CheckEncrypted(ns, packetID)) - break; - - PacketHandler handler = ns.GetHandler(packetID); - - if (handler == null) - { - byte[] data = new byte[length]; - length = buffer.Dequeue(data, 0, length); - new PacketReader(data, length, false).Trace(ns); - break; - } - - int packetLength = handler.Length; - - if (packetLength <= 0) - { - if (length >= 3) - { - packetLength = buffer.GetPacketLength(); - - if (packetLength < 3) - { - ns.Dispose(); - break; - } - } - else - { - break; - } - } - - if (length >= packetLength) - { - if (handler.Ingame) - { - if (ns.Mobile == null) - { - Console.WriteLine( - "Client: {0}: Sent ingame packet (0x{1:X2}) before having been attached to a mobile", ns, - packetID); - ns.Dispose(); - break; - } - - if (ns.Mobile.Deleted) - { - ns.Dispose(); - break; - } - } - - ThrottlePacketCallback throttler = handler.ThrottleCallback; - - if (throttler?.Invoke(ns) == false) - { - m_Throttled.Enqueue(ns); - return; - } - - PacketReceiveProfile prof = null; - - if (Core.Profiling) - prof = PacketReceiveProfile.Acquire(packetID); - - prof?.Start(); - - byte[] packetBuffer = BufferSize >= packetLength ? m_Buffers.AcquireBuffer() : new byte[packetLength]; - - packetLength = buffer.Dequeue(packetBuffer, 0, packetLength); - - PacketReader r = new PacketReader(packetBuffer, packetLength, handler.Length != 0); - - handler.OnReceive(ns, r); - length = buffer.Length; - - if (BufferSize >= packetLength) - m_Buffers.ReleaseBuffer(packetBuffer); - - prof?.Finish(packetLength); - } - else - { - break; - } - } + State = ns; + Sequence = seq; + OnReceive = onReceive; } } } diff --git a/Server/Network/NetState.cs b/Server/Network/NetState.cs index 2bfa00c6d..51f4cbf8f 100644 --- a/Server/Network/NetState.cs +++ b/Server/Network/NetState.cs @@ -19,9 +19,11 @@ ***************************************************************************/ using System; +using System.Buffers; +using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; using System.IO; +using System.IO.Pipelines; using System.Net; using System.Net.Sockets; using System.Threading; @@ -37,54 +39,90 @@ namespace Server.Network { public interface IPacketEncoder { - void EncodeOutgoingPacket(NetState to, ref byte[] buffer, ref int length); - void DecodeIncomingPacket(NetState from, ref byte[] buffer, ref int length); + void EncodeOutgoingPacket(NetState to, ref Memory seq); + void DecodeIncomingPacket(NetState from, ref Memory seq); } public delegate void NetStateCreatedCallback(NetState ns); + [Flags] + public enum ProtocolChanges + { + NewSpellbook = 0x00000001, + DamagePacket = 0x00000002, + Unpack = 0x00000004, + BuffIcon = 0x00000008, + NewHaven = 0x00000010, + ContainerGridLines = 0x00000020, + ExtendedSupportedFeatures = 0x00000040, + StygianAbyss = 0x00000080, + HighSeas = 0x00000100, + NewCharacterList = 0x00000200, + NewCharacterCreation = 0x00000400, + ExtendedStatus = 0x00000800, + NewMobileIncoming = 0x00001000, + NewSecureTrading = 0x00002000, + UltimaStore = 0x00004000, + EndlessJourney = 0x00008000, + + Version400a = NewSpellbook, + Version407a = Version400a | DamagePacket, + Version500a = Version407a | Unpack, + Version502b = Version500a | BuffIcon, + Version6000 = Version502b | NewHaven, + Version6017 = Version6000 | ContainerGridLines, + Version60142 = Version6017 | ExtendedSupportedFeatures, + Version7000 = Version60142 | StygianAbyss, + Version7090 = Version7000 | HighSeas, + Version70130 = Version7090 | NewCharacterList, + Version70160 = Version70130 | NewCharacterCreation, + Version70300 = Version70160 | ExtendedStatus, + Version70331 = Version70300 | NewMobileIncoming, + Version704565 = Version70331 | NewSecureTrading, + Version70500 = Version704565 | UltimaStore, + Version70610 = Version70500 | EndlessJourney + } + + public class AsyncState + { + public bool Paused { get; set; } + public AsyncState(bool paused) + { + Paused = paused; + } + } + public class NetState : IComparable { - private byte[] m_RecvBuffer; - private SendQueue m_SendQueue; - - private SocketAsyncEventArgs m_ReceiveEventArgs; - private SocketAsyncEventArgs m_SendEventArgs; - - private MessagePump m_MessagePump; private string m_ToString; private ClientVersion m_Version; + private SendQueue m_SendQueue = new SendQueue(); - public DateTime ConnectedOn{ get; } + public DateTime ConnectedOn { get; } public TimeSpan ConnectedFor => DateTime.UtcNow - ConnectedOn; + public DateTime ThrottledUntil { get; set; } + internal int m_Seed; internal int m_AuthID; - public IPAddress Address{ get; } + public IPAddress Address { get; } - private static bool m_Paused; + private static AsyncState m_PauseState = new AsyncState(true); + private static AsyncState m_ResumeState = new AsyncState(false); - [Flags] - private enum AsyncState - { - Pending = 0x01, - Paused = 0x02 - } + private static AsyncState m_AsyncState = m_ResumeState; - private AsyncState m_AsyncState; - private object m_AsyncLock = new object(); + public IPacketEncoder PacketEncoder { get; set; } - public IPacketEncoder PacketEncoder{ get; set; } + public static NetStateCreatedCallback CreatedCallback { get; set; } - public static NetStateCreatedCallback CreatedCallback{ get; set; } + public bool SentFirstPacket { get; set; } - public bool SentFirstPacket{ get; set; } + public bool BlockAllPackets { get; set; } - public bool BlockAllPackets{ get; set; } - - public ClientFlags Flags{ get; set; } + public ClientFlags Flags { get; set; } public ClientVersion Version { @@ -93,107 +131,78 @@ namespace Server.Network { m_Version = value; + if (value >= m_Version70610) + ProtocolChanges = ProtocolChanges.Version70610; + if (value >= m_Version70500) + ProtocolChanges = ProtocolChanges.Version70500; if (value >= m_Version704565) - _ProtocolChanges = ProtocolChanges.Version704565; + ProtocolChanges = ProtocolChanges.Version704565; else if (value >= m_Version70331) - _ProtocolChanges = ProtocolChanges.Version70331; + ProtocolChanges = ProtocolChanges.Version70331; else if (value >= m_Version70300) - _ProtocolChanges = ProtocolChanges.Version70300; + ProtocolChanges = ProtocolChanges.Version70300; else if (value >= m_Version70160) - _ProtocolChanges = ProtocolChanges.Version70160; + ProtocolChanges = ProtocolChanges.Version70160; else if (value >= m_Version70130) - _ProtocolChanges = ProtocolChanges.Version70130; + ProtocolChanges = ProtocolChanges.Version70130; else if (value >= m_Version7090) - _ProtocolChanges = ProtocolChanges.Version7090; + ProtocolChanges = ProtocolChanges.Version7090; else if (value >= m_Version7000) - _ProtocolChanges = ProtocolChanges.Version7000; + ProtocolChanges = ProtocolChanges.Version7000; else if (value >= m_Version60142) - _ProtocolChanges = ProtocolChanges.Version60142; + ProtocolChanges = ProtocolChanges.Version60142; else if (value >= m_Version6017) - _ProtocolChanges = ProtocolChanges.Version6017; + ProtocolChanges = ProtocolChanges.Version6017; else if (value >= m_Version6000) - _ProtocolChanges = ProtocolChanges.Version6000; + ProtocolChanges = ProtocolChanges.Version6000; else if (value >= m_Version502b) - _ProtocolChanges = ProtocolChanges.Version502b; + ProtocolChanges = ProtocolChanges.Version502b; else if (value >= m_Version500a) - _ProtocolChanges = ProtocolChanges.Version500a; + ProtocolChanges = ProtocolChanges.Version500a; else if (value >= m_Version407a) - _ProtocolChanges = ProtocolChanges.Version407a; - else if (value >= m_Version400a) _ProtocolChanges = ProtocolChanges.Version400a; + ProtocolChanges = ProtocolChanges.Version407a; + else if (value >= m_Version400a) ProtocolChanges = ProtocolChanges.Version400a; } } - private static ClientVersion m_Version400a = new ClientVersion("4.0.0a"); - private static ClientVersion m_Version407a = new ClientVersion("4.0.7a"); - private static ClientVersion m_Version500a = new ClientVersion("5.0.0a"); - private static ClientVersion m_Version502b = new ClientVersion("5.0.2b"); - private static ClientVersion m_Version6000 = new ClientVersion("6.0.0.0"); - private static ClientVersion m_Version6017 = new ClientVersion("6.0.1.7"); - private static ClientVersion m_Version60142 = new ClientVersion("6.0.14.2"); - private static ClientVersion m_Version7000 = new ClientVersion("7.0.0.0"); - private static ClientVersion m_Version7090 = new ClientVersion("7.0.9.0"); - private static ClientVersion m_Version70130 = new ClientVersion("7.0.13.0"); - private static ClientVersion m_Version70160 = new ClientVersion("7.0.16.0"); - private static ClientVersion m_Version70300 = new ClientVersion("7.0.30.0"); - private static ClientVersion m_Version70331 = new ClientVersion("7.0.33.1"); - private static ClientVersion m_Version704565 = new ClientVersion("7.0.45.65"); + private static readonly ClientVersion m_Version400a = new ClientVersion("4.0.0a"); + private static readonly ClientVersion m_Version407a = new ClientVersion("4.0.7a"); + private static readonly ClientVersion m_Version500a = new ClientVersion("5.0.0a"); + private static readonly ClientVersion m_Version502b = new ClientVersion("5.0.2b"); + private static readonly ClientVersion m_Version6000 = new ClientVersion("6.0.0.0"); + private static readonly ClientVersion m_Version6017 = new ClientVersion("6.0.1.7"); + private static readonly ClientVersion m_Version60142 = new ClientVersion("6.0.14.2"); + private static readonly ClientVersion m_Version7000 = new ClientVersion("7.0.0.0"); + private static readonly ClientVersion m_Version7090 = new ClientVersion("7.0.9.0"); + private static readonly ClientVersion m_Version70130 = new ClientVersion("7.0.13.0"); + private static readonly ClientVersion m_Version70160 = new ClientVersion("7.0.16.0"); + private static readonly ClientVersion m_Version70300 = new ClientVersion("7.0.30.0"); + private static readonly ClientVersion m_Version70331 = new ClientVersion("7.0.33.1"); + private static readonly ClientVersion m_Version704565 = new ClientVersion("7.0.45.65"); + private static readonly ClientVersion m_Version70500 = new ClientVersion("7.0.50.0"); + private static readonly ClientVersion m_Version70610 = new ClientVersion("7.0.61.0"); - private ProtocolChanges _ProtocolChanges; - - private enum ProtocolChanges - { - NewSpellbook = 0x00000001, - DamagePacket = 0x00000002, - Unpack = 0x00000004, - BuffIcon = 0x00000008, - NewHaven = 0x00000010, - ContainerGridLines = 0x00000020, - ExtendedSupportedFeatures = 0x00000040, - StygianAbyss = 0x00000080, - HighSeas = 0x00000100, - NewCharacterList = 0x00000200, - NewCharacterCreation = 0x00000400, - ExtendedStatus = 0x00000800, - NewMobileIncoming = 0x00001000, - NewSecureTrading = 0x00002000, - - Version400a = NewSpellbook, - Version407a = Version400a | DamagePacket, - Version500a = Version407a | Unpack, - Version502b = Version500a | BuffIcon, - Version6000 = Version502b | NewHaven, - Version6017 = Version6000 | ContainerGridLines, - Version60142 = Version6017 | ExtendedSupportedFeatures, - Version7000 = Version60142 | StygianAbyss, - Version7090 = Version7000 | HighSeas, - Version70130 = Version7090 | NewCharacterList, - Version70160 = Version70130 | NewCharacterCreation, - Version70300 = Version70160 | ExtendedStatus, - Version70331 = Version70300 | NewMobileIncoming, - Version704565 = Version70331 | NewSecureTrading - } - - public bool NewSpellbook => (_ProtocolChanges & ProtocolChanges.NewSpellbook) != 0; - public bool DamagePacket => (_ProtocolChanges & ProtocolChanges.DamagePacket) != 0; - public bool Unpack => (_ProtocolChanges & ProtocolChanges.Unpack) != 0; - public bool BuffIcon => (_ProtocolChanges & ProtocolChanges.BuffIcon) != 0; - public bool NewHaven => (_ProtocolChanges & ProtocolChanges.NewHaven) != 0; - public bool ContainerGridLines => (_ProtocolChanges & ProtocolChanges.ContainerGridLines) != 0; - public bool ExtendedSupportedFeatures => (_ProtocolChanges & ProtocolChanges.ExtendedSupportedFeatures) != 0; - public bool StygianAbyss => (_ProtocolChanges & ProtocolChanges.StygianAbyss) != 0; - public bool HighSeas => (_ProtocolChanges & ProtocolChanges.HighSeas) != 0; - public bool NewCharacterList => (_ProtocolChanges & ProtocolChanges.NewCharacterList) != 0; - public bool NewCharacterCreation => (_ProtocolChanges & ProtocolChanges.NewCharacterCreation) != 0; - public bool ExtendedStatus => (_ProtocolChanges & ProtocolChanges.ExtendedStatus) != 0; - public bool NewMobileIncoming => (_ProtocolChanges & ProtocolChanges.NewMobileIncoming) != 0; - public bool NewSecureTrading => (_ProtocolChanges & ProtocolChanges.NewSecureTrading) != 0; + public bool NewSpellbook => (ProtocolChanges & ProtocolChanges.NewSpellbook) != 0; + public bool DamagePacket => (ProtocolChanges & ProtocolChanges.DamagePacket) != 0; + public bool Unpack => (ProtocolChanges & ProtocolChanges.Unpack) != 0; + public bool BuffIcon => (ProtocolChanges & ProtocolChanges.BuffIcon) != 0; + public bool NewHaven => (ProtocolChanges & ProtocolChanges.NewHaven) != 0; + public bool ContainerGridLines => (ProtocolChanges & ProtocolChanges.ContainerGridLines) != 0; + public bool ExtendedSupportedFeatures => (ProtocolChanges & ProtocolChanges.ExtendedSupportedFeatures) != 0; + public bool StygianAbyss => (ProtocolChanges & ProtocolChanges.StygianAbyss) != 0; + public bool HighSeas => (ProtocolChanges & ProtocolChanges.HighSeas) != 0; + public bool NewCharacterList => (ProtocolChanges & ProtocolChanges.NewCharacterList) != 0; + public bool NewCharacterCreation => (ProtocolChanges & ProtocolChanges.NewCharacterCreation) != 0; + public bool ExtendedStatus => (ProtocolChanges & ProtocolChanges.ExtendedStatus) != 0; + public bool NewMobileIncoming => (ProtocolChanges & ProtocolChanges.NewMobileIncoming) != 0; + public bool NewSecureTrading => (ProtocolChanges & ProtocolChanges.NewSecureTrading) != 0; public bool IsUOTDClient => - (Flags & ClientFlags.UOTD) != 0 || m_Version != null && m_Version.Type == ClientType.UOTD; + (Flags & ClientFlags.UOTD) != 0 || m_Version?.Type == ClientType.UOTD; - public bool IsSAClient => m_Version != null && m_Version.Type == ClientType.SA; + public bool IsSAClient => m_Version?.Type == ClientType.SA; - public List Trades{ get; } + public List Trades { get; } public void ValidateAllTrades() { @@ -260,21 +269,27 @@ namespace Server.Network return newTrade.From.Container; } - public bool CompressionEnabled{ get; set; } + public bool Running { get; private set; } - public int Sequence{ get; set; } + public bool Seeded { get; set; } - public List Gumps{ get; private set; } + public Socket Socket { get; private set; } - public List HuePickers{ get; private set; } + public bool CompressionEnabled { get; set; } - public List Menus{ get; private set; } + public int Sequence { get; set; } - public static int GumpCap{ get; set; } = 512; + public List Gumps { get; private set; } - public static int HuePickerCap{ get; set; } = 512; + public List HuePickers { get; private set; } - public static int MenuCap{ get; set; } = 512; + public List Menus { get; private set; } + + public static int GumpCap { get; set; } = 512; + + public static int HuePickerCap { get; set; } = 512; + + public static int MenuCap { get; set; } = 512; public void WriteConsole(string text) { @@ -288,12 +303,11 @@ namespace Server.Network public void AddMenu(IMenu menu) { - if (Menus == null) Menus = new List(); + if (Menus == null) + Menus = new List(); if (Menus.Count < MenuCap) - { Menus.Add(menu); - } else { WriteConsole("Exceeded menu cap, disconnecting..."); @@ -318,12 +332,11 @@ namespace Server.Network public void AddHuePicker(HuePicker huePicker) { - if (HuePickers == null) HuePickers = new List(); + if (HuePickers == null) + HuePickers = new List(); if (HuePickers.Count < HuePickerCap) - { HuePickers.Add(huePicker); - } else { WriteConsole("Exceeded hue picker cap, disconnecting..."); @@ -348,12 +361,11 @@ namespace Server.Network public void AddGump(Gump gump) { - if (Gumps == null) Gumps = new List(); + if (Gumps == null) + Gumps = new List(); if (Gumps.Count < GumpCap) - { Gumps.Add(gump); - } else { WriteConsole("Exceeded gump cap, disconnecting..."); @@ -382,38 +394,31 @@ namespace Server.Network Send(new LaunchBrowser(url)); } - public CityInfo[] CityInfo{ get; set; } + public CityInfo[] CityInfo { get; set; } - public Mobile Mobile{ get; set; } + public Mobile Mobile { get; set; } - public ServerInfo[] ServerInfo{ get; set; } + public ServerInfo[] ServerInfo { get; set; } - public IAccount Account{ get; set; } + public IAccount Account { get; set; } public override string ToString() { return m_ToString; } - public static List Instances{ get; } = new List(); + public static List Instances { get; } = new List(); - private static BufferPool m_ReceiveBufferPool = new BufferPool("Receive", 2048, 2048); - - public NetState(Socket socket, MessagePump messagePump) + public NetState(Socket socket, MessagePump pump) { Socket = socket; - Buffer = new ByteQueue(); Seeded = false; Running = false; - m_RecvBuffer = m_ReceiveBufferPool.AcquireBuffer(); - m_MessagePump = messagePump; Gumps = new List(); HuePickers = new List(); Menus = new List(); Trades = new List(); - m_SendQueue = new SendQueue(); - m_NextCheckActivity = Core.TickCount + 30000; Instances.Add(this); @@ -431,12 +436,21 @@ namespace Server.Network } ConnectedOn = DateTime.UtcNow; + _ = Start(pump); CreatedCallback?.Invoke(this); + Console.WriteLine("Client: {0}: Connected. [{1} Online]", this, NetState.Instances.Count); } - private bool _sending; - private object _sendL = new object(); + public static void Pause() + { + m_AsyncState = Interlocked.Exchange(ref m_AsyncState, m_PauseState); + } + + public static void Resume() + { + m_AsyncState = Interlocked.Exchange(ref m_AsyncState, m_ResumeState); + } public virtual void Send(Packet p) { @@ -446,299 +460,147 @@ namespace Server.Network return; } - byte[] buffer = p.Compile(CompressionEnabled, out int length); + m_SendQueue.Enqueue(p); + } - if (buffer == null) + public bool CheckEncrypted(int packetID) + { + if (!SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 && + packetID != 0x91 && packetID != 0xA4 && packetID != 0xEF) { - Console.WriteLine("Client: {0}: null buffer send, disconnecting...", this); - using (StreamWriter op = new StreamWriter("null_send.log", true)) - { - op.WriteLine("{0} Client: {1}: null buffer send, disconnecting...", DateTime.UtcNow, this); - op.WriteLine(new StackTrace()); - } - + Console.WriteLine("Client: {0}: Encrypted client detected, disconnecting", this); Dispose(); - return; - } - - if (buffer.Length <= 0 || length <= 0) - { - p.OnSend(); - return; - } - - PacketSendProfile prof = null; - - if (Core.Profiling) - prof = PacketSendProfile.Acquire(p.GetType()); - - prof?.Start(); - - PacketEncoder?.EncodeOutgoingPacket(this, ref buffer, ref length); - - try - { - lock (_sendL) - { - SendQueue.Gram gram; - lock (m_SendQueue) - { - gram = m_SendQueue.Enqueue(buffer, length); - } - - if (gram != null && !_sending) - { - _sending = true; - m_SendEventArgs.SetBuffer(gram.Buffer, 0, gram.Length); - Send_Start(); - } - } - } - catch (CapacityExceededException) - { - Console.WriteLine("Client: {0}: Too much data pending, disconnecting...", this); - Dispose(false); - } - - p.OnSend(); - - prof?.Finish(length); - } - - public void Start() - { - m_ReceiveEventArgs = new SocketAsyncEventArgs(); - m_ReceiveEventArgs.Completed += Receive_Completion; - m_ReceiveEventArgs.SetBuffer(m_RecvBuffer, 0, m_RecvBuffer.Length); - - m_SendEventArgs = new SocketAsyncEventArgs(); - m_SendEventArgs.Completed += Send_Completion; - - Running = true; - - if (Socket == null || m_Paused) return; - - Receive_Start(); - } - - private void Receive_Start() - { - try - { - bool result = false; - - do - { - lock (m_AsyncLock) - { - if ((m_AsyncState & (AsyncState.Pending | AsyncState.Paused)) == 0) - { - m_AsyncState |= AsyncState.Pending; - result = !Socket.ReceiveAsync(m_ReceiveEventArgs); - - if (result) - Receive_Process(m_ReceiveEventArgs); - } - } - } while (result); - } - catch (Exception ex) - { - TraceException(ex); - Dispose(false); - } - } - - private void Receive_Completion(object sender, SocketAsyncEventArgs e) - { - Receive_Process(e); - - if (!IsDisposing) - Receive_Start(); - } - - private void Receive_Process(SocketAsyncEventArgs e) - { - int byteCount = e.BytesTransferred; - - if (e.SocketError != SocketError.Success || byteCount <= 0) - { - Dispose(false); - return; - } - - if (IsDisposing) - return; - - m_NextCheckActivity = Core.TickCount + 90000; - - byte[] buffer = m_RecvBuffer; - - PacketEncoder?.DecodeIncomingPacket(this, ref buffer, ref byteCount); - - lock (Buffer) - { - Buffer.Enqueue(buffer, 0, byteCount); - } - - m_MessagePump.OnReceive(this); - - lock (m_AsyncLock) - { - m_AsyncState &= ~AsyncState.Pending; - } - } - - private void Send_Start() - { - try - { - bool result; - - do - { - result = !Socket.SendAsync(m_SendEventArgs); - - if (result) - Send_Process(m_SendEventArgs); - } while (result); - } - catch (Exception ex) - { - TraceException(ex); - Dispose(false); - } - } - - private void Send_Completion(object sender, SocketAsyncEventArgs e) - { - Send_Process(e); - - if (IsDisposing) - return; - - if (CoalesceSleep >= 0) Thread.Sleep(CoalesceSleep); - - SendQueue.Gram gram; - - lock (m_SendQueue) - { - gram = m_SendQueue.Dequeue(); - - if (gram == null && m_SendQueue.IsFlushReady) - gram = m_SendQueue.CheckFlushReady(); - } - - if (gram != null) - { - m_SendEventArgs.SetBuffer(gram.Buffer, 0, gram.Length); - Send_Start(); - } - else - { - lock (_sendL) - { - _sending = false; - } - } - } - - private void Send_Process(SocketAsyncEventArgs e) - { - int bytes = e.BytesTransferred; - - if (e.SocketError != SocketError.Success || bytes <= 0) - { - Dispose(false); - return; - } - - m_NextCheckActivity = Core.TickCount + 90000; - } - - public static void Pause() - { - m_Paused = true; - - for (int i = 0; i < Instances.Count; ++i) - { - NetState ns = Instances[i]; - - lock (ns.m_AsyncLock) - { - ns.m_AsyncState |= AsyncState.Paused; - } - } - } - - public static void Resume() - { - m_Paused = false; - - for (int i = 0; i < Instances.Count; ++i) - { - NetState ns = Instances[i]; - - if (ns.Socket == null) continue; - - lock (ns.m_AsyncLock) - { - ns.m_AsyncState &= ~AsyncState.Paused; - - if ((ns.m_AsyncState & AsyncState.Pending) == 0) - ns.Receive_Start(); - } - } - } - - public bool Flush() - { - if (Socket == null) - return false; - - lock (_sendL) - { - if (_sending) - return false; - - SendQueue.Gram gram; - - lock (m_SendQueue) - { - if (!m_SendQueue.IsFlushReady) - return false; - - gram = m_SendQueue.CheckFlushReady(); - } - - if (gram != null) - { - _sending = true; - m_SendEventArgs.SetBuffer(gram.Buffer, 0, gram.Length); - Send_Start(); - } + return true; } return false; } + private Pipe m_RecvdPipe; + + private async Task Start(MessagePump pump) + { + m_RecvdPipe = new Pipe(); + Running = true; + + await Task.WhenAll(ProcessSends(), ProcessRecvs(), HandlePackets(pump)).ConfigureAwait(false); + } + + private async Task ProcessRecvs() + { + PipeWriter w = m_RecvdPipe.Writer; + + while (true) + { + if (m_AsyncState.Paused) + { + await Timer.Pause(50).ConfigureAwait(false); + continue; + } + + try + { + Memory memory = w.GetMemory(); + int bytesRead = await Socket.ReceiveAsync(memory, SocketFlags.None).ConfigureAwait(false); + if (bytesRead == 0) + break; + + Interlocked.Exchange(ref m_NextCheckActivity, Core.TickCount + 90000); + + w.Advance(bytesRead); + + FlushResult result = await w.FlushAsync().ConfigureAwait(false); + if (result.IsCompleted || result.IsCanceled) + break; + } + catch + { + break; + } + } + + w.Complete(); + Dispose(); + } + + private async Task ProcessSends() + { + while (true) + { + try + { + Packet p = await m_SendQueue?.DequeueAsync() ?? null; + if (p == null) + break; + + ReadOnlyMemory buffer = p.Compile(CompressionEnabled, out int length); + + if (buffer.Length <= 0 || length <= 0) + { + p.OnSend(); + return; + } + + buffer = buffer.Slice(0, length); + + PacketSendProfile prof = null; + + if (Core.Profiling) + prof = PacketSendProfile.Acquire(p.GetType()); + + prof?.Start(); + + await Socket.SendAsync(buffer, SocketFlags.None).ConfigureAwait(false); + + p.OnSend(); + + prof?.Finish(length); + } + catch (SocketException ex) + { + Console.WriteLine(ex); + TraceException(ex); + Dispose(); + break; + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + } + + private async Task HandlePackets(MessagePump pump) + { + PipeReader pr = m_RecvdPipe.Reader; + + while (true) + { + ReadResult result = await pr.ReadAsync(); + ReadOnlySequence seq = result.Buffer; + if (seq.Length == 0) + break; + + long pos = PacketHandlers.ProcessPacket(pump, this, seq); + + if (pos <= 0) + break; + + pr.AdvanceTo(seq.GetPosition(pos, seq.Start)); + + if (result.IsCompleted || result.IsCanceled) + break; + } + + pr.Complete(); + } + public PacketHandler GetHandler(int packetID) { return ContainerGridLines ? PacketHandlers.Get6017Handler(packetID) : PacketHandlers.GetHandler(packetID); } - public static void FlushAll() - { - if (Instances.Count >= 1024) - Parallel.ForEach(Instances, ns => ns.Flush()); - else - for (int i = 0; i < Instances.Count; ++i) - Instances[i].Flush(); - } - - public static int CoalesceSleep{ get; set; } = -1; - private long m_NextCheckActivity; public void CheckAlive(long curTicks) @@ -772,72 +634,34 @@ namespace Server.Network // ignored } - try - { - Console.WriteLine(ex); - } - catch - { - // ignored - } + Console.WriteLine(ex); } - public bool IsDisposing{ get; private set; } + private int m_Disposing; - public virtual void Dispose(bool flush = true) + public bool IsDisposing { get { return m_Disposing != 0; } private set { m_Disposing = value ? 1 : 0; } } + + public virtual void Dispose() { - if (Socket == null || IsDisposing) + int disposing = Interlocked.Exchange(ref m_Disposing, 1); + if (disposing == 1) return; - IsDisposing = true; - - if (flush) - flush = Flush(); - - try + Task.Run(async () => { - Socket.Shutdown(SocketShutdown.Both); - } - catch (SocketException ex) - { - TraceException(ex); - } + m_RecvdPipe.Reader.CancelPendingRead(); + m_RecvdPipe.Reader.Complete(); + await m_RecvdPipe.Writer.FlushAsync().ConfigureAwait(false); + m_RecvdPipe.Writer.Complete(); - try - { - Socket.Close(); - } - catch (SocketException ex) - { - TraceException(ex); - } + try { Socket.Shutdown(SocketShutdown.Both); } catch (Exception ex) { TraceException(ex); } + try { Socket.Close(); } catch (Exception ex) { TraceException(ex); } - if (m_RecvBuffer != null) - lock (m_ReceiveBufferPool) - { - m_ReceiveBufferPool.ReleaseBuffer(m_RecvBuffer); - } - - Socket = null; - - Buffer = null; - m_RecvBuffer = null; - - m_ReceiveEventArgs = null; - m_SendEventArgs = null; - - Running = false; - - lock (m_Disposed) - { + Socket = null; + m_RecvdPipe = null; + m_SendQueue = null; m_Disposed.Enqueue(this); - } - - lock (m_SendQueue) - { - if ( /*!flush &&*/ !m_SendQueue.IsEmpty) - m_SendQueue.Clear(); - } + }); } public static void Initialize() @@ -863,53 +687,42 @@ namespace Server.Network } } - private static Queue m_Disposed = new Queue(); + private static ConcurrentQueue m_Disposed = new ConcurrentQueue(); public static void ProcessDisposedQueue() { - lock (m_Disposed) + int breakout = 0; + + while (breakout++ < 200) { - int breakout = 0; + if (!m_Disposed.TryDequeue(out NetState ns)) + break; - while (breakout < 200 && m_Disposed.Count > 0) + Mobile m = ns.Mobile; + IAccount a = ns.Account; + + if (m != null) { - ++breakout; - NetState ns = m_Disposed.Dequeue(); - - Mobile m = ns.Mobile; - IAccount a = ns.Account; - - if (m != null) - { - m.NetState = null; - ns.Mobile = null; - } - - ns.Gumps.Clear(); - ns.Menus.Clear(); - ns.HuePickers.Clear(); - ns.Account = null; - ns.ServerInfo = null; - ns.CityInfo = null; - - Instances.Remove(ns); - - if (a != null) - ns.WriteConsole("Disconnected. [{0} Online] [{1}]", Instances.Count, a); - else - ns.WriteConsole("Disconnected. [{0} Online]", Instances.Count); + m.NetState = null; + ns.Mobile = null; } + + ns.Gumps.Clear(); + ns.Menus.Clear(); + ns.HuePickers.Clear(); + ns.Account = null; + ns.ServerInfo = null; + ns.CityInfo = null; + + Instances.Remove(ns); + + if (a != null) + ns.WriteConsole("Disconnected. [{0} Online] [{1}]", Instances.Count, a); + else + ns.WriteConsole("Disconnected. [{0} Online]", Instances.Count); } } - public bool Running{ get; private set; } - - public bool Seeded{ get; set; } - - public Socket Socket{ get; private set; } - - public ByteQueue Buffer{ get; private set; } - public ExpansionInfo ExpansionInfo { get @@ -928,6 +741,8 @@ namespace Server.Network public Expansion Expansion => (Expansion)ExpansionInfo.ID; + public ProtocolChanges ProtocolChanges { get; set; } + public bool SupportsExpansion(ExpansionInfo info, bool checkCoreExpansion = true) { if (info == null || checkCoreExpansion && (int)Core.Expansion < info.ID) diff --git a/Server/Network/Packet.cs b/Server/Network/Packet.cs new file mode 100644 index 000000000..0bfbb39fe --- /dev/null +++ b/Server/Network/Packet.cs @@ -0,0 +1,273 @@ +/*************************************************************************** + * Packet.cs + * ------------------- + * begin : August 2, 2019 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using Server.Diagnostics; +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +namespace Server.Network +{ + public abstract class Packet + { + private const int CompressorBufferSize = 0x10000; + + private const int BufferSize = 4096; + + private byte[] m_CompiledBuffer; + private int m_CompiledLength; + private int m_Length; + private State m_State; + + protected PacketWriter m_Stream; + + protected Packet(int packetID) + { + PacketID = packetID; + + if (Core.Profiling) + { + PacketSendProfile prof = PacketSendProfile.Acquire(GetType()); + prof.Increment(); + } + } + + protected Packet(int packetID, int length) + { + PacketID = packetID; + m_Length = length; + + m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length ); + m_Stream.Write((byte)packetID); + + if (Core.Profiling) + { + PacketSendProfile prof = PacketSendProfile.Acquire(GetType()); + prof.Increment(); + } + } + + public int PacketID { get; } + + public PacketWriter UnderlyingStream => m_Stream; + + public void EnsureCapacity(int length) + { + m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length ); + m_Stream.Write((byte)PacketID); + m_Stream.Write((short)0); + } + + public static Packet SetStatic(Packet p) + { + p.SetStatic(); + return p; + } + + public static Packet Acquire(Packet p) + { + p.Acquire(); + return p; + } + + public static void Release(ref Packet p) + { + p?.Release(); + p = null; + } + + public static void Release(Packet p) + { + p?.Release(); + } + + public void SetStatic() + { + m_State |= State.Static | State.Acquired; + } + + public void Acquire() + { + m_State |= State.Acquired; + } + + public void OnSend() + { + Core.Set(); // Is this still needed if this is done async? + + if ((m_State & (State.Acquired | State.Static)) == 0) + Free(); + } + + private void Free() + { + if (m_CompiledBuffer == null) + return; + + if ((m_State & State.Buffered) != 0) + ArrayPool.Shared.Return(m_CompiledBuffer); + + m_State &= ~(State.Static | State.Acquired | State.Buffered); + + m_CompiledBuffer = null; + } + + public void Release() + { + if ((m_State & State.Acquired) != 0) + Free(); + } + + public byte[] Compile(bool compress, out int length) + { + lock (this) + { + if (m_CompiledBuffer == null) + { + if ((m_State & State.Accessed) == 0) + { + m_State |= State.Accessed; + } + else + { + if ((m_State & State.Warned) == 0) + { + m_State |= State.Warned; + + try + { + using (StreamWriter op = new StreamWriter("net_opt.log", true)) + { + op.WriteLine("Redundant compile for packet {0}, use Acquire() and Release()", GetType()); + op.WriteLine(new StackTrace()); + } + } + catch + { + // ignored + } + } + + m_CompiledBuffer = new byte[0]; + m_CompiledLength = 0; + + length = m_CompiledLength; + return m_CompiledBuffer; + } + + InternalCompile(compress); + } + + length = m_CompiledLength; + return m_CompiledBuffer; + } + } + + private void InternalCompile(bool compress) + { + if (m_Length == 0) + { + long streamLen = m_Stream.Length; + + m_Stream.Seek(1, SeekOrigin.Begin); + m_Stream.Write((ushort)streamLen); + } + else if (m_Stream.Length != m_Length) + { + int diff = (int)m_Stream.Length - m_Length; + + Console.WriteLine("Packet: 0x{0:X2}: Bad packet length! ({1}{2} bytes)", PacketID, diff >= 0 ? "+" : "", + diff); + } + + MemoryStream ms = m_Stream.UnderlyingStream; + + m_CompiledBuffer = ms.GetBuffer(); + int length = (int)ms.Length; + + if (compress) + { + byte[] buffer = ArrayPool.Shared.Rent(CompressorBufferSize); + + Compression.Compress(m_CompiledBuffer, 0, length, buffer, ref length); + + if (length <= 0) + { + Console.WriteLine("Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})", + PacketID, GetType().Name, length); + using (StreamWriter op = new StreamWriter("compression_overflow.log", true)) + { + op.WriteLine("{0} Warning: Compression buffer overflowed on packet 0x{1:X2} ('{2}') (length={3})", + DateTime.UtcNow, PacketID, GetType().Name, length); + op.WriteLine(new StackTrace()); + } + } + else + { + m_CompiledLength = length; + + if ((m_State & State.Static) != 0) + { + m_CompiledBuffer = new byte[length]; + Buffer.BlockCopy(buffer, 0, m_CompiledBuffer, 0, length); + ArrayPool.Shared.Return(buffer); + } + else + { + m_CompiledBuffer = buffer; + m_State |= State.Buffered; + } + } + } + else if (length > 0) + { + byte[] old = m_CompiledBuffer; + m_CompiledLength = length; + + if ((m_State & State.Static) != 0) + m_CompiledBuffer = new byte[length]; + else + { + m_CompiledBuffer = ArrayPool.Shared.Rent(length); + m_State |= State.Buffered; + } + + Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, length); + } + + PacketWriter.ReleaseInstance(m_Stream); + m_Stream = null; + } + + [Flags] + private enum State + { + Inactive = 0x00, + Static = 0x01, + Acquired = 0x02, + Accessed = 0x04, + Buffered = 0x08, + Warned = 0x10 + } + } +} diff --git a/Server/Network/PacketHandler.cs b/Server/Network/PacketHandler.cs index f2268a65e..022405fd5 100644 --- a/Server/Network/PacketHandler.cs +++ b/Server/Network/PacketHandler.cs @@ -18,15 +18,17 @@ * ***************************************************************************/ +using System; + namespace Server.Network { public delegate void OnPacketReceive(NetState state, PacketReader pvSrc); - public delegate bool ThrottlePacketCallback(NetState state); + public delegate TimeSpan ThrottlePacketCallback(NetState state); public class PacketHandler { - public PacketHandler(int packetID, int length, bool ingame, OnPacketReceive onReceive) + public PacketHandler(int packetID, long length, bool ingame, OnPacketReceive onReceive) { PacketID = packetID; Length = length; @@ -36,7 +38,7 @@ namespace Server.Network public int PacketID{ get; } - public int Length{ get; } + public long Length{ get; } public OnPacketReceive OnReceive{ get; } @@ -44,4 +46,4 @@ namespace Server.Network public bool Ingame{ get; } } -} \ No newline at end of file +} diff --git a/Server/Network/PacketHandlers.cs b/Server/Network/PacketHandlers.cs index b0b62e192..b7acefa3e 100644 --- a/Server/Network/PacketHandlers.cs +++ b/Server/Network/PacketHandlers.cs @@ -19,8 +19,10 @@ ***************************************************************************/ using System; +using System.Buffers; using System.Collections.Generic; using System.IO; +using System.IO.Pipelines; using Server.Accounting; using Server.ContextMenus; using Server.Diagnostics; @@ -304,6 +306,102 @@ namespace Server.Network ph.ThrottleCallback = t; } + public static long ProcessPacket(MessagePump pump, NetState ns, in ReadOnlySequence seq) + { + PacketReader r = new PacketReader(seq); + + if (!r.TryReadByte(out byte packetId)) + { + ns.Dispose(); + return -1; + } + + if (!ns.Seeded) + { + if (packetId == 0xEF) + { + // new packet in client 6.0.5.0 replaces the traditional seed method with a seed packet + // 0xEF = 239 = multicast IP, so this should never appear in a normal seed. So this is backwards compatible with older clients. + ns.Seeded = true; + } + else + { + int seed = (packetId << 24) | (r.ReadByte() << 16) | (r.ReadByte() << 8) | r.ReadByte(); + + if (seed == 0) + { + Console.WriteLine("Login: {0}: Invalid client detected, disconnecting", ns); + ns.Dispose(); + return -1; + } + + ns.m_Seed = seed; + ns.Seeded = true; + + return 4; + } + } + + if (ns.CheckEncrypted(packetId)) + { + ns.Dispose(); + return -1; + } + + // Get Handlers + PacketHandler handler = ns.GetHandler(packetId); + + if (handler == null) + { + r.Trace(ns); + return -1; + } + + long packetLength = handler.Length; + if (handler.Length <= 0 && r.Length >= 3) + { + packetLength = r.ReadUInt16(); + if (packetLength < 3) + { + ns.Dispose(); + return -1; + } + } + + if (r.Length < packetLength) + return 0; + + if (handler.Ingame && ns.Mobile?.Deleted != false) + { + Console.WriteLine( + "Client: {0}: Sent ingame packet (0x{1:X2}) without being attached to a valid mobile.", + ns, + packetId + ); + ns.Dispose(); + return -1; + } + + ThrottlePacketCallback throttler = handler.ThrottleCallback; + TimeSpan throttled = handler.ThrottleCallback?.Invoke(ns) ?? TimeSpan.Zero; + + if (throttled > TimeSpan.Zero) + ns.ThrottledUntil = DateTime.UtcNow + throttled; + + PacketReceiveProfile prof = null; + + if (Core.Profiling) + prof = PacketReceiveProfile.Acquire(packetId); + + prof?.Start(); + + pump.QueueWork(ns, seq.Slice(r.Position), handler.OnReceive); + + prof?.Finish(packetLength); + + return packetLength; + } + private static void UnhandledBF(NetState state, PacketReader pvSrc) { } @@ -450,7 +548,8 @@ namespace Server.Network Mobile vendor = World.FindMobile(pvSrc.ReadUInt32()); byte flag = pvSrc.ReadByte(); - if (vendor == null) return; + if (vendor == null) + return; if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10)) { @@ -499,7 +598,7 @@ namespace Server.Network } int count = pvSrc.ReadUInt16(); - if (count < 100 && pvSrc.Size == 1 + 2 + 4 + 2 + count * 6) + if (count < 100 && pvSrc.Length == 1 + 2 + 4 + 2 + count * 6) { List sellList = new List(count); @@ -888,7 +987,8 @@ namespace Server.Network public static void GodModeRequest(NetState state, PacketReader pvSrc) { - if (VerifyGC(state)) state.Send(new GodModeReply(pvSrc.ReadBoolean())); + if (VerifyGC(state)) + state.Send(new GodModeReply(pvSrc.ReadBoolean())); } public static void AsciiPromptResponse(NetState state, PacketReader pvSrc) @@ -1603,6 +1703,7 @@ namespace Server.Network { int packetID = pvSrc.ReadUInt16(); + Console.WriteLine("Extended Packet: {0:X}", packetID); PacketHandler ph = GetExtendedHandler(packetID); if (ph == null) @@ -1681,12 +1782,12 @@ namespace Server.Network Mobile from = state.Mobile; - int length = pvSrc.Size - 3; + long length = pvSrc.Length - 3; if (length < 0 || length % 4 != 0) return; - int count = length / 4; + long count = length / 4; for (int i = 0; i < count; ++i) { @@ -2010,7 +2111,7 @@ namespace Server.Network pvSrc.Seek(2, SeekOrigin.Current); int flags = pvSrc.ReadInt32(); - if (FeatureProtection.DisabledFeatures != 0 && ThirdPartyAuthCallback != null) +/* if (FeatureProtection.DisabledFeatures != 0 && ThirdPartyAuthCallback != null) { bool authOK = false; @@ -2031,18 +2132,18 @@ namespace Server.Network } ThirdPartyAuthCallback(state, authOK); - } - else - { + }*/ +/* else + {*/ pvSrc.Seek(24, SeekOrigin.Current); - } +/* }*/ - if (ThirdPartyHackedCallback != null) +/* if (ThirdPartyHackedCallback != null) { pvSrc.Seek(-2, SeekOrigin.Current); if (pvSrc.ReadUInt16() == 0xDEAD) ThirdPartyHackedCallback(state, true); - } + }*/ if (!state.Running) return; @@ -2053,9 +2154,7 @@ namespace Server.Network IAccount a = state.Account; if (a == null || charSlot < 0 || charSlot >= a.Length) - { state.Dispose(); - } else { Mobile m = a[charSlot]; @@ -2079,7 +2178,6 @@ namespace Server.Network return; } - m.NetState?.Dispose(); // TODO: Make this wait one tick so we don't have to call it unnecessarily @@ -2206,8 +2304,6 @@ namespace Server.Network int prof = pvSrc.ReadByte(); pvSrc.Seek(15, SeekOrigin.Current); - //bool female = pvSrc.ReadBoolean(); - int genderRace = pvSrc.ReadByte(); int str = pvSrc.ReadByte(); @@ -2645,8 +2741,7 @@ namespace Server.Network if (e.Rejected) { state.Account = null; - state.Send(new AccountLoginRej(ALRReason.BadComm)); - state.Dispose(); + AccountLogin_ReplyRej(state, ALRReason.BadComm); } else { diff --git a/Server/Network/PacketReader.cs b/Server/Network/PacketReader.cs index c120903b5..d5facc4ef 100644 --- a/Server/Network/PacketReader.cs +++ b/Server/Network/PacketReader.cs @@ -18,25 +18,29 @@ * ***************************************************************************/ +using System; +using System.Buffers; using System.IO; +using System.IO.Pipelines; using System.Text; namespace Server.Network { - public class PacketReader + public ref struct PacketReader { - private int m_Index; + private SequenceReader m_Reader; - public PacketReader(byte[] data, int size, bool fixedSize) + public SequencePosition Position => m_Reader.Position; + public long Length => m_Reader.Length; + public long Consumed => m_Reader.Consumed; + public long Remaining => m_Reader.Remaining; + + public PacketReader(ReadOnlySequence seq) { - Buffer = data; - Size = size; - m_Index = fixedSize ? 1 : 3; + m_Reader = new SequenceReader(seq); } - public byte[] Buffer{ get; } - - public int Size{ get; } + public byte Peek() => m_Reader.TryPeek(out byte value) ? value : (byte)0; public void Trace(NetState state) { @@ -44,7 +48,7 @@ namespace Server.Network { using (StreamWriter sw = new StreamWriter("Packets.log", true)) { - byte[] buffer = Buffer; + byte[] buffer = m_Reader.Sequence.ToArray(); if (buffer.Length > 0) sw.WriteLine("Client: {0}: Unhandled packet 0x{1:X2}", state, buffer[0]); @@ -64,113 +68,83 @@ namespace Server.Network } } - public int Seek(int offset, SeekOrigin origin) + public SequencePosition Seek(long offset, SeekOrigin origin) { switch (origin) { case SeekOrigin.Begin: - m_Index = offset; + if (offset < m_Reader.Consumed) + m_Reader.Rewind(m_Reader.Consumed - Math.Max(offset, 0L)); + else + m_Reader.Advance(offset - m_Reader.Consumed); break; case SeekOrigin.Current: - m_Index += offset; + if (offset < 0) + m_Reader.Rewind(Math.Min(m_Reader.Consumed, offset * -1)); + else + m_Reader.Advance(Math.Min(m_Reader.Remaining, offset)); break; case SeekOrigin.End: - m_Index = Size - offset; + long count = m_Reader.Remaining - offset; + if (count < 0) + m_Reader.Rewind(count * -1); + else if (count > 0) + m_Reader.Advance(count); break; } - return m_Index; + return m_Reader.Position; } - public int ReadInt32() - { - if (m_Index + 4 > Size) - return 0; + public bool TryReadByte(out byte value) => m_Reader.TryRead(out value); - return (Buffer[m_Index++] << 24) - | (Buffer[m_Index++] << 16) - | (Buffer[m_Index++] << 8) - | Buffer[m_Index++]; - } + public int ReadInt32() => m_Reader.TryReadBigEndian(out int value) ? value : 0; - public short ReadInt16() - { - if (m_Index + 2 > Size) - return 0; + public short ReadInt16() => m_Reader.TryReadBigEndian(out short value) ? value : (short)0; - return (short)((Buffer[m_Index++] << 8) | Buffer[m_Index++]); - } + public byte ReadByte() => m_Reader.TryRead(out byte value) ? value : (byte)0; - public byte ReadByte() - { - if (m_Index + 1 > Size) - return 0; + public uint ReadUInt32() => (uint)ReadInt32(); - return Buffer[m_Index++]; - } + public ushort ReadUInt16() => (ushort)ReadInt16(); - public uint ReadUInt32() - { - if (m_Index + 4 > Size) - return 0; + public sbyte ReadSByte() => (sbyte)ReadByte(); - return (uint)((Buffer[m_Index++] << 24) | (Buffer[m_Index++] << 16) | (Buffer[m_Index++] << 8) | - Buffer[m_Index++]); - } - - public ushort ReadUInt16() - { - if (m_Index + 2 > Size) - return 0; - - return (ushort)((Buffer[m_Index++] << 8) | Buffer[m_Index++]); - } - - public sbyte ReadSByte() - { - if (m_Index + 1 > Size) - return 0; - - return (sbyte)Buffer[m_Index++]; - } - - public bool ReadBoolean() - { - if (m_Index + 1 > Size) - return false; - - return Buffer[m_Index++] != 0; - } + public bool ReadBoolean() => ReadByte() > 0; public string ReadUnicodeStringLE() { StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index + 1 < Size && (c = Buffer[m_Index++] | (Buffer[m_Index++] << 8)) != 0) + while (m_Reader.TryReadLittleEndian(out short c) && c != 0) sb.Append((char)c); return sb.ToString(); } + public string ReadUnicodeStringLE(int fixedLength) + { + StringBuilder sb = new StringBuilder(); + + while (fixedLength-- > 0 && m_Reader.TryReadLittleEndian(out short c) && c != 0) + sb.Append((char)c); + + if (fixedLength > 0) + m_Reader.Advance(fixedLength); + + return sb.ToString(); + } + public string ReadUnicodeStringLESafe(int fixedLength) { - int bound = m_Index + (fixedLength << 1); - int end = bound; - - if (bound > Size) - bound = Size; - StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index + 1 < bound && (c = Buffer[m_Index++] | (Buffer[m_Index++] << 8)) != 0) + while (fixedLength-- > 0 && m_Reader.TryReadLittleEndian(out short c) && c != 0) if (IsSafeChar(c)) sb.Append((char)c); - m_Index = end; + if (fixedLength > 0) + m_Reader.Advance(fixedLength * 2); return sb.ToString(); } @@ -179,9 +153,7 @@ namespace Server.Network { StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index + 1 < Size && (c = Buffer[m_Index++] | (Buffer[m_Index++] << 8)) != 0) + while (m_Reader.TryReadLittleEndian(out short c) && c != 0) if (IsSafeChar(c)) sb.Append((char)c); @@ -192,9 +164,7 @@ namespace Server.Network { StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index + 1 < Size && (c = (Buffer[m_Index++] << 8) | Buffer[m_Index++]) != 0) + while (m_Reader.TryReadBigEndian(out short c) && c != 0) if (IsSafeChar(c)) sb.Append((char)c); @@ -205,9 +175,7 @@ namespace Server.Network { StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index + 1 < Size && (c = (Buffer[m_Index++] << 8) | Buffer[m_Index++]) != 0) + while (m_Reader.TryReadBigEndian(out short c) && c != 0) sb.Append((char)c); return sb.ToString(); @@ -220,45 +188,17 @@ namespace Server.Network public string ReadUTF8StringSafe(int fixedLength) { - if (m_Index >= Size) + string s; + + if (m_Reader.TryReadTo(out ReadOnlySpan span, (byte)'\0', true)) + s = Utility.UTF8.GetString(span.Length > fixedLength ? span.Slice(0, fixedLength) : span); + else { - m_Index += fixedLength; - return string.Empty; + long size = Math.Min(m_Reader.Remaining, fixedLength); + s = Utility.UTF8.GetString(m_Reader.Sequence.Slice(m_Reader.Position, size).ToArray()); + m_Reader.Advance(size); } - int bound = m_Index + fixedLength; - //int end = bound; - - if (bound > Size) - bound = Size; - - int count = 0; - int index = m_Index; - int start = m_Index; - - while (index < bound && Buffer[index++] != 0) - ++count; - - index = 0; - - byte[] buffer = new byte[count]; - int value = 0; - - while (m_Index < bound && (value = Buffer[m_Index++]) != 0) - buffer[index++] = (byte)value; - - string s = Utility.UTF8.GetString(buffer); - - bool isSafe = true; - - for (int i = 0; isSafe && i < s.Length; ++i) - isSafe = IsSafeChar(s[i]); - - m_Index = start + fixedLength; - - if (isSafe) - return s; - StringBuilder sb = new StringBuilder(s.Length); for (int i = 0; i < s.Length; ++i) @@ -270,32 +210,15 @@ namespace Server.Network public string ReadUTF8StringSafe() { - if (m_Index >= Size) - return string.Empty; + string s; - int count = 0; - int index = m_Index; - - while (index < Size && Buffer[index++] != 0) - ++count; - - index = 0; - - byte[] buffer = new byte[count]; - int value = 0; - - while (m_Index < Size && (value = Buffer[m_Index++]) != 0) - buffer[index++] = (byte)value; - - string s = Utility.UTF8.GetString(buffer); - - bool isSafe = true; - - for (int i = 0; isSafe && i < s.Length; ++i) - isSafe = IsSafeChar(s[i]); - - if (isSafe) - return s; + if (m_Reader.TryReadTo(out ReadOnlySpan span, (byte)'\0', true)) + s = Utility.UTF8.GetString(span); + else + { + s = Utility.UTF8.GetString(m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray()); + m_Reader.Advance(m_Reader.Remaining); + } StringBuilder sb = new StringBuilder(s.Length); @@ -308,33 +231,17 @@ namespace Server.Network public string ReadUTF8String() { - if (m_Index >= Size) - return string.Empty; - - int count = 0; - int index = m_Index; - - while (index < Size && Buffer[index++] != 0) - ++count; - - index = 0; - - byte[] buffer = new byte[count]; - int value = 0; - - while (m_Index < Size && (value = Buffer[m_Index++]) != 0) - buffer[index++] = (byte)value; - - return Utility.UTF8.GetString(buffer); + return Utility.UTF8.GetString( + m_Reader.TryReadTo(out ReadOnlySpan span, (byte)'\0', true) ? span : + m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray() + ); } public string ReadString() { StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index < Size && (c = Buffer[m_Index++]) != 0) + while (m_Reader.TryRead(out byte c)) sb.Append((char)c); return sb.ToString(); @@ -344,9 +251,7 @@ namespace Server.Network { StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index < Size && (c = Buffer[m_Index++]) != 0) + while (m_Reader.TryRead(out byte c)) if (IsSafeChar(c)) sb.Append((char)c); @@ -355,84 +260,56 @@ namespace Server.Network public string ReadUnicodeStringSafe(int fixedLength) { - int bound = m_Index + (fixedLength << 1); - int end = bound; - - if (bound > Size) - bound = Size; - StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index + 1 < bound && (c = (Buffer[m_Index++] << 8) | Buffer[m_Index++]) != 0) + while (fixedLength-- > 0 && m_Reader.TryReadBigEndian(out short c) && c != 0) if (IsSafeChar(c)) sb.Append((char)c); - m_Index = end; + if (fixedLength > 0) + m_Reader.Advance(fixedLength * 2); return sb.ToString(); } public string ReadUnicodeString(int fixedLength) { - int bound = m_Index + (fixedLength << 1); - int end = bound; - - if (bound > Size) - bound = Size; - StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index + 1 < bound && (c = (Buffer[m_Index++] << 8) | Buffer[m_Index++]) != 0) + while (fixedLength-- > 0 && m_Reader.TryReadBigEndian(out short c) && c != 0) sb.Append((char)c); - m_Index = end; + if (fixedLength > 0) + m_Reader.Advance(fixedLength * 2); return sb.ToString(); } public string ReadStringSafe(int fixedLength) { - int bound = m_Index + fixedLength; - int end = bound; - - if (bound > Size) - bound = Size; - StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index < bound && (c = Buffer[m_Index++]) != 0) + while (fixedLength-- > 0 && m_Reader.TryRead(out byte c) && c != 0) if (IsSafeChar(c)) sb.Append((char)c); - m_Index = end; + if (fixedLength > 0) + m_Reader.Advance(fixedLength); return sb.ToString(); } public string ReadString(int fixedLength) { - int bound = m_Index + fixedLength; - int end = bound; - - if (bound > Size) - bound = Size; - StringBuilder sb = new StringBuilder(); - int c; - - while (m_Index < bound && (c = Buffer[m_Index++]) != 0) + while (fixedLength-- > 0 && m_Reader.TryRead(out byte c) && c != 0) sb.Append((char)c); - m_Index = end; + if (fixedLength > 0) + m_Reader.Advance(fixedLength); return sb.ToString(); } } -} \ No newline at end of file +} diff --git a/Server/Network/PacketWriter.cs b/Server/Network/PacketWriter.cs index e45a1e12b..c90b85fb8 100644 --- a/Server/Network/PacketWriter.cs +++ b/Server/Network/PacketWriter.cs @@ -19,7 +19,7 @@ ***************************************************************************/ using System; -using System.Collections.Generic; +using System.Collections.Concurrent; using System.IO; using System.Text; @@ -30,7 +30,7 @@ namespace Server.Network /// public class PacketWriter { - private static Stack m_Pool = new Stack(); + private static ConcurrentQueue m_Pool = new ConcurrentQueue(); /// /// Internal format buffer. @@ -39,85 +39,50 @@ namespace Server.Network private int m_Capacity; - /// - /// Internal stream which holds the entire packet. - /// - private MemoryStream m_Stream; - /// /// Instantiates a new PacketWriter instance with a given capacity. /// /// Initial capacity for the internal stream. public PacketWriter(int capacity = 32) { - m_Stream = new MemoryStream(capacity); + UnderlyingStream = new MemoryStream(capacity); m_Capacity = capacity; } /// /// Gets the total stream length. /// - public long Length => m_Stream.Length; + public long Length => UnderlyingStream.Length; /// /// Gets or sets the current stream position. /// public long Position { - get => m_Stream.Position; - set => m_Stream.Position = value; + get => UnderlyingStream.Position; + set => UnderlyingStream.Position = value; } /// /// The internal stream used by this PacketWriter instance. /// - public MemoryStream UnderlyingStream => m_Stream; + public MemoryStream UnderlyingStream { get; private set; } - public static PacketWriter CreateInstance() + public static PacketWriter CreateInstance(int capacity = 32) { - return CreateInstance(32); - } - - public static PacketWriter CreateInstance(int capacity) - { - PacketWriter pw = null; - - lock (m_Pool) + if (m_Pool.TryDequeue(out PacketWriter pw)) { - if (m_Pool.Count > 0) - { - pw = m_Pool.Pop(); - - if (pw != null) - { - pw.m_Capacity = capacity; - pw.m_Stream.SetLength(0); - } - } + pw.m_Capacity = capacity; + pw.UnderlyingStream.SetLength(0); + return pw; } - return pw ?? new PacketWriter(capacity); + return new PacketWriter(capacity); } public static void ReleaseInstance(PacketWriter pw) { - lock (m_Pool) - { - if (!m_Pool.Contains(pw)) - m_Pool.Push(pw); - else - try - { - using (StreamWriter op = new StreamWriter("neterr.log")) - { - op.WriteLine("{0}\tInstance pool contains writer", DateTime.UtcNow); - } - } - catch - { - Console.WriteLine("net error"); - } - } + m_Pool.Enqueue(pw); } /// @@ -125,7 +90,7 @@ namespace Server.Network /// public void Write(bool value) { - m_Stream.WriteByte((byte)(value ? 1 : 0)); + UnderlyingStream.WriteByte((byte)(value ? 1 : 0)); } /// @@ -133,7 +98,7 @@ namespace Server.Network /// public void Write(byte value) { - m_Stream.WriteByte(value); + UnderlyingStream.WriteByte(value); } /// @@ -141,7 +106,7 @@ namespace Server.Network /// public void Write(sbyte value) { - m_Stream.WriteByte((byte)value); + UnderlyingStream.WriteByte((byte)value); } /// @@ -152,7 +117,7 @@ namespace Server.Network m_Buffer[0] = (byte)(value >> 8); m_Buffer[1] = (byte)value; - m_Stream.Write(m_Buffer, 0, 2); + UnderlyingStream.Write(m_Buffer, 0, 2); } /// @@ -163,7 +128,7 @@ namespace Server.Network m_Buffer[0] = (byte)(value >> 8); m_Buffer[1] = (byte)value; - m_Stream.Write(m_Buffer, 0, 2); + UnderlyingStream.Write(m_Buffer, 0, 2); } /// @@ -176,7 +141,7 @@ namespace Server.Network m_Buffer[2] = (byte)(value >> 8); m_Buffer[3] = (byte)value; - m_Stream.Write(m_Buffer, 0, 4); + UnderlyingStream.Write(m_Buffer, 0, 4); } /// @@ -189,7 +154,7 @@ namespace Server.Network m_Buffer[2] = (byte)(value >> 8); m_Buffer[3] = (byte)value; - m_Stream.Write(m_Buffer, 0, 4); + UnderlyingStream.Write(m_Buffer, 0, 4); } /// @@ -197,7 +162,7 @@ namespace Server.Network /// public void Write(byte[] buffer, int offset, int size) { - m_Stream.Write(buffer, offset, size); + UnderlyingStream.Write(buffer, offset, size); } /// @@ -214,29 +179,18 @@ namespace Server.Network int length = value.Length; - m_Stream.SetLength(m_Stream.Length + size); + UnderlyingStream.SetLength(UnderlyingStream.Length + size); if (length >= size) { - m_Stream.Position += Encoding.ASCII.GetBytes(value, 0, size, m_Stream.GetBuffer(), (int)m_Stream.Position); + UnderlyingStream.Position += + Encoding.ASCII.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); } else { - Encoding.ASCII.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position); - m_Stream.Position += size; + Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += size; } - - /*byte[] buffer = Encoding.ASCII.GetBytes( value ); - - if ( buffer.Length >= size ) - { - m_Stream.Write( buffer, 0, size ); - } - else - { - m_Stream.Write( buffer, 0, buffer.Length ); - Fill( size - buffer.Length ); - }*/ } /// @@ -252,15 +206,10 @@ namespace Server.Network int length = value.Length; - m_Stream.SetLength(m_Stream.Length + length + 1); + UnderlyingStream.SetLength(UnderlyingStream.Length + length + 1); - Encoding.ASCII.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position); - m_Stream.Position += length + 1; - - /*byte[] buffer = Encoding.ASCII.GetBytes( value ); - - m_Stream.Write( buffer, 0, buffer.Length ); - m_Stream.WriteByte( 0 );*/ + Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += length + 1; } /// @@ -276,18 +225,10 @@ namespace Server.Network int length = value.Length; - m_Stream.SetLength(m_Stream.Length + (length + 1) * 2); + UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2); - m_Stream.Position += Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position); - m_Stream.Position += 2; - - /*byte[] buffer = Encoding.Unicode.GetBytes( value ); - - m_Stream.Write( buffer, 0, buffer.Length ); - - m_Buffer[0] = 0; - m_Buffer[1] = 0; - m_Stream.Write( m_Buffer, 0, 2 );*/ + UnderlyingStream.Position += Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += 2; } /// @@ -302,36 +243,21 @@ namespace Server.Network value = string.Empty; } + int length = value.Length; size *= 2; - int length = value.Length; - - m_Stream.SetLength(m_Stream.Length + size); + UnderlyingStream.SetLength(UnderlyingStream.Length + size); if (length * 2 >= size) { - m_Stream.Position += - Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position); + UnderlyingStream.Position += + Encoding.Unicode.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); } else { - Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position); - m_Stream.Position += size; + Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += size; } - - /*size *= 2; - - byte[] buffer = Encoding.Unicode.GetBytes( value ); - - if ( buffer.Length >= size ) - { - m_Stream.Write( buffer, 0, size ); - } - else - { - m_Stream.Write( buffer, 0, buffer.Length ); - Fill( size - buffer.Length ); - }*/ } /// @@ -347,19 +273,11 @@ namespace Server.Network int length = value.Length; - m_Stream.SetLength(m_Stream.Length + (length + 1) * 2); + UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2); - m_Stream.Position += - Encoding.BigEndianUnicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position); - m_Stream.Position += 2; - - /*byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value ); - - m_Stream.Write( buffer, 0, buffer.Length ); - - m_Buffer[0] = 0; - m_Buffer[1] = 0; - m_Stream.Write( m_Buffer, 0, 2 );*/ + UnderlyingStream.Position += + Encoding.BigEndianUnicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += 2; } /// @@ -374,36 +292,21 @@ namespace Server.Network value = string.Empty; } + int length = value.Length; size *= 2; - int length = value.Length; + UnderlyingStream.SetLength(UnderlyingStream.Length + size); - m_Stream.SetLength(m_Stream.Length + size); - - if (length * 2 >= size) + if (length * 2 >= size ) { - m_Stream.Position += - Encoding.BigEndianUnicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position); + UnderlyingStream.Position += + Encoding.BigEndianUnicode.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); } else { - Encoding.BigEndianUnicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position); - m_Stream.Position += size; + Encoding.BigEndianUnicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position); + UnderlyingStream.Position += size; } - - /*size *= 2; - - byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value ); - - if ( buffer.Length >= size ) - { - m_Stream.Write( buffer, 0, size ); - } - else - { - m_Stream.Write( buffer, 0, buffer.Length ); - Fill( size - buffer.Length ); - }*/ } /// @@ -411,39 +314,33 @@ namespace Server.Network /// public void Fill() { - Fill((int)(m_Capacity - m_Stream.Length)); + Fill(m_Capacity - UnderlyingStream.Length); } /// /// Writes a number of 0x00 byte values to the underlying stream. /// - public void Fill(int length) + public void Fill(long length) { - if (m_Stream.Position == m_Stream.Length) + if (UnderlyingStream.Position == UnderlyingStream.Length) { - m_Stream.SetLength(m_Stream.Length + length); - m_Stream.Seek(0, SeekOrigin.End); + UnderlyingStream.SetLength(UnderlyingStream.Length + length); + UnderlyingStream.Seek(0, SeekOrigin.End); } else { - m_Stream.Write(new byte[length], 0, length); + UnderlyingStream.Write(new byte[length], 0, (int)length); } } /// /// Offsets the current position from an origin. /// - public long Seek(long offset, SeekOrigin origin) - { - return m_Stream.Seek(offset, origin); - } + public long Seek(long offset, SeekOrigin origin) => UnderlyingStream.Seek(offset, origin); /// /// Gets the entire stream content as a byte array. /// - public byte[] ToArray() - { - return m_Stream.ToArray(); - } + public byte[] ToArray() => UnderlyingStream.ToArray(); } } diff --git a/Server/Network/Packets.cs b/Server/Network/Packets.cs index a08633c70..4dabd698d 100644 --- a/Server/Network/Packets.cs +++ b/Server/Network/Packets.cs @@ -19,6 +19,7 @@ ***************************************************************************/ using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -2336,8 +2337,6 @@ namespace Server.Network public sealed class DisplayGumpPacked : Packet, IGumpWriter { - private const int GumpBufferSize = 0x5000; - private static byte[] m_True = Gump.StringToBuffer(" 1"); private static byte[] m_False = Gump.StringToBuffer(" 0"); @@ -2345,7 +2344,6 @@ namespace Server.Network private static byte[] m_EndTextSeparator = Gump.StringToBuffer("@"); private static byte[] m_Buffer = new byte[48]; - private static BufferPool m_PackBuffers = new BufferPool("Gump", 4, GumpBufferSize); private Gump m_Gump; @@ -2465,30 +2463,17 @@ namespace Server.Network wantLength += 4095; wantLength &= ~4095; - byte[] m_PackBuffer; - lock (m_PackBuffers) - { - m_PackBuffer = m_PackBuffers.AcquireBuffer(); - } + byte[] packBuffer = ArrayPool.Shared.Rent(wantLength); - if (m_PackBuffer.Length < wantLength) - { - Console.WriteLine("Notice: DisplayGumpPacked creating new {0} byte buffer", wantLength); - m_PackBuffer = new byte[wantLength]; - } + int packLength = wantLength; - int packLength = m_PackBuffer.Length; - - Compression.Pack(m_PackBuffer, ref packLength, buffer, length, ZLibQuality.Default); + Compression.Pack(packBuffer, ref packLength, buffer, length, ZLibQuality.Default); m_Stream.Write(4 + packLength); m_Stream.Write(length); - m_Stream.Write(m_PackBuffer, 0, packLength); + m_Stream.Write(packBuffer, 0, packLength); - lock (m_PackBuffers) - { - m_PackBuffers.ReleaseBuffer(m_PackBuffer); - } + ArrayPool.Shared.Return(packBuffer); } } @@ -3954,7 +3939,7 @@ namespace Server.Network public sealed class CharacterList : Packet { - private static MD5CryptoServiceProvider m_MD5Provider; + //private static MD5CryptoServiceProvider m_MD5Provider; public CharacterList(IAccount a, CityInfo[] info) : base(0xA9) { @@ -4013,7 +3998,7 @@ namespace Server.Network m_Stream.Write((short)-1); - ThirdPartyFeature disabled = FeatureProtection.DisabledFeatures; + /*ThirdPartyFeature disabled = FeatureProtection.DisabledFeatures; if (disabled != 0) { @@ -4040,7 +4025,7 @@ namespace Server.Network m_Stream.Seek(95, SeekOrigin.Begin); m_Stream.Write(hashCode, 0, hashCode.Length); - } + }*/ } public static CharacterListFlags AdditionalFlags{ get; set; } @@ -4048,7 +4033,7 @@ namespace Server.Network public sealed class CharacterListOld : Packet { - private static MD5CryptoServiceProvider m_MD5Provider; + // private static MD5CryptoServiceProvider m_MD5Provider; public CharacterListOld(IAccount a, CityInfo[] info) : base(0xA9) { @@ -4099,7 +4084,7 @@ namespace Server.Network m_Stream.Write((int)(flags | CharacterList.AdditionalFlags)); // Additional Flags - ThirdPartyFeature disabled = FeatureProtection.DisabledFeatures; +/* ThirdPartyFeature disabled = FeatureProtection.DisabledFeatures; if (disabled != 0) { @@ -4126,7 +4111,7 @@ namespace Server.Network m_Stream.Seek(95, SeekOrigin.Begin); m_Stream.Write(hashCode, 0, hashCode.Length); - } + }*/ } } @@ -4197,7 +4182,7 @@ namespace Server.Network public sealed class ServerInfo { - public ServerInfo(string name, int fullPercent, TimeZone tz, IPEndPoint address) + public ServerInfo(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address) { Name = name; FullPercent = fullPercent; @@ -4289,271 +4274,4 @@ namespace Server.Network m_Stream.Write(m_AuthID); } } - - public abstract class Packet - { - private const int CompressorBufferSize = 0x10000; - - private const int BufferSize = 4096; - private static BufferPool m_CompressorBuffers = new BufferPool("Compressor", 4, CompressorBufferSize); - private static BufferPool m_Buffers = new BufferPool("Compressed", 16, BufferSize); - - private byte[] m_CompiledBuffer; - private int m_CompiledLength; - private int m_Length; - private State m_State; - - protected PacketWriter m_Stream; - - protected Packet(int packetID) - { - PacketID = packetID; - - if (Core.Profiling) - { - PacketSendProfile prof = PacketSendProfile.Acquire(GetType()); - prof.Increment(); - } - } - - protected Packet(int packetID, int length) - { - PacketID = packetID; - m_Length = length; - - m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length ); - m_Stream.Write((byte)packetID); - - if (Core.Profiling) - { - PacketSendProfile prof = PacketSendProfile.Acquire(GetType()); - prof.Increment(); - } - } - - public int PacketID{ get; } - - public PacketWriter UnderlyingStream => m_Stream; - - public void EnsureCapacity(int length) - { - m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length ); - m_Stream.Write((byte)PacketID); - m_Stream.Write((short)0); - } - - public static Packet SetStatic(Packet p) - { - p.SetStatic(); - return p; - } - - public static Packet Acquire(Packet p) - { - p.Acquire(); - return p; - } - - public static void Release(ref Packet p) - { - p?.Release(); - p = null; - } - - public static void Release(Packet p) - { - p?.Release(); - } - - public void SetStatic() - { - m_State |= State.Static | State.Acquired; - } - - public void Acquire() - { - m_State |= State.Acquired; - } - - public void OnSend() - { - Core.Set(); - - lock (this) - { - if ((m_State & (State.Acquired | State.Static)) == 0) - Free(); - } - } - - private void Free() - { - if (m_CompiledBuffer == null) - return; - - if ((m_State & State.Buffered) != 0) - m_Buffers.ReleaseBuffer(m_CompiledBuffer); - - m_State &= ~(State.Static | State.Acquired | State.Buffered); - - m_CompiledBuffer = null; - } - - public void Release() - { - if ((m_State & State.Acquired) != 0) - Free(); - } - - public byte[] Compile(bool compress, out int length) - { - lock (this) - { - if (m_CompiledBuffer == null) - { - if ((m_State & State.Accessed) == 0) - { - m_State |= State.Accessed; - } - else - { - if ((m_State & State.Warned) == 0) - { - m_State |= State.Warned; - - try - { - using (StreamWriter op = new StreamWriter("net_opt.log", true)) - { - op.WriteLine("Redundant compile for packet {0}, use Acquire() and Release()", GetType()); - op.WriteLine(new StackTrace()); - } - } - catch - { - // ignored - } - } - - m_CompiledBuffer = new byte[0]; - m_CompiledLength = 0; - - length = m_CompiledLength; - return m_CompiledBuffer; - } - - InternalCompile(compress); - } - - length = m_CompiledLength; - return m_CompiledBuffer; - } - } - - private void InternalCompile(bool compress) - { - if (m_Length == 0) - { - long streamLen = m_Stream.Length; - - m_Stream.Seek(1, SeekOrigin.Begin); - m_Stream.Write((ushort)streamLen); - } - else if (m_Stream.Length != m_Length) - { - int diff = (int)m_Stream.Length - m_Length; - - Console.WriteLine("Packet: 0x{0:X2}: Bad packet length! ({1}{2} bytes)", PacketID, diff >= 0 ? "+" : "", - diff); - } - - MemoryStream ms = m_Stream.UnderlyingStream; - - m_CompiledBuffer = ms.GetBuffer(); - int length = (int)ms.Length; - - if (compress) - { - byte[] buffer; - lock (m_CompressorBuffers) - { - buffer = m_CompressorBuffers.AcquireBuffer(); - } - - Compression.Compress(m_CompiledBuffer, 0, length, buffer, ref length); - - if (length <= 0) - { - Console.WriteLine("Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})", - PacketID, GetType().Name, length); - using (StreamWriter op = new StreamWriter("compression_overflow.log", true)) - { - op.WriteLine("{0} Warning: Compression buffer overflowed on packet 0x{1:X2} ('{2}') (length={3})", - DateTime.UtcNow, PacketID, GetType().Name, length); - op.WriteLine(new StackTrace()); - } - } - else - { - m_CompiledLength = length; - - if (length > BufferSize || (m_State & State.Static) != 0) - { - m_CompiledBuffer = new byte[length]; - } - else - { - lock (m_Buffers) - { - m_CompiledBuffer = m_Buffers.AcquireBuffer(); - } - - m_State |= State.Buffered; - } - - Buffer.BlockCopy(buffer, 0, m_CompiledBuffer, 0, length); - - lock (m_CompressorBuffers) - { - m_CompressorBuffers.ReleaseBuffer(buffer); - } - } - } - else if (length > 0) - { - byte[] old = m_CompiledBuffer; - m_CompiledLength = length; - - if (length > BufferSize || (m_State & State.Static) != 0) - { - m_CompiledBuffer = new byte[length]; - } - else - { - lock (m_Buffers) - { - m_CompiledBuffer = m_Buffers.AcquireBuffer(); - } - - m_State |= State.Buffered; - } - - Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, length); - } - - PacketWriter.ReleaseInstance(m_Stream); - m_Stream = null; - } - - [Flags] - private enum State - { - Inactive = 0x00, - Static = 0x01, - Acquired = 0x02, - Accessed = 0x04, - Buffered = 0x08, - Warned = 0x10 - } - } } diff --git a/Server/Network/SendQueue.cs b/Server/Network/SendQueue.cs index 78f98fe87..2b0364e0e 100644 --- a/Server/Network/SendQueue.cs +++ b/Server/Network/SendQueue.cs @@ -18,208 +18,34 @@ * ***************************************************************************/ -using System; -using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Threading.Tasks; namespace Server.Network { - public class SendQueue + public class SendQueue { - private const int PendingCap = 256 * 1024; - - private static int m_CoalesceBufferSize = 512; - private static BufferPool m_UnusedBuffers = new BufferPool("Coalesced", 2048, m_CoalesceBufferSize); - - private Gram _buffered; - - private Queue _pending; + private BlockingCollection m_Queue = new BlockingCollection(new ConcurrentQueue()); public SendQueue() { - _pending = new Queue(); } - public static int CoalesceBufferSize + public void Enqueue(T t) { - get => m_CoalesceBufferSize; - set - { - if (m_CoalesceBufferSize == value) - return; - - BufferPool old = m_UnusedBuffers; - - lock (old) - { - m_UnusedBuffers?.Free(); - - m_CoalesceBufferSize = value; - m_UnusedBuffers = new BufferPool("Coalesced", 2048, m_CoalesceBufferSize); - } - } + m_Queue.Add(t); } - public bool IsFlushReady => _pending.Count == 0 && _buffered != null; - - public bool IsEmpty => _pending.Count == 0 && _buffered == null; - - public static byte[] AcquireBuffer() + public Task DequeueAsync() { - lock (m_UnusedBuffers) - { - return m_UnusedBuffers.AcquireBuffer(); - } + TaskCompletionSource taskCompletion = new TaskCompletionSource(); + Task.Run(() => taskCompletion.SetResult(Dequeue())); + return taskCompletion.Task; } - public static void ReleaseBuffer(byte[] buffer) + public T Dequeue() { - lock (m_UnusedBuffers) - { - if (buffer != null && buffer.Length == m_CoalesceBufferSize) - m_UnusedBuffers.ReleaseBuffer(buffer); - } - } - - public Gram CheckFlushReady() - { - Gram gram = _buffered; - _pending.Enqueue(_buffered); - _buffered = null; - return gram; - } - - public Gram Dequeue() - { - Gram gram = null; - - if (_pending.Count > 0) - { - _pending.Dequeue().Release(); - - if (_pending.Count > 0) gram = _pending.Peek(); - } - - return gram; - } - - public Gram Enqueue(byte[] buffer, int length) - { - return Enqueue(buffer, 0, length); - } - - public Gram Enqueue(byte[] buffer, int offset, int length) - { - if (buffer == null) throw new ArgumentNullException("buffer"); - - if (!(offset >= 0 && offset < buffer.Length)) - throw new ArgumentOutOfRangeException("offset", offset, - "Offset must be greater than or equal to zero and less than the size of the buffer."); - if (length < 0 || length > buffer.Length) - throw new ArgumentOutOfRangeException("length", length, - "Length cannot be less than zero or greater than the size of the buffer."); - if (buffer.Length - offset < length) - throw new ArgumentException("Offset and length do not point to a valid segment within the buffer."); - - int existingBytes = _pending.Count * m_CoalesceBufferSize + (_buffered?.Length ?? 0); - - if (existingBytes + length > PendingCap) throw new CapacityExceededException(); - - Gram gram = null; - - while (length > 0) - { - if (_buffered == null) _buffered = Gram.Acquire(); - - int bytesWritten = _buffered.Write(buffer, offset, length); - - offset += bytesWritten; - length -= bytesWritten; - - if (_buffered.IsFull) - { - if (_pending.Count == 0) gram = _buffered; - - _pending.Enqueue(_buffered); - _buffered = null; - } - } - - return gram; - } - - public void Clear() - { - if (_buffered != null) - { - _buffered.Release(); - _buffered = null; - } - - while (_pending.Count > 0) _pending.Dequeue().Release(); - } - - public class Gram - { - private static Stack _pool = new Stack(); - - private Gram() - { - } - - public byte[] Buffer{ get; private set; } - - public int Length{ get; private set; } - - public int Available => Buffer.Length - Length; - - public bool IsFull => Length == Buffer.Length; - - public static Gram Acquire() - { - lock (_pool) - { - Gram gram; - - if (_pool.Count > 0) - gram = _pool.Pop(); - else - gram = new Gram(); - - gram.Buffer = AcquireBuffer(); - gram.Length = 0; - - return gram; - } - } - - public int Write(byte[] buffer, int offset, int length) - { - int write = Math.Min(length, Available); - - System.Buffer.BlockCopy(buffer, offset, Buffer, Length, write); - - Length += write; - - return write; - } - - public void Release() - { - lock (_pool) - { - _pool.Push(this); - ReleaseBuffer(Buffer); - } - } + return m_Queue.Take(); } } - - [Serializable] - public sealed class CapacityExceededException : Exception - { - public CapacityExceededException() - : base("Too much data pending.") - { - } - } -} \ No newline at end of file +} diff --git a/Server/Network/SocketExtensions.cs b/Server/Network/SocketExtensions.cs new file mode 100644 index 000000000..4eaf373d6 --- /dev/null +++ b/Server/Network/SocketExtensions.cs @@ -0,0 +1,57 @@ +/*************************************************************************** + * SocketExtensions.cs + * ------------------- + * begin : August 2, 2019 + * copyright : (C) The ModernUO Team + * email : hi@modernuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Buffers; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace Server.Network +{ + public static class SocketExtensions + { + public static Task ReceiveAsync(this Socket socket, Memory memory, SocketFlags socketFlags) + { + return SocketTaskExtensions.ReceiveAsync(socket, GetArray(memory), socketFlags); + } + + public static ArraySegment GetArray(this Memory memory) + { + return ((ReadOnlyMemory)memory).GetArray(); + } + + public static ArraySegment GetArray(this ReadOnlyMemory memory) + { + if (MemoryMarshal.TryGetArray(memory, out var result)) + return result; + + throw new InvalidOperationException("Buffer backed by array was expected"); + } + + public static ArraySegment GetArray(this ReadOnlySequence memory) + { + if (SequenceMarshal.TryGetArray(memory, out var result)) + return result; + + throw new InvalidOperationException("Buffer backed by array was expected"); + } + } +} diff --git a/Server/Network/StaticPacketHandlers.cs b/Server/Network/StaticPacketHandlers.cs index ff09ffd50..b2c710581 100644 --- a/Server/Network/StaticPacketHandlers.cs +++ b/Server/Network/StaticPacketHandlers.cs @@ -1,3 +1,23 @@ +/*************************************************************************** + * StaticPacketHandlers.cs + * ------------------- + * begin : March 15, 2019 + * copyright : (C) The ModernUO Team + * email : hi@modernuo.com + * + * $Id$ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + using System.Collections.Concurrent; namespace Server.Network diff --git a/Server/Persistence/DualSaveStrategy.cs b/Server/Persistence/DualSaveStrategy.cs index cd93949f3..8e9ce9785 100644 --- a/Server/Persistence/DualSaveStrategy.cs +++ b/Server/Persistence/DualSaveStrategy.cs @@ -26,17 +26,17 @@ namespace Server { public override string Name => "Dual"; - public override void Save(SaveMetrics metrics, bool permitBackgroundWrite) + public override void Save(bool permitBackgroundWrite) { PermitBackgroundWrite = permitBackgroundWrite; - Thread saveThread = new Thread(delegate() { SaveItems(metrics); }); + Thread saveThread = new Thread(delegate() { SaveItems(); }); saveThread.Name = "Item Save Subset"; saveThread.Start(); - SaveMobiles(metrics); - SaveGuilds(metrics); + SaveMobiles(); + SaveGuilds(); saveThread.Join(); diff --git a/Server/Persistence/DynamicSaveStrategy.cs b/Server/Persistence/DynamicSaveStrategy.cs index 384d6f506..0132c1f52 100644 --- a/Server/Persistence/DynamicSaveStrategy.cs +++ b/Server/Persistence/DynamicSaveStrategy.cs @@ -37,7 +37,6 @@ namespace Server private BlockingCollection _itemThreadWriters; - private SaveMetrics _metrics; private SequentialFileWriter _mobileData, _mobileIndex; private BlockingCollection _mobileThreadWriters; @@ -51,10 +50,8 @@ namespace Server public override string Name => "Dynamic"; - public override void Save(SaveMetrics metrics, bool permitBackgroundWrite) + public override void Save(bool permitBackgroundWrite) { - _metrics = metrics; - OpenFiles(); Task[] saveTasks = new Task[3]; @@ -130,8 +127,6 @@ namespace Server if (item.Decays && item.Parent == null && item.Map != Map.Internal && DateTime.UtcNow > item.LastMoved + item.DecayTime) _decayBag.Add(item); - _metrics?.OnItemSaved(size); - return writer; }, writer => @@ -165,8 +160,6 @@ namespace Server writer.QueueForIndex(mobile, size); - _metrics?.OnMobileSaved(size); - return writer; }, writer => @@ -201,8 +194,6 @@ namespace Server writer.QueueForIndex(guild, size); - _metrics?.OnGuildSaved(size); - return writer; }, writer => @@ -226,14 +217,14 @@ namespace Server private void OpenFiles() { - _itemData = new SequentialFileWriter(World.ItemDataPath, _metrics); - _itemIndex = new SequentialFileWriter(World.ItemIndexPath, _metrics); + _itemData = new SequentialFileWriter(World.ItemDataPath); + _itemIndex = new SequentialFileWriter(World.ItemIndexPath); - _mobileData = new SequentialFileWriter(World.MobileDataPath, _metrics); - _mobileIndex = new SequentialFileWriter(World.MobileIndexPath, _metrics); + _mobileData = new SequentialFileWriter(World.MobileDataPath); + _mobileIndex = new SequentialFileWriter(World.MobileIndexPath); - _guildData = new SequentialFileWriter(World.GuildDataPath, _metrics); - _guildIndex = new SequentialFileWriter(World.GuildIndexPath, _metrics); + _guildData = new SequentialFileWriter(World.GuildDataPath); + _guildIndex = new SequentialFileWriter(World.GuildIndexPath); WriteCount(_itemIndex, World.Items.Count); WriteCount(_mobileIndex, World.Mobiles.Count); diff --git a/Server/Persistence/FileQueue.cs b/Server/Persistence/FileQueue.cs index 21c44eda5..52e670cf4 100644 --- a/Server/Persistence/FileQueue.cs +++ b/Server/Persistence/FileQueue.cs @@ -19,9 +19,9 @@ ***************************************************************************/ using System; +using System.Buffers; using System.Collections.Generic; using System.Threading; -using Server.Network; namespace Server { @@ -30,7 +30,6 @@ namespace Server public sealed class FileQueue : IDisposable { private static int bufferSize; - private static BufferPool bufferPool; private Chunk[] active; private int activeCount; @@ -47,15 +46,14 @@ namespace Server static FileQueue() { bufferSize = FileOperations.BufferSize; - bufferPool = new BufferPool("File Buffers", 64, bufferSize); } public FileQueue(int concurrentWrites, FileCommitCallback callback) { if (concurrentWrites < 1) throw new ArgumentOutOfRangeException("concurrentWrites"); - if (bufferSize < 1) throw new ArgumentOutOfRangeException("bufferSize"); - if (callback == null) throw new ArgumentNullException("callback"); + if (bufferSize < 1) + throw new ArgumentOutOfRangeException("bufferSize"); syncRoot = new object(); @@ -139,7 +137,7 @@ namespace Server { if (active[slot] != chunk) throw new ArgumentException(); - bufferPool.ReleaseBuffer(chunk.Buffer); + ArrayPool.Shared.Return(chunk.Buffer); if (pending.Count > 0) { @@ -172,7 +170,8 @@ namespace Server while (size > 0) { - if (buffered.buffer == null) buffered.buffer = bufferPool.AcquireBuffer(); + if (buffered.buffer == null) + buffered.buffer = ArrayPool.Shared.Rent(bufferSize); byte[] page = buffered.buffer; // buffer page int pageSpace = page.Length - buffered.length; // available bytes in page @@ -229,4 +228,4 @@ namespace Server public int length; } } -} \ No newline at end of file +} diff --git a/Server/Persistence/ParallelSaveStrategy.cs b/Server/Persistence/ParallelSaveStrategy.cs index 02132c602..0e47fd454 100644 --- a/Server/Persistence/ParallelSaveStrategy.cs +++ b/Server/Persistence/ParallelSaveStrategy.cs @@ -38,7 +38,6 @@ namespace Server private SequentialFileWriter itemData, itemIndex; - private SaveMetrics metrics; private SequentialFileWriter mobileData, mobileIndex; private int processorCount; @@ -57,10 +56,8 @@ namespace Server return processorCount - 1; } - public override void Save(SaveMetrics metrics, bool permitBackgroundWrite) + public override void Save(bool permitBackgroundWrite) { - this.metrics = metrics; - OpenFiles(); consumers = new Consumer[GetThreadCount()]; @@ -121,14 +118,14 @@ namespace Server private void OpenFiles() { - itemData = new SequentialFileWriter(World.ItemDataPath, metrics); - itemIndex = new SequentialFileWriter(World.ItemIndexPath, metrics); + itemData = new SequentialFileWriter(World.ItemDataPath); + itemIndex = new SequentialFileWriter(World.ItemIndexPath); - mobileData = new SequentialFileWriter(World.MobileDataPath, metrics); - mobileIndex = new SequentialFileWriter(World.MobileIndexPath, metrics); + mobileData = new SequentialFileWriter(World.MobileDataPath); + mobileIndex = new SequentialFileWriter(World.MobileIndexPath); - guildData = new SequentialFileWriter(World.GuildDataPath, metrics); - guildIndex = new SequentialFileWriter(World.GuildIndexPath, metrics); + guildData = new SequentialFileWriter(World.GuildDataPath); + guildIndex = new SequentialFileWriter(World.GuildIndexPath); WriteCount(itemIndex, World.Items.Count); WriteCount(mobileIndex, World.Mobiles.Count); @@ -176,9 +173,7 @@ namespace Server private void Save(Item item, BinaryMemoryWriter writer) { - int length = writer.CommitTo(itemData, itemIndex, item.m_TypeRef, item.Serial); - - metrics?.OnItemSaved(length); + writer.CommitTo(itemData, itemIndex, item.m_TypeRef, item.Serial); if (item.Decays && item.Parent == null && item.Map != Map.Internal && DateTime.UtcNow > item.LastMoved + item.DecayTime) _decayQueue.Enqueue(item); @@ -186,16 +181,12 @@ namespace Server private void Save(Mobile mob, BinaryMemoryWriter writer) { - int length = writer.CommitTo(mobileData, mobileIndex, mob.m_TypeRef, mob.Serial); - - metrics?.OnMobileSaved(length); + writer.CommitTo(mobileData, mobileIndex, mob.m_TypeRef, mob.Serial); } private void Save(BaseGuild guild, BinaryMemoryWriter writer) { - int length = writer.CommitTo(guildData, guildIndex, 0, guild.Id); - - metrics?.OnGuildSaved(length); + writer.CommitTo(guildData, guildIndex, 0, guild.Id); } private bool Enqueue(ISerializable value) diff --git a/Server/Persistence/SaveMetrics.cs b/Server/Persistence/SaveMetrics.cs deleted file mode 100644 index b1384ffde..000000000 --- a/Server/Persistence/SaveMetrics.cs +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************** - * SaveMetrics.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System; -using System.Diagnostics; - -namespace Server -{ - public sealed class SaveMetrics : IDisposable - { - private const string PerformanceCategoryName = "RunUO 2.1"; - private const string PerformanceCategoryDesc = "Performance counters for RunUO 2.1."; - - private bool isDisposed; - - private PerformanceCounter itemsPerSecond; - private PerformanceCounter mobilesPerSecond; - - private PerformanceCounter numberOfWorldSaves; - - private PerformanceCounter serializedBytesPerSecond; - private PerformanceCounter writtenBytesPerSecond; - - public SaveMetrics() - { - if (!PerformanceCounterCategory.Exists(PerformanceCategoryName)) - { - CounterCreationDataCollection counters = new CounterCreationDataCollection(); - - counters.Add(new CounterCreationData( - "Save - Count", - "Number of world saves.", - PerformanceCounterType.NumberOfItems32 - ) - ); - - counters.Add(new CounterCreationData( - "Save - Items/sec", - "Number of items saved per second.", - PerformanceCounterType.RateOfCountsPerSecond32 - ) - ); - - counters.Add(new CounterCreationData( - "Save - Mobiles/sec", - "Number of mobiles saved per second.", - PerformanceCounterType.RateOfCountsPerSecond32 - ) - ); - - counters.Add(new CounterCreationData( - "Save - Serialized bytes/sec", - "Amount of world-save bytes serialized per second.", - PerformanceCounterType.RateOfCountsPerSecond32 - ) - ); - - counters.Add(new CounterCreationData( - "Save - Written bytes/sec", - "Amount of world-save bytes written to disk per second.", - PerformanceCounterType.RateOfCountsPerSecond32 - ) - ); - - PerformanceCounterCategory.Create(PerformanceCategoryName, PerformanceCategoryDesc, - PerformanceCounterCategoryType.SingleInstance, counters); - } - - numberOfWorldSaves = new PerformanceCounter(PerformanceCategoryName, "Save - Count", false); - - itemsPerSecond = new PerformanceCounter(PerformanceCategoryName, "Save - Items/sec", false); - mobilesPerSecond = new PerformanceCounter(PerformanceCategoryName, "Save - Mobiles/sec", false); - - serializedBytesPerSecond = new PerformanceCounter(PerformanceCategoryName, "Save - Serialized bytes/sec", false); - writtenBytesPerSecond = new PerformanceCounter(PerformanceCategoryName, "Save - Written bytes/sec", false); - - // increment number of world saves - numberOfWorldSaves.Increment(); - } - - public void Dispose() - { - if (!isDisposed) - { - isDisposed = true; - - numberOfWorldSaves.Dispose(); - - itemsPerSecond.Dispose(); - mobilesPerSecond.Dispose(); - - serializedBytesPerSecond.Dispose(); - writtenBytesPerSecond.Dispose(); - } - } - - public void OnItemSaved(int numberOfBytes) - { - itemsPerSecond.Increment(); - - serializedBytesPerSecond.IncrementBy(numberOfBytes); - } - - public void OnMobileSaved(int numberOfBytes) - { - mobilesPerSecond.Increment(); - - serializedBytesPerSecond.IncrementBy(numberOfBytes); - } - - public void OnGuildSaved(int numberOfBytes) - { - serializedBytesPerSecond.IncrementBy(numberOfBytes); - } - - public void OnFileWritten(int numberOfBytes) - { - writtenBytesPerSecond.IncrementBy(numberOfBytes); - } - } -} diff --git a/Server/Persistence/SaveStrategy.cs b/Server/Persistence/SaveStrategy.cs index 9da97f2e5..dbf7f6938 100644 --- a/Server/Persistence/SaveStrategy.cs +++ b/Server/Persistence/SaveStrategy.cs @@ -40,7 +40,7 @@ namespace Server return new StandardSaveStrategy(); } - public abstract void Save(SaveMetrics metrics, bool permitBackgroundWrite); + public abstract void Save(bool permitBackgroundWrite); public abstract void ProcessDecay(); } diff --git a/Server/Persistence/SequentialFileWriter.cs b/Server/Persistence/SequentialFileWriter.cs index be4b569e9..24af4c618 100644 --- a/Server/Persistence/SequentialFileWriter.cs +++ b/Server/Persistence/SequentialFileWriter.cs @@ -28,16 +28,12 @@ namespace Server private FileQueue fileQueue; private FileStream fileStream; - private SaveMetrics metrics; - private AsyncCallback writeCallback; - public SequentialFileWriter(string path, SaveMetrics metrics) + public SequentialFileWriter(string path) { if (path == null) throw new ArgumentNullException("path"); - this.metrics = metrics; - fileStream = FileOperations.OpenSequentialStream(path, FileMode.Create, FileAccess.Write, FileShare.None); fileQueue = new FileQueue( @@ -66,8 +62,6 @@ namespace Server { fileStream.Write(chunk.Buffer, chunk.Offset, chunk.Size); - metrics?.OnFileWritten(chunk.Size); - chunk.Commit(); } else @@ -84,8 +78,6 @@ namespace Server fileStream.EndWrite(asyncResult); - metrics?.OnFileWritten(chunk.Size); - chunk.Commit(); } diff --git a/Server/Persistence/StandardSaveStrategy.cs b/Server/Persistence/StandardSaveStrategy.cs index 0894434a7..14df9b994 100644 --- a/Server/Persistence/StandardSaveStrategy.cs +++ b/Server/Persistence/StandardSaveStrategy.cs @@ -47,20 +47,20 @@ namespace Server protected bool UseSequentialWriters => SaveType == SaveOption.Normal || !PermitBackgroundWrite; - public override void Save(SaveMetrics metrics, bool permitBackgroundWrite) + public override void Save(bool permitBackgroundWrite) { PermitBackgroundWrite = permitBackgroundWrite; - SaveMobiles(metrics); - SaveItems(metrics); - SaveGuilds(metrics); + SaveMobiles(); + SaveItems(); + SaveGuilds(); if (permitBackgroundWrite && UseSequentialWriters ) //If we're permitted to write in the background, but we don't anyways, then notify. World.NotifyDiskWriteComplete(); } - protected void SaveMobiles(SaveMetrics metrics) + protected void SaveMobiles() { Dictionary mobiles = World.Mobiles; @@ -92,8 +92,6 @@ namespace Server m.Serialize(bin); - metrics?.OnMobileSaved((int)(bin.Position - start)); - idx.Write((int)(bin.Position - start)); m.FreeCache(); @@ -109,7 +107,7 @@ namespace Server bin.Close(); } - protected void SaveItems(SaveMetrics metrics) + protected void SaveItems() { Dictionary items = World.Items; @@ -147,8 +145,6 @@ namespace Server item.Serialize(bin); - metrics?.OnItemSaved((int)(bin.Position - start)); - idx.Write((int)(bin.Position - start)); item.FreeCache(); @@ -163,7 +159,7 @@ namespace Server bin.Close(); } - protected void SaveGuilds(SaveMetrics metrics) + protected void SaveGuilds() { GenericWriter idx; GenericWriter bin; @@ -190,8 +186,6 @@ namespace Server guild.Serialize(bin); - metrics?.OnGuildSaved((int)(bin.Position - start)); - idx.Write((int)(bin.Position - start)); } diff --git a/Server/Properties/PublishProfiles/Linux-Portable.pubxml b/Server/Properties/PublishProfiles/Linux-Portable.pubxml new file mode 100644 index 000000000..06a48d905 --- /dev/null +++ b/Server/Properties/PublishProfiles/Linux-Portable.pubxml @@ -0,0 +1,16 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.0 + ../ + linux-x64 + false + <_IsPortable>true + + diff --git a/Server/Properties/PublishProfiles/Linux.pubxml b/Server/Properties/PublishProfiles/Linux.pubxml new file mode 100644 index 000000000..52201225c --- /dev/null +++ b/Server/Properties/PublishProfiles/Linux.pubxml @@ -0,0 +1,16 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.0 + ../ + linux-x64 + true + <_IsPortable>false + + diff --git a/Server/Properties/PublishProfiles/OSX.pubxml b/Server/Properties/PublishProfiles/OSX.pubxml new file mode 100644 index 000000000..969dea22d --- /dev/null +++ b/Server/Properties/PublishProfiles/OSX.pubxml @@ -0,0 +1,16 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.0 + ../ + osx-x64 + false + <_IsPortable>true + + diff --git a/Server/Properties/PublishProfiles/Windows.pubxml b/Server/Properties/PublishProfiles/Windows.pubxml new file mode 100644 index 000000000..c74181459 --- /dev/null +++ b/Server/Properties/PublishProfiles/Windows.pubxml @@ -0,0 +1,16 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.0 + ../ + win-x64 + false + <_IsPortable>true + + diff --git a/Server/ScriptCompiler.cs b/Server/ScriptCompiler.cs index 8ecf26c7b..4457b6232 100644 --- a/Server/ScriptCompiler.cs +++ b/Server/ScriptCompiler.cs @@ -19,538 +19,37 @@ ***************************************************************************/ using System; -using System.CodeDom.Compiler; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Reflection; -using System.Security.Cryptography; -using System.Text; +#if NETCORE +using System.Runtime.Loader; +#endif namespace Server { public static class ScriptCompiler { - private static List m_AdditionalReferences = new List(); - private static Dictionary m_TypeCaches = new Dictionary(); private static TypeCache m_NullCache; - public static Assembly[] Assemblies{ get; set; } + public static Assembly[] Assemblies { get; set; } - public static string[] GetReferenceAssemblies() + public static string ScriptsPath = EnsureDirectory("Assemblies"); + + public static bool LoadScripts(string path = null) { - List list = new List(); + string[] files = Directory.GetFiles(path ?? ScriptsPath, "*.dll"); - string path = Path.Combine(Core.BaseDirectory, "Data/Assemblies.cfg"); + Assemblies = new Assembly[files.Length]; - if (File.Exists(path)) - using (StreamReader ip = new StreamReader(path)) - { - string line; - - while ((line = ip.ReadLine()) != null) - if (line.Length > 0 && !line.StartsWith("#")) - list.Add(line); - } - - list.Add(Core.ExePath); - - list.AddRange(m_AdditionalReferences); - - return list.ToArray(); - } - - public static string GetCompilerOptions(bool debug) - { - StringBuilder sb = null; - - AppendCompilerOption(ref sb, "/unsafe"); - - if (!debug) - AppendCompilerOption(ref sb, "/optimize"); - -#if MONO - AppendCompilerOption( ref sb, "/d:MONO" ); + for (int i = 0; i < files.Length; i++) +#if NETCORE + Assemblies[i] = AssemblyLoadContext.Default.LoadFromAssemblyPath(files[i]); +#else + Assemblies[i] = Assembly.LoadFrom(files[i]); #endif - if (Core.Is64Bit) - AppendCompilerOption(ref sb, "/d:x64"); - -#if NEWTIMERS - AppendCompilerOption(ref sb, "/d:NEWTIMERS"); -#endif - - return sb?.ToString(); - } - - private static void AppendCompilerOption(ref StringBuilder sb, string define) - { - if (sb == null) - sb = new StringBuilder(); - else - sb.Append(' '); - - sb.Append(define); - } - - private static byte[] GetHashCode(string compiledFile, string[] scriptFiles, bool debug) - { - using (MemoryStream ms = new MemoryStream()) - { - using (BinaryWriter bin = new BinaryWriter(ms)) - { - FileInfo fileInfo = new FileInfo(compiledFile); - - bin.Write(fileInfo.LastWriteTimeUtc.Ticks); - - foreach (string scriptFile in scriptFiles) - { - fileInfo = new FileInfo(scriptFile); - - bin.Write(fileInfo.LastWriteTimeUtc.Ticks); - } - - bin.Write(debug); - bin.Write(Core.Version.ToString()); - - ms.Position = 0; - - using (SHA1 sha1 = SHA1.Create()) - { - return sha1.ComputeHash(ms); - } - } - } - } - - public static bool CompileCSScripts(out Assembly assembly, bool cache = true, bool debug = false) - { - Console.Write("Scripts: Compiling C# scripts..."); - string[] files = GetScripts("*.cs"); - - if (files.Length == 0) - { - Console.WriteLine("no files found."); - assembly = null; - return true; - } - - if (File.Exists("Scripts/Output/Scripts.CS.dll")) - if (cache && File.Exists("Scripts/Output/Scripts.CS.hash")) - try - { - byte[] hashCode = GetHashCode("Scripts/Output/Scripts.CS.dll", files, debug); - - using (FileStream fs = new FileStream("Scripts/Output/Scripts.CS.hash", FileMode.Open, - FileAccess.Read, FileShare.Read)) - { - using (BinaryReader bin = new BinaryReader(fs)) - { - byte[] bytes = bin.ReadBytes(hashCode.Length); - - if (bytes.Length == hashCode.Length) - { - bool valid = true; - - for (int i = 0; i < bytes.Length; ++i) - if (bytes[i] != hashCode[i]) - { - valid = false; - break; - } - - if (valid) - { - assembly = Assembly.LoadFrom("Scripts/Output/Scripts.CS.dll"); - - if (!m_AdditionalReferences.Contains(assembly.Location)) - m_AdditionalReferences.Add(assembly.Location); - - Console.WriteLine("done (cached)"); - - return true; - } - } - } - } - } - catch - { - // ignored - } - - DeleteFiles("Scripts.CS*.dll"); - - using (CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp")) - { - string path = GetUnusedPath("Scripts.CS"); - - CompilerParameters parms = new CompilerParameters(GetReferenceAssemblies(), path, debug); - - string options = GetCompilerOptions(debug); - - if (options != null) - parms.CompilerOptions = options; - - if (Core.HaltOnWarning) - parms.WarningLevel = 4; - - if (Core.Unix) - { - parms.CompilerOptions = $"{parms.CompilerOptions} /nowarn:169,219,414 /recurse:Scripts/*.cs"; - files = new string[0]; - } - - CompilerResults results = provider.CompileAssemblyFromFile(parms, files); - m_AdditionalReferences.Add(path); - - Display(results); - - if (results.Errors.Count > 0) - { - if (!Core.Unix) - { - assembly = null; - return false; - } - - foreach (CompilerError err in results.Errors) - if (!err.IsWarning) - { - assembly = null; - return false; - } - } - - - if (cache && Path.GetFileName(path) == "Scripts.CS.dll") - try - { - byte[] hashCode = GetHashCode(path, files, debug); - - using (FileStream fs = new FileStream("Scripts/Output/Scripts.CS.hash", FileMode.Create, - FileAccess.Write, FileShare.None)) - { - using (BinaryWriter bin = new BinaryWriter(fs)) - { - bin.Write(hashCode, 0, hashCode.Length); - } - } - } - catch - { - // ignored - } - - assembly = results.CompiledAssembly; - return true; - } - } - - public static bool CompileVBScripts(out Assembly assembly, bool cache = true, bool debug = false) - { - Console.Write("Scripts: Compiling VB.NET scripts..."); - string[] files = GetScripts("*.vb"); - - if (files.Length == 0) - { - Console.WriteLine("no files found."); - assembly = null; - return true; - } - - if (File.Exists("Scripts/Output/Scripts.VB.dll")) - if (cache && File.Exists("Scripts/Output/Scripts.VB.hash")) - { - byte[] hashCode = GetHashCode("Scripts/Output/Scripts.VB.dll", files, debug); - - try - { - using (FileStream fs = new FileStream("Scripts/Output/Scripts.VB.hash", FileMode.Open, - FileAccess.Read, FileShare.Read)) - { - using (BinaryReader bin = new BinaryReader(fs)) - { - byte[] bytes = bin.ReadBytes(hashCode.Length); - - if (bytes.Length == hashCode.Length) - { - bool valid = true; - - for (int i = 0; i < bytes.Length; ++i) - if (bytes[i] != hashCode[i]) - { - valid = false; - break; - } - - if (valid) - { - assembly = Assembly.LoadFrom("Scripts/Output/Scripts.VB.dll"); - - if (!m_AdditionalReferences.Contains(assembly.Location)) - m_AdditionalReferences.Add(assembly.Location); - - Console.WriteLine("done (cached)"); - - return true; - } - } - } - } - } - catch - { - // ignored - } - } - - DeleteFiles("Scripts.VB*.dll"); - - using (CodeDomProvider provider = CodeDomProvider.CreateProvider("VisualBasic")) - { - string path = GetUnusedPath("Scripts.VB"); - - CompilerParameters parms = new CompilerParameters(GetReferenceAssemblies(), path, debug); - - string options = GetCompilerOptions(debug); - - if (options != null) - parms.CompilerOptions = options; - - if (Core.HaltOnWarning) - parms.WarningLevel = 4; - - if (Core.Unix) - { - parms.CompilerOptions = $"{parms.CompilerOptions} /nowarn:169,219,414 /recurse:Scripts/*.vb"; - files = new string[0]; - } - - CompilerResults results = provider.CompileAssemblyFromFile(parms, files); - m_AdditionalReferences.Add(path); - - Display(results); - - if (results.Errors.Count > 0) - { - if (!Core.Unix) - { - assembly = null; - return false; - } - - foreach (CompilerError err in results.Errors) - if (!err.IsWarning) - { - assembly = null; - return false; - } - } - - if (cache && Path.GetFileName(path) == "Scripts.VB.dll") - try - { - byte[] hashCode = GetHashCode(path, files, debug); - - using (FileStream fs = new FileStream("Scripts/Output/Scripts.VB.hash", FileMode.Create, - FileAccess.Write, FileShare.None)) - { - using (BinaryWriter bin = new BinaryWriter(fs)) - { - bin.Write(hashCode, 0, hashCode.Length); - } - } - } - catch - { - // ignored - } - - assembly = results.CompiledAssembly; - return true; - } - } - - public static void Display(CompilerResults results) - { - if (results.Errors.Count > 0) - { - Dictionary> errors = - new Dictionary>(results.Errors.Count, StringComparer.OrdinalIgnoreCase); - Dictionary> warnings = - new Dictionary>(results.Errors.Count, StringComparer.OrdinalIgnoreCase); - - foreach (CompilerError e in results.Errors) - { - string file = e.FileName; - - // Ridiculous. FileName is null if the warning/error is internally generated in csc. - if (string.IsNullOrEmpty(file)) - { - Console.WriteLine("ScriptCompiler: {0}: {1}", e.ErrorNumber, e.ErrorText); - continue; - } - - Dictionary> table = e.IsWarning ? warnings : errors; - - if (!table.TryGetValue(file, out List list)) - table[file] = list = new List(); - - list.Add(e); - } - - Console.WriteLine(errors.Count > 0 ? "failed ({0} errors, {1} warnings)" : "done ({0} errors, {1} warnings)", - errors.Count, warnings.Count); - - string scriptRoot = - Path.GetFullPath(Path.Combine(Core.BaseDirectory, "Scripts" + Path.DirectorySeparatorChar)); - Uri scriptRootUri = new Uri(scriptRoot); - - Utility.PushColor(ConsoleColor.Yellow); - - if (warnings.Count > 0) - Console.WriteLine("Warnings:"); - - foreach (KeyValuePair> kvp in warnings) - { - string fileName = kvp.Key; - List list = kvp.Value; - - string fullPath = Path.GetFullPath(fileName); - string usedPath = - Uri.UnescapeDataString(scriptRootUri.MakeRelativeUri(new Uri(fullPath)).OriginalString); - - Console.WriteLine(" + {0}:", usedPath); - - Utility.PushColor(ConsoleColor.DarkYellow); - - foreach (CompilerError e in list) - Console.WriteLine(" {0}: Line {1}: {2}", e.ErrorNumber, e.Line, e.ErrorText); - - Utility.PopColor(); - } - - Utility.PopColor(); - - Utility.PushColor(ConsoleColor.Red); - - if (errors.Count > 0) - Console.WriteLine("Errors:"); - - foreach (KeyValuePair> kvp in errors) - { - string fileName = kvp.Key; - List list = kvp.Value; - - string fullPath = Path.GetFullPath(fileName); - string usedPath = - Uri.UnescapeDataString(scriptRootUri.MakeRelativeUri(new Uri(fullPath)).OriginalString); - - Console.WriteLine(" + {0}:", usedPath); - - Utility.PushColor(ConsoleColor.DarkRed); - - foreach (CompilerError e in list) - Console.WriteLine(" {0}: Line {1}: {2}", e.ErrorNumber, e.Line, e.ErrorText); - - Utility.PopColor(); - } - - Utility.PopColor(); - } - else - { - Console.WriteLine("done (0 errors, 0 warnings)"); - } - } - - public static string GetUnusedPath(string name) - { - string path = Path.Combine(Core.BaseDirectory, $"Scripts/Output/{name}.dll"); - - for (int i = 2; File.Exists(path) && i <= 1000; ++i) - path = Path.Combine(Core.BaseDirectory, $"Scripts/Output/{name}.{i}.dll"); - - return path; - } - - public static void DeleteFiles(string mask) - { - try - { - string[] files = Directory.GetFiles(Path.Combine(Core.BaseDirectory, "Scripts/Output"), mask); - - foreach (string file in files) - try - { - File.Delete(file); - } - catch - { - // ignored - } - } - catch - { - // ignored - } - } - - public static bool Compile(bool debug, bool cache = true) - { - EnsureDirectory("Scripts/"); - EnsureDirectory("Scripts/Output/"); - - if (m_AdditionalReferences.Count > 0) - m_AdditionalReferences.Clear(); - - List assemblies = new List(); - - if (CompileCSScripts(out Assembly assembly, cache, debug)) - { - if (assembly != null) - assemblies.Add(assembly); - } - else - { - return false; - } - - if (Core.VBdotNet) - { - if (CompileVBScripts(out Assembly vbAssembly, cache, debug)) - { - if (vbAssembly != null) - assemblies.Add(vbAssembly); - } - else - { - return false; - } - } - else - { - Console.WriteLine("Scripts: Skipping VB.NET Scripts...done (use -vb to enable)"); - } - - if (assemblies.Count == 0) - return false; - - Assemblies = assemblies.ToArray(); - - Console.Write("Scripts: Verifying..."); - - Stopwatch watch = Stopwatch.StartNew(); - - Core.VerifySerialization(); - - watch.Stop(); - - Console.WriteLine("done ({0} items, {1} mobiles) ({2:F2} seconds)", Core.ScriptItems, Core.ScriptMobiles, - watch.Elapsed.TotalSeconds); - - return true; + return files.Length > 0; } public static void Invoke(string method) @@ -618,32 +117,15 @@ namespace Server return type ?? GetTypeCache(Core.Assembly).GetTypeByName(name, ignoreCase); } - public static void EnsureDirectory(string dir) + public static string EnsureDirectory(string dir) { string path = Path.Combine(Core.BaseDirectory, dir); if (!Directory.Exists(path)) Directory.CreateDirectory(path); + + return path; } - - public static string[] GetScripts(string filter) - { - List list = new List(); - - GetScripts(list, Path.Combine(Core.BaseDirectory, "Scripts"), filter); - - return list.ToArray(); - } - - public static void GetScripts(List list, string path, string filter) - { - foreach (string dir in Directory.GetDirectories(path)) - GetScripts(list, dir, filter); - - list.AddRange(Directory.GetFiles(path, filter)); - } - - private delegate CompilerResults Compiler(bool debug); } public class TypeCache diff --git a/Server/Server.csproj b/Server/Server.csproj index 6fbb90173..9a38278a3 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -1,266 +1,48 @@  - - + - Debug - x86 - {0B33CEEB-88E1-49A6-8D7D-AF6A5A357087} Exe - false - RunUO - v4.7 - - - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - - Server - - runuo.ico + + + ModernUO + + 3.0.0 + Kamron Batman + ModernUO + ModernUO + 2019 + netcoreapp3.0 + true - - Server.Core + + NETCORE;NETSTANDARD - - true - ..\ - TRACE;DEBUG;NEWTIMERS + + TRACE;DEBUG true - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - false - false - - + false ..\ - TRACE;NEWTIMERS - true - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - false - false - - - true - ..\ - TRACE;DEBUG;NEWTIMERS - true - full + ..\ + + true x64 - prompt - MinimumRecommendedRules.ruleset - false - false - - ..\ - TRACE;NEWTIMERS + true - true - pdbonly + ..\ + ..\ + + true x64 - prompt - MinimumRecommendedRules.ruleset - false - false - - - ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 4.5 - true - + + ..\System.IO.Pipelines.dll + false + - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file + diff --git a/Server/Timer.cs b/Server/Timer.cs index 4c65848b9..510d2200c 100644 --- a/Server/Timer.cs +++ b/Server/Timer.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading; +using System.Threading.Tasks; using Server.Diagnostics; namespace Server @@ -587,5 +588,31 @@ namespace Server } #endregion + + private class DelayTaskTimer : Timer + { + private TaskCompletionSource m_TaskCompleter; + + public Task Task { get { return m_TaskCompleter.Task; } } + + public DelayTaskTimer(TimeSpan delay) : base(delay) + { + m_TaskCompleter = new TaskCompletionSource(); + } + + protected override void OnTick() + { + m_TaskCompleter.SetResult(this); + } + } + + public static Task Pause(int ms) => Pause(TimeSpan.FromMilliseconds(ms)); + + public static Task Pause(TimeSpan ms) + { + DelayTaskTimer t = new DelayTaskTimer(ms); + t.Start(); + return t.Task; + } } } diff --git a/Server/Utility.cs b/Server/Utility.cs index dd8420927..7e1abf6bf 100644 --- a/Server/Utility.cs +++ b/Server/Utility.cs @@ -968,16 +968,12 @@ namespace Server public static int GetAddressValue(IPAddress address) { -#pragma warning disable 618 - return (int)address.Address; -#pragma warning restore 618 + return BitConverter.ToInt32(address.GetAddressBytes(), 0); } public static long GetLongAddressValue(IPAddress address) { -#pragma warning disable 618 - return address.Address; -#pragma warning restore 618 + return BitConverter.ToInt64(address.GetAddressBytes(), 0); } #endregion diff --git a/Server/World.cs b/Server/World.cs index 7dff0cfdd..dafd0cbe6 100644 --- a/Server/World.cs +++ b/Server/World.cs @@ -107,8 +107,6 @@ namespace Server list[i].Send(p); p.Release(); - - NetState.FlushAll(); } public static void Broadcast(int hue, bool ascii, string format, params object[] args) @@ -622,7 +620,6 @@ namespace Server ++m_Saves; - NetState.FlushAll(); NetState.Pause(); WaitForWriteCompletion(); //Blocks Save until current disk flush is done. @@ -649,9 +646,7 @@ namespace Server Directory.CreateDirectory("Saves/Guilds/"); - /*using ( SaveMetrics metrics = new SaveMetrics() ) {*/ - strategy.Save(null, permitBackgroundWrite); - /*}*/ + strategy.Save(permitBackgroundWrite); try { @@ -818,4 +813,4 @@ namespace Server public int Length{ get; } } } -} \ No newline at end of file +} diff --git a/Server/packages.config b/Server/packages.config index 8e1dc78d7..3299dfcf0 100644 --- a/Server/packages.config +++ b/Server/packages.config @@ -1,13 +1,2 @@ - - - - - - - - - - - - - \ No newline at end of file + + \ No newline at end of file diff --git a/System.IO.Pipelines.dll b/System.IO.Pipelines.dll new file mode 100644 index 000000000..a09ab12a8 Binary files /dev/null and b/System.IO.Pipelines.dll differ