Initial commit
This commit is contained in:
commit
673b59c087
|
@ -0,0 +1,107 @@
|
|||
[*.*]
|
||||
dotnet_analyzer_diagnostic.severity = default
|
||||
|
||||
[*.{cs,vb}]
|
||||
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = error
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = error
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = error
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
dotnet_style_namespace_match_folder = true:suggestion
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
end_of_line = crlf
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = true:error
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
|
||||
dotnet_code_quality_unused_parameters = all:suggestion
|
||||
indent_style = space
|
||||
|
||||
[*.cs]
|
||||
csharp_using_directive_placement = outside_namespace:error
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
csharp_prefer_braces = true:error
|
||||
csharp_style_namespace_declarations = block_scoped:error
|
||||
csharp_style_prefer_method_group_conversion = true:silent
|
||||
csharp_style_prefer_top_level_statements = true:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
|
||||
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_prefer_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||
csharp_style_prefer_tuple_swap = true:suggestion
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||
dotnet_diagnostic.IDE0240.severity = silent
|
||||
dotnet_diagnostic.IDE0241.severity = silent
|
||||
dotnet_diagnostic.IDE0005.severity = error
|
|
@ -0,0 +1,11 @@
|
|||
# Generic
|
||||
bin
|
||||
obj
|
||||
.vs
|
||||
*.user
|
||||
|
||||
# Server
|
||||
/Src/HM5.Server/Logs
|
||||
|
||||
# Other
|
||||
/Res
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/Src/HM5.Server/bin/Debug/net6.0/HM5.Server.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/Src/HM5.Server",
|
||||
"stopAtEntry": false,
|
||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"build",
|
||||
"Src\\HM5.Server\\HM5.Server.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "test",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"test",
|
||||
"Src\\HM5.Test\\HM5.Test.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"group": "test",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33122.133
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HM5.Server", "Src\HM5.Server\HM5.Server.csproj", "{6FA95780-4890-46C7-9342-C5CC7E465EEF}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{43E1351B-28D0-45FE-A10A-545CFE650039}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MH5.Hook", "Src\HM5.Hook\MH5.Hook.vcxproj", "{57ABB826-E2F3-4908-BBBB-634C1A747CAA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HM5.Test", "Src\HM5.Test\HM5.Test.csproj", "{815C296D-7137-4DC6-96FF-4EC7432CEA1F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x64.Build.0 = Debug|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x86.Build.0 = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x64.ActiveCfg = Release|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x64.Build.0 = Release|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x86.Build.0 = Release|Win32
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {742A6A34-A300-4A5A-BD85-0CBCC7421E7A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,22 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DLC/@EntryIndexedValue">DLC</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OS/@EntryIndexedValue">OS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UTC/@EntryIndexedValue">UTC</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=categoryid/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=checkpointid/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=contractid/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=contractname/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Deinitialize/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=dlctokens/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Hitman/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Leaderboard/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=leaderboardid/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=leaderboardtype/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=levelindex/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=metacategories/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=startindex/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=startingoutfittoken/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=startingweapontoken/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=tabgroup/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Templated/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
|
@ -0,0 +1,188 @@
|
|||
# Hitman Absolution & Sniper Challenge Server
|
||||
This project emulates the server used by [Hitman: Absolution](https://store.steampowered.com/app/203140/Hitman_Absolution/) and the [Hitman: Sniper Challenge](https://steamcommunity.com/app/205930) and aims to restore all its features, including the Contracts feature.
|
||||
|
||||
# Getting started with the code
|
||||
In order to get started with the code, you need to have one of the following IDEs/editors installed:
|
||||
- Visual Studio 2022 (recommended)
|
||||
- Jetbrains Rider
|
||||
- Visual Studio Code with [vscode-solution-explorer](https://marketplace.visualstudio.com/items?itemName=fernandoescolar.vscode-solution-explorer) (recommended) and [C#](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) (required) installed.
|
||||
|
||||
On top of that, you need to have the [.NET SDK](https://dotnet.microsoft.com/en-us/download) for your OS installed (**not** the Runtime). The current project is based on .NET 6 LTS. You can however install any newer version you like.
|
||||
|
||||
## Getting starting with the hook
|
||||
The dinput8.dll hook is based on C++. It's beyond the scope of this document to explain how to compile that.
|
||||
|
||||
Once you have a x32 bit compiled version however, just drop it in the game folder along with the `hook.ini` file, make changes accordingly and start the game.
|
||||
|
||||
The hook supports both Hitman Absolution and Hitman Sniper Challenge depending on what you set in the `hook.ini`. Both allow to change the WebService URL. Hitman Absolution additionally allows you to skip the launcher.
|
||||
|
||||
The hook does not *crack* the games in any sort of way, you still need a legitimate copy in order to make use of this project.
|
||||
|
||||
# TODO
|
||||
In its current state, almost everything is reverse engineered and working with mocked data. But there are still a few things to figure out to restore the full experience.
|
||||
|
||||
## Server
|
||||
Phase 1:
|
||||
- ~~Figure out if game can actually POST a body~~ Nope! It can't.
|
||||
- ~~Figure out if GetFeaturedContract is actually used~~ Yes! After loading a level in Singleplayer. Will be shown on the in-game menu.
|
||||
- ~~Figure out if GetScoreComparison is acctually used~~ Yes! After loading a level in Singleplayer. Will be shown on the in-game HUD at the start of a level.
|
||||
- ~~Figure out if __metadata is even needed anywhere~~ Nope! Doesn't seem like it at least.
|
||||
- Figure out the MessageTemplateIds
|
||||
- Add Unit Tests based on real requests made by the game.
|
||||
|
||||
Phase 2:
|
||||
- Add EntityFramework and define a database schema
|
||||
- Replace all mocked with actual functionality
|
||||
|
||||
Phase 3:
|
||||
- Expose leaderboards through Web UI
|
||||
|
||||
## Hook
|
||||
- Figure out how to patch Hitman Sniper Challenge without triggering anti-debugging measures to skip launcher.
|
||||
- IDEA: Hook Steam Friends API to hook up own account system with friends.
|
||||
|
||||
# Notes about Ids in-game
|
||||
- UserId is almost always a 64-bit SteamId. However, to stay on the safe side all UserId-properties are treated as a String.
|
||||
- ContractId is considered a String in-game, since `Play_01` is used by the Contracts tutorial. This also has a effect on the LeaderboardId-properties, since that property can be a ContractId if the game wants to receive Contract-specific leaderboards.
|
||||
- IDEA: Use the hook to change these ID's to a negative number so the data model can keep using Integers.
|
||||
|
||||
# Documentation
|
||||
This section aims to explain the inner workings of the game in relation to the API endpoints that need to be reverse engineered.
|
||||
|
||||
## Startup Phase
|
||||
The first interesting calls happen here:
|
||||
- `ZOnlineManagerWindows::Update`
|
||||
- `ZOnlineManager::Update`
|
||||
- Called near a `_SteamAPI_RunCallbacks`-call
|
||||
- Contains a lot of timed events that call API endpoints regularly
|
||||
|
||||
If the webservice is not connected yet, it will call `ZOSWebService::Connect` followed by ` OSuite::ZOnlineSuite::CreateWebServiceClient`. In this function the configured service-url is passed to `OSuite::ZWebServiceClientManager::Create`.
|
||||
|
||||
Since there is no instance for this webservice yet, it will go into `OSuite::ZWebServiceClient::Initialize`. This function registers the `os_getStatus` and `os_$metadata` endpoints with a callback to `OSuite::ZWebServiceClient::InternalProbeResultCallback`. Eventually, `OSuite::ZWebServiceClient::ProbeAvailability` is called.
|
||||
|
||||
`OSuite::ZWebServiceClient::ProbeAvailability` will prepare the request for the `os_getStatus` endpoint and use `OSuite::ZWebServiceClient::InternalProbeCallback` as a callback. This callback is responsible for parsing the response.
|
||||
|
||||
If succesfully parsed, `OSuite::ZWebServiceClient::InternalProbeResultCallback` is called which will prepare the request to the `os_$metadata` endpoint with `OSuite::ZWebServiceClient::InternalMetadataCallback` as a callback.
|
||||
|
||||
Unlike the `os_getStatus` request, a cache is used for the metadata and `OSuite::ZAtomCache::Open<OSuite::ZOMetadata>` will be called to fetch the result from the endpoint. The response is parsed (see the notes about `OSuite::ZAtomCache::Open` below) and the `OSuite::ZWebServiceClient::InternalMetadataCallback` callback is called.
|
||||
|
||||
This function will check if a valid Metadata-response was given through `OSuite::ZWebServiceClient::RetrieveRequest<OSuite::ZOMetadata>` and if there was, flag the ZWebServiceClient as connected (`m_eStatus = 2 //READY_STATE`)
|
||||
|
||||
## OSuite::ZAtomCache::Open
|
||||
Something very important happens in any `OSuite::ZAtomCache::Open<T>`-function, as it will make an instance of a `TAtomObject<T>`. When the response comes back from the endpoint, this instance will get its `Read`-function called, which will then make an instance of the generic type.
|
||||
|
||||
There are a few of these `Read`-functions responsible for creating instances for:
|
||||
- `OSuite::ZOEntry`
|
||||
- `OSuite::ZOFeed`
|
||||
- `OSuite::ZOMetadata`
|
||||
- `OSuite::ZOServiceOperationResult`
|
||||
|
||||
Any of these constructors will call their respective `ParseJsonValue`-function.
|
||||
|
||||
## Invoking requests
|
||||
- `ZOSServiceOperation::Invoke` with callback
|
||||
- Callback can be used to find the expected response-type based on usage of the following functions:
|
||||
- `OSuite::ZWebServiceClient::RetrieveRequest<OSuite::ZOFeed>`
|
||||
- `OSuite::ZWebServiceClient::RetrieveRequest<OSuite::ZOEntry>`
|
||||
- `OSuite::ZWebServiceClient::RetrieveRequest<OSuite::ZServiceOperationResult>`
|
||||
- See ReturnType below to find out what to set ReturnType to.
|
||||
- `ZOSQueryManager::Push` => `ZOSServiceOperation::Execute` => `OSuite::ZWebServiceClient::ExecuteQuery`
|
||||
|
||||
`OSuite::ZWebServiceClient::ExecuteQuery` will the try to get API endpoint. It bases this on the QueryMode, which can either be:
|
||||
- QM_NONE //0
|
||||
- QM_ENTITYSET //1
|
||||
- QM_FUNCTIONIMPORT //2
|
||||
|
||||
## ExecuteQuery with QM_NONE
|
||||
This will always generate an internal 404, which causes the webservice to disconnect and show the Disconnected-dialog in-game (this happens with the `ShowDialog` in `ZOnlineManager::Update`).
|
||||
|
||||
## ExecuteQuery with QM_FUNCTIONIMPORT
|
||||
`OSuite::ZOMetadata::FunctionImport` will be called and if this fails an internal 404 is generated.
|
||||
|
||||
It will then check if the FunctionImport has all the querystring-parameters specified. If something is missing, again an internal 404 is generated.
|
||||
|
||||
Otherwise, it will continue and call the endpoint based on the data from the FunctionImport. It can make either a GET or a POST request (`HttpMethod`). Based on the `ReturnType` of the FunctionImport it will decide to either expect a `ZOEntry`, `ZOServiceOperationResult` or a `ZOFeed`.
|
||||
|
||||
## ExecuteQuery with QM_ENTITYSET
|
||||
`OSuite::ZOMetadata::EntitySet` will be called and always result in a GET-request for a `ZOFeed`.
|
||||
|
||||
# ReturnType
|
||||
These are the different ReturnType:
|
||||
- SVOP_FEED = 0x0 => `OSuite::ZOFeed`
|
||||
- SVOP_ENTRY = 0x1 => `OSuite::ZOEntry`
|
||||
- SVOP_VALUE = 0x2 => `OSuite::ZOServiceOperationResult`
|
||||
- SVOP_VALUECOLLECTION = 0x3
|
||||
- SVOP_VOID = 0x4
|
||||
|
||||
The following pseudocode shows how the game will convert the value of the `ReturnType` on a `EdmFunctionImport` to a ReturnType enumeration value:
|
||||
```
|
||||
this->entityName = ReturnType;
|
||||
this->returnType = SVOP_VOID;
|
||||
|
||||
var isEntityType = !this->entityName.Contains("Edm.")
|
||||
|
||||
if(this->entityName->StartsWith("Collection"))
|
||||
{
|
||||
if(isEntityType) {
|
||||
this->returnType = SVOP_FEED
|
||||
}
|
||||
else {
|
||||
this->returnType = SVOP_VALUECOLLECTION
|
||||
}
|
||||
|
||||
this->entityName = "Collection(this->entityName)"
|
||||
}
|
||||
else if(isEntityType) {
|
||||
this->returnType = SVOP_ENTRY
|
||||
}
|
||||
else {
|
||||
this->returnType = SVOP_VALUE
|
||||
}
|
||||
```
|
||||
|
||||
# Json parsing
|
||||
JSONTYPE_STRING = 0x0,
|
||||
JSONTYPE_OBJECT = 0x1,
|
||||
JSONTYPE_ARRAY = 0x2,
|
||||
|
||||
When `OSuite::ZAtomBase::ParseJson` is called:
|
||||
- It will loop over all key-value pairs of the JSON-object that is passed in as the second argument.
|
||||
- Each key-value pair will be passed to a `ParseJsonValue`-function, which is determined by the type of `ZAtomBase`-object passed in as the first argument.
|
||||
|
||||
There are a few of the `ZAtomBase`-objects in the game:
|
||||
- `ZServiceOperationValue`
|
||||
- `ZServiceOperationResult`
|
||||
- `ZAtomFeed`
|
||||
- `ZAtomEntry`
|
||||
- `ZOMetadata`
|
||||
|
||||
The `ZOMetadata`-object is responsible for parsing the metadata-response from the API. It will call the `OSuite::ZOMetadata::ParseSchema`, which will call the `ParseJson`-function, which will call the `ParseJsonValue`-function of passed-in `ZEdmBase`-object.
|
||||
|
||||
There are a few of the `ZEdmBase`-objects in the game:
|
||||
- `ZOEdmEntityType`
|
||||
- `ZOEdmComplexType`
|
||||
- `ZOEdmAssociation`
|
||||
- `ZOEdmFunctionImport`
|
||||
- `ZOEdmClientConfiguration`
|
||||
- NOTE: Instanced from `ZOMetadata->ParseJsonValue`
|
||||
|
||||
## ZOEntry
|
||||
- ZOEntry is always an EdmEntityType
|
||||
- Can contain a "results" which then contains the ZOEntry, but this is not required.
|
||||
|
||||
## ZOFeed
|
||||
- ZOFeed appears to support object and literal value. Not sure about array.
|
||||
- object should contain a "results" and "__count", results is then treated as an array of ZOEntry.
|
||||
|
||||
## ZOServiceOperationResult
|
||||
- ZOServiceOperationResult can be a single value or an array of values
|
||||
- All values will be converted to a ZServiceOperationValue
|
||||
- In-memory a ZOServiceOperationResult is always a list of 1 or more ZServiceOperationValue
|
||||
- ZServiceOperationValue can be a single value or an object
|
||||
|
||||
# Scratchpad
|
||||
These are just some random notes.
|
||||
- `OSuite::ZOEntry::ParseJsonValue`, `OSuite::ZOFeed::ParseJsonValue` and `OSuite::ZOServiceOperationResult::ParseJsonValue` describe how to parse their respective type.
|
||||
- The use of `OSuite::ZOEntry::Property` describes an expected property on a `ZOEntry`.
|
||||
- The second argument of `OSuite::ZOQuery::EntitySet` is the name of the expected EntitySet,
|
||||
- The first argument of `ZOSServiceOperation::Invoke` is the name of the expected `EdmImportFunction`
|
|
@ -0,0 +1,441 @@
|
|||
// Read an INI file into easy-to-access name/value pairs.
|
||||
|
||||
// inih and INIReader are released under the New BSD license (see LICENSE.txt).
|
||||
// Go to the project home page for more info:
|
||||
//
|
||||
// https://github.com/benhoyt/inih
|
||||
/* inih -- simple .INI file parser
|
||||
|
||||
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
||||
home page for more info:
|
||||
|
||||
https://github.com/benhoyt/inih
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __INI_H__
|
||||
#define __INI_H__
|
||||
|
||||
/* Make this header file easier to include in C++ code */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Typedef for prototype of handler function. */
|
||||
typedef int(*ini_handler)(void* user, const char* section,
|
||||
const char* name, const char* value);
|
||||
|
||||
/* Typedef for prototype of fgets-style reader function. */
|
||||
typedef char* (*ini_reader)(char* str, int num, void* stream);
|
||||
|
||||
/* Parse given INI-style file. May have [section]s, name=value pairs
|
||||
(whitespace stripped), and comments starting with ';' (semicolon). Section
|
||||
is "" if name=value pair parsed before any section heading. name:value
|
||||
pairs are also supported as a concession to Python's configparser.
|
||||
|
||||
For each name=value pair parsed, call handler function with given user
|
||||
pointer as well as section, name, and value (data only valid for duration
|
||||
of handler call). Handler should return nonzero on success, zero on error.
|
||||
|
||||
Returns 0 on success, line number of first error on parse error (doesn't
|
||||
stop on first error), -1 on file open error, or -2 on memory allocation
|
||||
error (only when INI_USE_STACK is zero).
|
||||
*/
|
||||
int ini_parse(const char* filename, ini_handler handler, void* user);
|
||||
|
||||
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
|
||||
close the file when it's finished -- the caller must do that. */
|
||||
int ini_parse_file(FILE* file, ini_handler handler, void* user);
|
||||
|
||||
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
|
||||
filename. Used for implementing custom or string-based I/O. */
|
||||
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
void* user);
|
||||
|
||||
/* Nonzero to allow multi-line value parsing, in the style of Python's
|
||||
configparser. If allowed, ini_parse() will call the handler with the same
|
||||
name for each subsequent line parsed. */
|
||||
#ifndef INI_ALLOW_MULTILINE
|
||||
#define INI_ALLOW_MULTILINE 1
|
||||
#endif
|
||||
|
||||
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
|
||||
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
|
||||
#ifndef INI_ALLOW_BOM
|
||||
#define INI_ALLOW_BOM 1
|
||||
#endif
|
||||
|
||||
/* Nonzero to allow inline comments (with valid inline comment characters
|
||||
specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
|
||||
Python 3.2+ configparser behaviour. */
|
||||
#ifndef INI_ALLOW_INLINE_COMMENTS
|
||||
#define INI_ALLOW_INLINE_COMMENTS 1
|
||||
#endif
|
||||
#ifndef INI_INLINE_COMMENT_PREFIXES
|
||||
#define INI_INLINE_COMMENT_PREFIXES ";"
|
||||
#endif
|
||||
|
||||
/* Nonzero to use stack, zero to use heap (malloc/free). */
|
||||
#ifndef INI_USE_STACK
|
||||
#define INI_USE_STACK 1
|
||||
#endif
|
||||
|
||||
/* Stop parsing on first error (default is to keep parsing). */
|
||||
#ifndef INI_STOP_ON_FIRST_ERROR
|
||||
#define INI_STOP_ON_FIRST_ERROR 0
|
||||
#endif
|
||||
|
||||
/* Maximum line length for any line in INI file. */
|
||||
#ifndef INI_MAX_LINE
|
||||
#define INI_MAX_LINE 200
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* inih -- simple .INI file parser
|
||||
|
||||
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
||||
home page for more info:
|
||||
|
||||
https://github.com/benhoyt/inih
|
||||
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !INI_USE_STACK
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define MAX_SECTION 100
|
||||
#define MAX_NAME 100
|
||||
|
||||
/* Strip whitespace chars off end of given string, in place. Return s. */
|
||||
inline static char* rstrip(char* s)
|
||||
{
|
||||
char* p = s + strlen(s);
|
||||
while (p > s && isspace((unsigned char)(*--p)))
|
||||
*p = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Return pointer to first non-whitespace char in given string. */
|
||||
inline static char* lskip(const char* s)
|
||||
{
|
||||
while (*s && isspace((unsigned char)(*s)))
|
||||
s++;
|
||||
return (char*)s;
|
||||
}
|
||||
|
||||
/* Return pointer to first char (of chars) or inline comment in given string,
|
||||
or pointer to null at end of string if neither found. Inline comment must
|
||||
be prefixed by a whitespace character to register as a comment. */
|
||||
inline static char* find_chars_or_comment(const char* s, const char* chars)
|
||||
{
|
||||
#if INI_ALLOW_INLINE_COMMENTS
|
||||
int was_space = 0;
|
||||
while (*s && (!chars || !strchr(chars, *s)) &&
|
||||
!(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
|
||||
was_space = isspace((unsigned char)(*s));
|
||||
s++;
|
||||
}
|
||||
#else
|
||||
while (*s && (!chars || !strchr(chars, *s))) {
|
||||
s++;
|
||||
}
|
||||
#endif
|
||||
return (char*)s;
|
||||
}
|
||||
|
||||
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
|
||||
inline static char* strncpy0(char* dest, const char* src, size_t size)
|
||||
{
|
||||
strncpy(dest, src, size);
|
||||
dest[size - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
inline int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
void* user)
|
||||
{
|
||||
/* Uses a fair bit of stack (use heap instead if you need to) */
|
||||
#if INI_USE_STACK
|
||||
char line[INI_MAX_LINE];
|
||||
#else
|
||||
char* line;
|
||||
#endif
|
||||
char section[MAX_SECTION] = "";
|
||||
char prev_name[MAX_NAME] = "";
|
||||
|
||||
char* start;
|
||||
char* end;
|
||||
char* name;
|
||||
char* value;
|
||||
int lineno = 0;
|
||||
int error = 0;
|
||||
|
||||
#if !INI_USE_STACK
|
||||
line = (char*)malloc(INI_MAX_LINE);
|
||||
if (!line) {
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Scan through stream line by line */
|
||||
while (reader(line, INI_MAX_LINE, stream) != NULL) {
|
||||
lineno++;
|
||||
|
||||
start = line;
|
||||
#if INI_ALLOW_BOM
|
||||
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
|
||||
(unsigned char)start[1] == 0xBB &&
|
||||
(unsigned char)start[2] == 0xBF) {
|
||||
start += 3;
|
||||
}
|
||||
#endif
|
||||
start = lskip(rstrip(start));
|
||||
|
||||
if (*start == ';' || *start == '#') {
|
||||
/* Per Python configparser, allow both ; and # comments at the
|
||||
start of a line */
|
||||
}
|
||||
#if INI_ALLOW_MULTILINE
|
||||
else if (*prev_name && *start && start > line) {
|
||||
|
||||
#if INI_ALLOW_INLINE_COMMENTS
|
||||
end = find_chars_or_comment(start, NULL);
|
||||
if (*end)
|
||||
*end = '\0';
|
||||
rstrip(start);
|
||||
#endif
|
||||
|
||||
/* Non-blank line with leading whitespace, treat as continuation
|
||||
of previous name's value (as per Python configparser). */
|
||||
if (!handler(user, section, prev_name, start) && !error)
|
||||
error = lineno;
|
||||
}
|
||||
#endif
|
||||
else if (*start == '[') {
|
||||
/* A "[section]" line */
|
||||
end = find_chars_or_comment(start + 1, "]");
|
||||
if (*end == ']') {
|
||||
*end = '\0';
|
||||
strncpy0(section, start + 1, sizeof(section));
|
||||
*prev_name = '\0';
|
||||
}
|
||||
else if (!error) {
|
||||
/* No ']' found on section line */
|
||||
error = lineno;
|
||||
}
|
||||
}
|
||||
else if (*start) {
|
||||
/* Not a comment, must be a name[=:]value pair */
|
||||
end = find_chars_or_comment(start, "=:");
|
||||
if (*end == '=' || *end == ':') {
|
||||
*end = '\0';
|
||||
name = rstrip(start);
|
||||
value = lskip(end + 1);
|
||||
#if INI_ALLOW_INLINE_COMMENTS
|
||||
end = find_chars_or_comment(value, NULL);
|
||||
if (*end)
|
||||
*end = '\0';
|
||||
#endif
|
||||
rstrip(value);
|
||||
|
||||
/* Valid name[=:]value pair found, call handler */
|
||||
strncpy0(prev_name, name, sizeof(prev_name));
|
||||
if (!handler(user, section, name, value) && !error)
|
||||
error = lineno;
|
||||
}
|
||||
else if (!error) {
|
||||
/* No '=' or ':' found on name[=:]value line */
|
||||
error = lineno;
|
||||
}
|
||||
}
|
||||
|
||||
#if INI_STOP_ON_FIRST_ERROR
|
||||
if (error)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !INI_USE_STACK
|
||||
free(line);
|
||||
#endif
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
inline int ini_parse_file(FILE* file, ini_handler handler, void* user)
|
||||
{
|
||||
return ini_parse_stream((ini_reader)fgets, file, handler, user);
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
inline int ini_parse(const char* filename, ini_handler handler, void* user)
|
||||
{
|
||||
FILE* file;
|
||||
int error;
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if (!file)
|
||||
return -1;
|
||||
error = ini_parse_file(file, handler, user);
|
||||
fclose(file);
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif /* __INI_H__ */
|
||||
|
||||
|
||||
#ifndef __INIREADER_H__
|
||||
#define __INIREADER_H__
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
// Read an INI file into easy-to-access name/value pairs. (Note that I've gone
|
||||
// for simplicity here rather than speed, but it should be pretty decent.)
|
||||
class INIReader
|
||||
{
|
||||
public:
|
||||
// Empty Constructor
|
||||
INIReader() {};
|
||||
|
||||
// Construct INIReader and parse given filename. See ini.h for more info
|
||||
// about the parsing.
|
||||
INIReader(std::string filename);
|
||||
|
||||
// Return the result of ini_parse(), i.e., 0 on success, line number of
|
||||
// first error on parse error, or -1 on file open error.
|
||||
int ParseError() const;
|
||||
|
||||
// Return the list of sections found in ini file
|
||||
const std::set<std::string>& Sections() const;
|
||||
|
||||
// Get a string value from INI file, returning default_value if not found.
|
||||
std::string Get(std::string section, std::string name,
|
||||
std::string default_value) const;
|
||||
|
||||
// Get an integer (long) value from INI file, returning default_value if
|
||||
// not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
|
||||
long GetInteger(std::string section, std::string name, long default_value) const;
|
||||
|
||||
// Get a real (floating point double) value from INI file, returning
|
||||
// default_value if not found or not a valid floating point value
|
||||
// according to strtod().
|
||||
double GetReal(std::string section, std::string name, double default_value) const;
|
||||
|
||||
// Get a boolean value from INI file, returning default_value if not found or if
|
||||
// not a valid true/false value. Valid true values are "true", "yes", "on", "1",
|
||||
// and valid false values are "false", "no", "off", "0" (not case sensitive).
|
||||
bool GetBoolean(std::string section, std::string name, bool default_value) const;
|
||||
|
||||
protected:
|
||||
int _error;
|
||||
std::map<std::string, std::string> _values;
|
||||
std::set<std::string> _sections;
|
||||
static std::string MakeKey(std::string section, std::string name);
|
||||
static int ValueHandler(void* user, const char* section, const char* name,
|
||||
const char* value);
|
||||
};
|
||||
|
||||
#endif // __INIREADER_H__
|
||||
|
||||
|
||||
#ifndef __INIREADER__
|
||||
#define __INIREADER__
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
|
||||
using std::string;
|
||||
|
||||
inline INIReader::INIReader(string filename)
|
||||
{
|
||||
_error = ini_parse(filename.c_str(), ValueHandler, this);
|
||||
}
|
||||
|
||||
inline int INIReader::ParseError() const
|
||||
{
|
||||
return _error;
|
||||
}
|
||||
|
||||
inline const std::set<string>& INIReader::Sections() const
|
||||
{
|
||||
return _sections;
|
||||
}
|
||||
|
||||
inline string INIReader::Get(string section, string name, string default_value) const
|
||||
{
|
||||
string key = MakeKey(section, name);
|
||||
return _values.count(key) ? _values.at(key) : default_value;
|
||||
}
|
||||
|
||||
inline long INIReader::GetInteger(string section, string name, long default_value) const
|
||||
{
|
||||
string valstr = Get(section, name, "");
|
||||
const char* value = valstr.c_str();
|
||||
char* end;
|
||||
// This parses "1234" (decimal) and also "0x4D2" (hex)
|
||||
long n = strtol(value, &end, 0);
|
||||
return end > value ? n : default_value;
|
||||
}
|
||||
|
||||
inline double INIReader::GetReal(string section, string name, double default_value) const
|
||||
{
|
||||
string valstr = Get(section, name, "");
|
||||
const char* value = valstr.c_str();
|
||||
char* end;
|
||||
double n = strtod(value, &end);
|
||||
return end > value ? n : default_value;
|
||||
}
|
||||
|
||||
inline bool INIReader::GetBoolean(string section, string name, bool default_value) const
|
||||
{
|
||||
string valstr = Get(section, name, "");
|
||||
// Convert to lower case to make string comparisons case-insensitive
|
||||
std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
|
||||
if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
|
||||
return true;
|
||||
else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
|
||||
return false;
|
||||
else
|
||||
return default_value;
|
||||
}
|
||||
|
||||
inline string INIReader::MakeKey(string section, string name)
|
||||
{
|
||||
string key = section + "=" + name;
|
||||
// Convert to lower case to make section/name lookups case-insensitive
|
||||
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||
return key;
|
||||
}
|
||||
|
||||
inline int INIReader::ValueHandler(void* user, const char* section, const char* name,
|
||||
const char* value)
|
||||
{
|
||||
INIReader* reader = (INIReader*)user;
|
||||
string key = MakeKey(section, name);
|
||||
if (reader->_values[key].size() > 0)
|
||||
reader->_values[key] += "\n";
|
||||
reader->_values[key] += value;
|
||||
reader->_sections.insert(section);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // __INIREADER__
|
|
@ -0,0 +1,163 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="hook_absolution.cpp" />
|
||||
<ClCompile Include="hook_sniper.cpp" />
|
||||
<ClCompile Include="proxy.cpp" />
|
||||
<ClCompile Include="proxy_dinput8.cpp" />
|
||||
<ClCompile Include="hook.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="hook_absolution.h" />
|
||||
<ClInclude Include="hook_sniper.h" />
|
||||
<ClInclude Include="proxy.h" />
|
||||
<ClInclude Include="hook.h" />
|
||||
<ClInclude Include="INIReader.h" />
|
||||
<ClInclude Include="MinHook.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="libMinHook-x64-v140-mt.lib" />
|
||||
<Library Include="libMinHook-x86-v140-mt.lib" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="hook.ini" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{57ABB826-E2F3-4908-BBBB-634C1A747CAA}</ProjectGuid>
|
||||
<RootNamespace>MyDLL</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TargetName>dinput8</TargetName>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<TargetName>dinput8</TargetName>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetName>dinput8</TargetName>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<TargetName>dinput8</TargetName>
|
||||
<OutDir>bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalOptions>/NODEFAULTLIB:LIBCMT.lib %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="hook.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="proxy_dinput8.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hook_absolution.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="proxy.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hook_sniper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="hook.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MinHook.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="INIReader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="proxy.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hook_sniper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hook_absolution.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="libMinHook-x64-v140-mt.lib" />
|
||||
<Library Include="libMinHook-x86-v140-mt.lib" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="hook.ini">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2015 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !(defined _M_IX86) && !(defined _M_X64)
|
||||
#error MinHook supports only x86 and x64 systems.
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// MinHook Error Codes.
|
||||
typedef enum MH_STATUS
|
||||
{
|
||||
// Unknown error. Should not be returned.
|
||||
MH_UNKNOWN = -1,
|
||||
|
||||
// Successful.
|
||||
MH_OK = 0,
|
||||
|
||||
// MinHook is already initialized.
|
||||
MH_ERROR_ALREADY_INITIALIZED,
|
||||
|
||||
// MinHook is not initialized yet, or already uninitialized.
|
||||
MH_ERROR_NOT_INITIALIZED,
|
||||
|
||||
// The hook for the specified target function is already created.
|
||||
MH_ERROR_ALREADY_CREATED,
|
||||
|
||||
// The hook for the specified target function is not created yet.
|
||||
MH_ERROR_NOT_CREATED,
|
||||
|
||||
// The hook for the specified target function is already enabled.
|
||||
MH_ERROR_ENABLED,
|
||||
|
||||
// The hook for the specified target function is not enabled yet, or already
|
||||
// disabled.
|
||||
MH_ERROR_DISABLED,
|
||||
|
||||
// The specified pointer is invalid. It points the address of non-allocated
|
||||
// and/or non-executable region.
|
||||
MH_ERROR_NOT_EXECUTABLE,
|
||||
|
||||
// The specified target function cannot be hooked.
|
||||
MH_ERROR_UNSUPPORTED_FUNCTION,
|
||||
|
||||
// Failed to allocate memory.
|
||||
MH_ERROR_MEMORY_ALLOC,
|
||||
|
||||
// Failed to change the memory protection.
|
||||
MH_ERROR_MEMORY_PROTECT,
|
||||
|
||||
// The specified module is not loaded.
|
||||
MH_ERROR_MODULE_NOT_FOUND,
|
||||
|
||||
// The specified function is not found.
|
||||
MH_ERROR_FUNCTION_NOT_FOUND
|
||||
}
|
||||
MH_STATUS;
|
||||
|
||||
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
|
||||
// MH_QueueEnableHook or MH_QueueDisableHook.
|
||||
#define MH_ALL_HOOKS NULL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Initialize the MinHook library. You must call this function EXACTLY ONCE
|
||||
// at the beginning of your program.
|
||||
MH_STATUS WINAPI MH_Initialize(VOID);
|
||||
|
||||
// Uninitialize the MinHook library. You must call this function EXACTLY
|
||||
// ONCE at the end of your program.
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID);
|
||||
|
||||
// Creates a Hook for the specified target function, in disabled state.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Removes an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
|
||||
|
||||
// Enables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// enabled in one go.
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
|
||||
|
||||
// Disables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// disabled in one go.
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to enable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be enabled.
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to disable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be disabled.
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
|
||||
|
||||
// Applies all queued changes in one go.
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID);
|
||||
|
||||
// Translates the MH_STATUS to its name as a string.
|
||||
const char * WINAPI MH_StatusToString(MH_STATUS status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
template <typename T>
|
||||
inline MH_STATUS MH_CreateHookEx(LPVOID pTarget, LPVOID pDetour, T** ppOriginal)
|
||||
{
|
||||
return MH_CreateHook(pTarget, pDetour, reinterpret_cast<LPVOID*>(ppOriginal));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline MH_STATUS MH_CreateHookApiEx(LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, T** ppOriginal)
|
||||
{
|
||||
return MH_CreateHookApi(pszModule, pszProcName, pDetour, reinterpret_cast<LPVOID*>(ppOriginal));
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
#include "hook.h"
|
||||
#include "hook_absolution.h"
|
||||
#include "hook_sniper.h"
|
||||
#include "proxy.h"
|
||||
|
||||
bool OptionsEnabled = false;
|
||||
bool OptionsLog = false;
|
||||
|
||||
IHook* Hook;
|
||||
std::ofstream LogFile;
|
||||
INIReader IniFile;
|
||||
|
||||
void InitializeOptions()
|
||||
{
|
||||
LogFile.open("hook.log", std::ios_base::out);
|
||||
|
||||
LogTime();
|
||||
LogFile << "InitializeOptions" << std::endl;
|
||||
|
||||
IniFile = INIReader("hook.ini");
|
||||
|
||||
if (IniFile.ParseError() != 0) {
|
||||
LogFile << "Can't load hook.ini!" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
OptionsEnabled = IniFile.GetBoolean("options", "enabled", false);
|
||||
|
||||
if (!OptionsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OptionsLog = IniFile.GetBoolean("options", "log", false);
|
||||
|
||||
auto IsHitmanAbsolution = strcmp(
|
||||
IniFile.Get("options", "game", "hm5").c_str(),
|
||||
"hm5"
|
||||
) == 0;
|
||||
|
||||
if (IsHitmanAbsolution)
|
||||
{
|
||||
LogFile << "Hitman Absolution" << std::endl;
|
||||
|
||||
Hook = (IHook*)new AbsolutionHook();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile << "Hitman Sniper Challenge" << std::endl;
|
||||
|
||||
Hook = (IHook*)new SniperHook();
|
||||
}
|
||||
|
||||
Hook->InitializeOptions();
|
||||
}
|
||||
|
||||
void InitializeHook()
|
||||
{
|
||||
LogFile << "InitializeHook" << std::endl;
|
||||
|
||||
LogStatus("Initialize", MH_Initialize());
|
||||
|
||||
Hook->PreInitializeHook();
|
||||
}
|
||||
|
||||
void DeinitializeHook()
|
||||
{
|
||||
LogTime();
|
||||
LogFile << "DeinitializeHook" << std::endl;
|
||||
|
||||
LogStatus("Deinitialize", MH_Uninitialize());
|
||||
|
||||
if (LogFile)
|
||||
{
|
||||
LogFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID /*lpReserved*/)
|
||||
{
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
|
||||
InitializeOptions();
|
||||
|
||||
LoadProxyDll();
|
||||
|
||||
if (OptionsEnabled)
|
||||
{
|
||||
InitializeHook();
|
||||
}
|
||||
}
|
||||
else if (fdwReason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
if (OptionsEnabled)
|
||||
{
|
||||
DeinitializeHook();
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
#define _CRT_SECURE_NO_WARNINGS // NOLINT(bugprone-reserved-identifier)
|
||||
|
||||
#include <Windows.h>
|
||||
#include <fstream>
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
|
||||
#include "MinHook.h"
|
||||
#include "INIReader.h"
|
||||
|
||||
interface IHook {
|
||||
virtual void InitializeOptions() = 0;
|
||||
virtual void PreInitializeHook() = 0;
|
||||
virtual void PostInitializeHook() = 0;
|
||||
};
|
||||
|
||||
extern IHook* Hook;
|
||||
|
||||
extern bool OptionsEnabled;
|
||||
extern bool OptionsLog;
|
||||
|
||||
extern std::ofstream LogFile;
|
||||
extern INIReader IniFile;
|
||||
|
||||
inline void LogTime() {
|
||||
std::time_t result = std::time(nullptr);
|
||||
|
||||
char* time = std::asctime(std::localtime(&result));
|
||||
time[strlen(time) - 1] = 0;
|
||||
|
||||
LogFile << "[" << time << "]" << std::endl;
|
||||
}
|
||||
|
||||
#define LOG_MESSAGE(...) if(OptionsLog) { LogTime();LogFile << __VA_ARGS__ << std::endl;}
|
||||
|
||||
inline void LogStatus(LPCSTR name, MH_STATUS status)
|
||||
{
|
||||
LogFile << name << ": " << MH_StatusToString(status) << std::endl;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
[options]
|
||||
enabled=true
|
||||
log=true
|
||||
|
||||
;Can be set to either hm5 or sniper
|
||||
game=hm5
|
||||
|
||||
[hm5]
|
||||
webserviceurl=http://localhost/hm5
|
||||
skiplauncher=true
|
||||
|
||||
[sniper]
|
||||
webserviceurl=http://localhost/sniper
|
|
@ -0,0 +1,61 @@
|
|||
#include "hook_absolution.h"
|
||||
|
||||
bool AbsolutionHook::SkipLauncher = false;
|
||||
std::string AbsolutionHook::WebServiceUrl;
|
||||
AbsolutionHook::tGetApplicationOptionBool AbsolutionHook::oGetApplicationOptionBool = nullptr;
|
||||
AbsolutionHook::tZWebServiceClientManagerCreate AbsolutionHook::oZWebServiceClientManagerCreate = nullptr;
|
||||
|
||||
bool __cdecl AbsolutionHook::GetApplicationOptionBool(ZString* sName, bool bDefault)
|
||||
{
|
||||
if (strcmp(sName->m_chars, "EnableSplashScreen") == 0 && SkipLauncher)
|
||||
{
|
||||
LogFile << "SkipLauncher" << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return oGetApplicationOptionBool(sName, bDefault);
|
||||
}
|
||||
|
||||
//Source: https://tresp4sser.wordpress.com/2012/10/06/how-to-hook-thiscall-functions/
|
||||
void* __fastcall AbsolutionHook::ZWebServiceClientManagerCreate(void* instance, void* _, const char* baseUrl, void* callback)
|
||||
{
|
||||
LogFile << "ZWebServiceClientManagerCreate" << baseUrl << std::endl;
|
||||
|
||||
return oZWebServiceClientManagerCreate(instance, WebServiceUrl.c_str(), callback);
|
||||
}
|
||||
|
||||
void AbsolutionHook::InitializeOptions()
|
||||
{
|
||||
SkipLauncher = IniFile.GetBoolean("hm5", "skiplauncher", false);
|
||||
WebServiceUrl = IniFile.Get("hm5", "webserviceurl", "http://localhost/hm5");
|
||||
}
|
||||
|
||||
void AbsolutionHook::PreInitializeHook()
|
||||
{
|
||||
void* ptrGetApplicationOptionBool = (void*)0x00612930;
|
||||
void* ptrZWebServiceClientManagerCreate = (void*)0x00BE22CF;
|
||||
|
||||
MH_STATUS skipLauncherHook = MH_CreateHook(
|
||||
ptrGetApplicationOptionBool,
|
||||
GetApplicationOptionBool,
|
||||
reinterpret_cast<void**>(&oGetApplicationOptionBool)
|
||||
);
|
||||
|
||||
MH_STATUS webServiceurlHook = MH_CreateHook(
|
||||
ptrZWebServiceClientManagerCreate,
|
||||
ZWebServiceClientManagerCreate,
|
||||
reinterpret_cast<void**>(&oZWebServiceClientManagerCreate)
|
||||
);
|
||||
|
||||
LogStatus("SkipLauncher hook", skipLauncherHook);
|
||||
LogStatus("SkipLauncher enable", MH_EnableHook(ptrGetApplicationOptionBool));
|
||||
|
||||
LogStatus("WebServiceUrl hook", webServiceurlHook);
|
||||
LogStatus("WebServiceUrl enable", MH_EnableHook(ptrZWebServiceClientManagerCreate));
|
||||
}
|
||||
|
||||
void AbsolutionHook::PostInitializeHook()
|
||||
{
|
||||
//Do nothing
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "hook.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class AbsolutionHook : IHook
|
||||
{
|
||||
public:
|
||||
void InitializeOptions() override;
|
||||
void PreInitializeHook() override;
|
||||
void PostInitializeHook() override;
|
||||
|
||||
private:
|
||||
static bool SkipLauncher;
|
||||
static std::string WebServiceUrl;
|
||||
|
||||
struct ZString
|
||||
{
|
||||
unsigned int m_length;
|
||||
const char* m_chars;
|
||||
};
|
||||
|
||||
typedef bool(__cdecl* tGetApplicationOptionBool)(ZString* sName, bool bDefault);
|
||||
typedef void* (__thiscall* tZWebServiceClientManagerCreate)(void* instance, const char* baseUrl, void* callback);
|
||||
|
||||
static bool __cdecl GetApplicationOptionBool(ZString* sName, bool bDefault);
|
||||
static void* __fastcall ZWebServiceClientManagerCreate(void* instance, void* _, const char* baseUrl, void* callback);
|
||||
|
||||
static tGetApplicationOptionBool oGetApplicationOptionBool;
|
||||
static tZWebServiceClientManagerCreate oZWebServiceClientManagerCreate;
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
#include "hook_sniper.h"
|
||||
|
||||
void SniperHook::InitializeOptions()
|
||||
{
|
||||
WebServiceUrl = IniFile.Get("sniper", "webserviceurl", "http://localhost/sniper");
|
||||
}
|
||||
|
||||
void SniperHook::PreInitializeHook()
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
void SniperHook::PostInitializeHook()
|
||||
{
|
||||
auto ptrWebServiceUrl = (void*)0x113D5E8;
|
||||
strcpy((char*)ptrWebServiceUrl, WebServiceUrl.substr(0, 256).c_str());
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "hook.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class SniperHook : IHook
|
||||
{
|
||||
public:
|
||||
virtual void InitializeOptions();
|
||||
virtual void PreInitializeHook();
|
||||
virtual void PostInitializeHook();
|
||||
|
||||
private:
|
||||
std::string WebServiceUrl;
|
||||
};
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,10 @@
|
|||
#include "proxy.h"
|
||||
|
||||
#if HOOK_TYPE == HOOK_TYPE_DISABLED
|
||||
|
||||
void LoadProxyDll()
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#define HOOK_TYPE_DISABLED 0
|
||||
#define HOOK_TYPE_DINPUT8 1
|
||||
|
||||
#define HOOK_TYPE HOOK_TYPE_DINPUT8
|
||||
|
||||
void LoadProxyDll();
|
|
@ -0,0 +1,43 @@
|
|||
#include "proxy.h"
|
||||
|
||||
#if HOOK_TYPE == HOOK_TYPE_DINPUT8
|
||||
|
||||
#include "hook.h"
|
||||
#include <iostream>
|
||||
#include "MinHook.h"
|
||||
|
||||
typedef HRESULT(WINAPI* tDirectInput8Create)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, LPUNKNOWN punkOuter);
|
||||
tDirectInput8Create oDirectInput8Create;
|
||||
|
||||
void LoadProxyDll()
|
||||
{
|
||||
LogFile << "LoadProxyDLL: ";
|
||||
|
||||
wchar_t syspath[512];
|
||||
GetSystemDirectory(syspath, 512);
|
||||
wcscat_s(syspath, L"\\dinput8.dll");
|
||||
|
||||
const HMODULE hLibrary = LoadLibrary(syspath);
|
||||
|
||||
if (!hLibrary) {
|
||||
LogFile << "Fail!" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
oDirectInput8Create = (tDirectInput8Create)GetProcAddress(hLibrary, "DirectInput8Create");
|
||||
|
||||
LogFile << "Done!" << std::endl;
|
||||
}
|
||||
|
||||
#pragma comment(linker, "/export:DirectInput8Create=_DirectInput8Create@20")
|
||||
extern "C" __declspec(dllexport) HRESULT WINAPI DirectInput8Create(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID * ppvOut, LPUNKNOWN punkOuter)
|
||||
{
|
||||
LogFile << "DirectInput8Create" << std::endl;
|
||||
|
||||
Hook->PostInitializeHook();
|
||||
|
||||
return oDirectInput8Create(hinst, dwVersion, riidltf, ppvOut, punkOuter);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,13 @@
|
|||
namespace HM5.Server.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class EdmEntityAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public EdmEntityAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
namespace HM5.Server.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class EdmPropertyAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
public bool Nullable { get; set; }
|
||||
|
||||
public EdmPropertyAttribute(string name, string type, bool nullable)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
Nullable = nullable;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using HM5.Server.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Attributes
|
||||
{
|
||||
public class NormalizedStringAttribute : ModelBinderAttribute
|
||||
{
|
||||
public NormalizedStringAttribute(string propertyName = null)
|
||||
: base(typeof(NormalizedStringModelBinder))
|
||||
{
|
||||
Name = propertyName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
using HM5.Server.Interfaces;
|
||||
using HM5.Server.Models.Response;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers
|
||||
{
|
||||
public abstract class BaseController : Controller
|
||||
{
|
||||
protected readonly ISimpleLogger Logger;
|
||||
|
||||
protected BaseController(ISimpleLogger simpleLogger)
|
||||
{
|
||||
Logger = simpleLogger;
|
||||
}
|
||||
|
||||
protected JsonResult JsonGenericResponse<T>(T data)
|
||||
{
|
||||
return Json(new BaseResponse<T>
|
||||
{
|
||||
Data = data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Even though it is not constrained, only use primitive values for the generic!
|
||||
*/
|
||||
protected JsonResult JsonOperationValueResponse<T>(T data)
|
||||
{
|
||||
return Json(new BaseOperationValueResponse<T>
|
||||
{
|
||||
Data = new SingleOperationValue<T>
|
||||
{
|
||||
Key = data
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Even though it is not constrained, only use primitive values for the generic!
|
||||
*/
|
||||
protected JsonResult JsonOperationListResponse<T>(List<T> data)
|
||||
{
|
||||
return Json(new BaseOperationListResponse<T>
|
||||
{
|
||||
Data = data
|
||||
});
|
||||
}
|
||||
|
||||
protected JsonResult JsonEntryResponse<T>(T data)
|
||||
where T : IEdmEntity
|
||||
{
|
||||
return Json(new BaseEntryResponse<T>
|
||||
{
|
||||
Data = new EntryObject<T>
|
||||
{
|
||||
Results = data
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected JsonResult JsonFeedResponse<T>(List<T> data)
|
||||
where T : IEdmEntity
|
||||
{
|
||||
return Json(new BaseFeedResponse<T>
|
||||
{
|
||||
Data = new FeedObject<T>
|
||||
{
|
||||
Results = data,
|
||||
Count = data.Count
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers
|
||||
{
|
||||
public class ErrorController : Controller
|
||||
{
|
||||
[Route("{*url}")]
|
||||
public IActionResult CatchAll()
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Interfaces;
|
||||
using HM5.Server.Models;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
[Route("hm5")]
|
||||
public partial class HitmanController : BaseController
|
||||
{
|
||||
public const string SchemaNamespace = "HM5";
|
||||
|
||||
//NOTE: Rating seems unused in UI?
|
||||
private readonly List<ScoreEntry> _mockedGetScoresResponse = new()
|
||||
{
|
||||
new ScoreEntry
|
||||
{
|
||||
UserId = "LennardF1989",
|
||||
Rank = 1,
|
||||
Rating = 5,
|
||||
Score = 1989
|
||||
},
|
||||
new ScoreEntry
|
||||
{
|
||||
UserId = "RDIL",
|
||||
Rank = 2,
|
||||
Rating = 5,
|
||||
Score = 1989
|
||||
},
|
||||
new ScoreEntry
|
||||
{
|
||||
UserId = "AnthonyFuller",
|
||||
Rank = 3,
|
||||
Rating = 5,
|
||||
Score = 1989
|
||||
},
|
||||
new ScoreEntry
|
||||
{
|
||||
//NOTE: SteamID
|
||||
UserId = "76561198161220058",
|
||||
Rank = 4,
|
||||
Rating = 5,
|
||||
Score = 1989
|
||||
},
|
||||
new ScoreEntry
|
||||
{
|
||||
//NOTE: CountryID
|
||||
UserId = "73",
|
||||
Rank = 5,
|
||||
Rating = 5,
|
||||
Score = 1989
|
||||
}
|
||||
};
|
||||
|
||||
private readonly List<int> _mockedGetAverageScoresResponse = new()
|
||||
{
|
||||
1, //World Average
|
||||
2, //Country Average
|
||||
3, //Friends Average
|
||||
4 //Score: Deadliest / Richest / Most Popular Assassin
|
||||
};
|
||||
|
||||
private readonly Contract _mockedContractWithoutCompetition = new()
|
||||
{
|
||||
Id = 1,
|
||||
DisplayId = "FakeContract47",
|
||||
UserId = "76561198161220058",
|
||||
UserName = "Wingz of Death",
|
||||
Title = "Kill Diana",
|
||||
Description = "Lol, joke.",
|
||||
HighestScoringFriendName = "76561198161220058",
|
||||
HighestScoringFriendScore = 101,
|
||||
Targets = new TargetsWrapper
|
||||
{
|
||||
Targets = new List<Target>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "David Thorhauge",
|
||||
AmmoType = 0,
|
||||
OutfitToken = -947477428,
|
||||
SpecialSituation = 0,
|
||||
WeaponToken = 1575676105
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "Francois Munguia",
|
||||
AmmoType = 0,
|
||||
OutfitToken = -947477428,
|
||||
SpecialSituation = 0,
|
||||
WeaponToken = 0
|
||||
}
|
||||
}
|
||||
},
|
||||
Restrictions = new RestrictionsWrapper
|
||||
{
|
||||
Restrictions = new List<ERestrictionType>
|
||||
{
|
||||
ERestrictionType.NoWitnesses,
|
||||
ERestrictionType.PerfectShooter
|
||||
}
|
||||
},
|
||||
ExitId = 2,
|
||||
Difficulty = 2,
|
||||
LevelIndex = 0,
|
||||
CheckpointIndex = 40,
|
||||
Dislikes = 0,
|
||||
Likes = 0,
|
||||
Plays = 0,
|
||||
StartingOutfitToken = -947477428,
|
||||
StartingWeaponToken = 1575676105,
|
||||
UserScore = 241953
|
||||
};
|
||||
|
||||
private readonly Contract _mockedContractWithCompetition = new()
|
||||
{
|
||||
Id = 2,
|
||||
DisplayId = "FakeContract48",
|
||||
UserId = "76561198161220058",
|
||||
UserName = "Wingz of Death",
|
||||
Title = "Kill Diana",
|
||||
Description = "Lol, joke.",
|
||||
CompetitionLeader = "76561198161220058",
|
||||
CompetitionHighestScore = 101,
|
||||
HighestScoringFriendName = "76561198161220058",
|
||||
HighestScoringFriendScore = 101,
|
||||
Targets = new TargetsWrapper
|
||||
{
|
||||
Targets = new List<Target>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "David Thorhauge",
|
||||
AmmoType = 0,
|
||||
OutfitToken = -947477428,
|
||||
SpecialSituation = 0,
|
||||
WeaponToken = 1575676105
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "Francois Munguia",
|
||||
AmmoType = 0,
|
||||
OutfitToken = -947477428,
|
||||
SpecialSituation = 0,
|
||||
WeaponToken = 0
|
||||
}
|
||||
}
|
||||
},
|
||||
Restrictions = new RestrictionsWrapper
|
||||
{
|
||||
Restrictions = new List<ERestrictionType>
|
||||
{
|
||||
ERestrictionType.NoWitnesses,
|
||||
ERestrictionType.PerfectShooter
|
||||
}
|
||||
},
|
||||
Competition = new CompetitionWrapper
|
||||
{
|
||||
Competition = new List<Competition>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = 1,
|
||||
AllowInvites = true,
|
||||
DaysRemaining = 3,
|
||||
CompetitionCreator = "76561198161220058",
|
||||
EndTimeUTC = DateTime.UtcNow.AddDays(3)
|
||||
}
|
||||
}
|
||||
},
|
||||
ExitId = 2,
|
||||
Difficulty = 2,
|
||||
LevelIndex = 0,
|
||||
CheckpointIndex = 40,
|
||||
Dislikes = 0,
|
||||
Likes = 0,
|
||||
Plays = 0,
|
||||
StartingOutfitToken = -947477428,
|
||||
StartingWeaponToken = 1575676105,
|
||||
UserScore = 241953
|
||||
};
|
||||
|
||||
private readonly IMetadataService _metadataService;
|
||||
|
||||
public HitmanController(
|
||||
ISimpleLogger simpleLogger,
|
||||
IMetadataServiceForHitman metadataService
|
||||
)
|
||||
: base(simpleLogger)
|
||||
{
|
||||
_metadataService = metadataService;
|
||||
}
|
||||
|
||||
public static List<EdmFunctionImport> GetEdmFunctionImports()
|
||||
{
|
||||
return new List<EdmFunctionImport>
|
||||
{
|
||||
_updateDLCInfo,
|
||||
_getRichestAverageScores,
|
||||
_reportContract,
|
||||
_getScoreComparison,
|
||||
_updateUserProfileLevelProgression,
|
||||
_queueAddContract,
|
||||
_searchForContracts2,
|
||||
_getUserWallet,
|
||||
_updateUserProfileSpecialRatings,
|
||||
_uploadContract,
|
||||
_sendTemplatedMessage,
|
||||
_getMessages,
|
||||
_updateContractLikeDislikes,
|
||||
_queueRemoveContract,
|
||||
_mergeUserTokens,
|
||||
_executeWalletTransaction,
|
||||
_getUserOverviewData,
|
||||
_markContractAsPlayed,
|
||||
_inviteToCompetition,
|
||||
_createCompetition,
|
||||
_getAverageScores,
|
||||
_getDeadliestScores,
|
||||
_updateUserInfo,
|
||||
_getScores,
|
||||
_getFeaturedContract,
|
||||
_setMessageReadStatus,
|
||||
_getRichestScores,
|
||||
_getPopularAverageScores,
|
||||
_updateUserProfileChallenges,
|
||||
_updateUserProfileGameStats,
|
||||
_putScore,
|
||||
_getDeadliestAverageScores,
|
||||
_getPopularScores,
|
||||
_getNewMessageCount
|
||||
};
|
||||
}
|
||||
|
||||
public static List<Type> GetEdmEntityTypes()
|
||||
{
|
||||
return new List<Type>
|
||||
{
|
||||
typeof(Contract),
|
||||
typeof(GetUserOverviewData),
|
||||
typeof(Message),
|
||||
typeof(ScoreComparison),
|
||||
typeof(ScoreEntry),
|
||||
typeof(UserTokenData)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
public partial class HitmanController
|
||||
{
|
||||
[HttpPost]
|
||||
[Route("AddMetrics")]
|
||||
public IActionResult AddMetrics([FromBody] JsonDocument json)
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::UpdateCompetition @ 006E50B0
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _createCompetition = new()
|
||||
{
|
||||
Name = "CreateCompetition",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "contractId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "competitionLength",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "allowInvites",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("CreateCompetition")]
|
||||
public IActionResult CreateCompetition()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::ExecuteWalletTransactionAsync @ 00684EF0
|
||||
* Callback: ZContractManager::ExecuteWalletTransactionAsyncCallback @ 005E88A0
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _executeWalletTransaction = new()
|
||||
{
|
||||
Name = "ExecuteWalletTransaction",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new ()
|
||||
{
|
||||
Name = "amount",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new ()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new ()
|
||||
{
|
||||
Name = "tokenId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new ()
|
||||
{
|
||||
Name = "subId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new ()
|
||||
{
|
||||
Name = "level",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("ExecuteWalletTransaction")]
|
||||
public IActionResult ExecuteWalletTransaction()
|
||||
{
|
||||
//NOTE: Appears to be the new WalletAmount left
|
||||
return JsonOperationValueResponse(101);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetAverageScores @ 0073C100
|
||||
* Callback: ZLeaderboard::GetAverageScoresCallback @ 00760350
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getAverageScores = new()
|
||||
{
|
||||
Name = "GetAverageScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({EdmTypes.String})",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardtype",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetAverageScores")]
|
||||
public IActionResult GetAverageScores()
|
||||
{
|
||||
return JsonOperationListResponse(_mockedGetAverageScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetSpecialAverageDeadliest @ 00919C70
|
||||
* Callback: ZLeaderboard::GetAverageScoresCallback @ 00760350
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getDeadliestAverageScores = new()
|
||||
{
|
||||
Name = "GetDeadliestAverageScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({EdmTypes.String})",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetDeadliestAverageScores")]
|
||||
public IActionResult GetDeadliestAverageScores()
|
||||
{
|
||||
return JsonOperationListResponse(_mockedGetAverageScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetSpecialDeadliest @ 00791C00
|
||||
* Callback: ZLeaderboard::GetScoresCallback @ 007FD3D0
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getDeadliestScores = new()
|
||||
{
|
||||
Name = "GetDeadliestScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.ScoreEntry)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "filter",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "startindex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "range",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetDeadliestScores")]
|
||||
public IActionResult GetDeadliestScores()
|
||||
{
|
||||
return JsonFeedResponse(_mockedGetScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::Start @ 806E20
|
||||
* Callback: ZContractManager::RetrieveFeaturedContractCallback @ 964FE0
|
||||
* ReturnType: ZOEntry
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getFeaturedContract = new()
|
||||
{
|
||||
Name = "GetFeaturedContract",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"{SchemaNamespace}.Contract",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "levelindex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetFeaturedContract")]
|
||||
public IActionResult GetFeaturedContract()
|
||||
{
|
||||
return JsonEntryResponse(_mockedContractWithCompetition);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke:
|
||||
* - ZMessageManager::GetOnlineMessages @ 008D5730
|
||||
* - ZMessageManager::GetNewOnlineMessages @ 005EE400
|
||||
* Callback:
|
||||
* - ZMessageManager::OnGetMessagesComplete @ 9D8CF0
|
||||
* - ZMessageManager::OnGetNewMessagesComplete @ 00961A30
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getMessages = new()
|
||||
{
|
||||
Name = "GetMessages",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.Message)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "tabgroup",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "languageId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "skip",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "limit",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetMessages")]
|
||||
public IActionResult GetMessages()
|
||||
{
|
||||
return JsonFeedResponse(new List<Message>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = 5000,
|
||||
FromId = "76561198161220058",
|
||||
IsRead = false,
|
||||
TextTemplateId = 0,
|
||||
TemplateData = "Heya!",
|
||||
TimestampUTC = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = 5001,
|
||||
FromId = "76561198161220058",
|
||||
IsRead = true,
|
||||
TextTemplateId = 0,
|
||||
TemplateData = "Heya {userid}!",
|
||||
TimestampUTC = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZMessageManager::Update @ 0099DFA0
|
||||
* Callback: ZMessageManager::OnGetNewMessageCountComplete @ 008847F0
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getNewMessageCount = new()
|
||||
{
|
||||
Name = "GetNewMessageCount",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetNewMessageCount")]
|
||||
public IActionResult GetNewMessageCount()
|
||||
{
|
||||
return JsonOperationValueResponse(10);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetSpecialAveragePopular @ 00895B20
|
||||
* Callback: ZLeaderboard::GetAverageScoresCallback @ 00760350
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getPopularAverageScores = new()
|
||||
{
|
||||
Name = "GetPopularAverageScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({EdmTypes.String})",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetPopularAverageScores")]
|
||||
public IActionResult GetPopularAverageScores()
|
||||
{
|
||||
return JsonOperationListResponse(_mockedGetAverageScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetSpecialPopular @ 0095F6A0
|
||||
* Callback: ZLeaderboard::GetScoresCallback @ 007FD3D0
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getPopularScores = new()
|
||||
{
|
||||
Name = "GetPopularScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.ScoreEntry)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "filter",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "startindex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "range",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetPopularScores")]
|
||||
public IActionResult GetPopularScores()
|
||||
{
|
||||
return JsonFeedResponse(_mockedGetScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetSpecialAverageRichest @ 0044D220
|
||||
* Callback: ZLeaderboard::GetAverageScoresCallback @ 00760350
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getRichestAverageScores = new()
|
||||
{
|
||||
Name = "GetRichestAverageScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({EdmTypes.String})",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetRichestAverageScores")]
|
||||
public IActionResult GetRichestAverageScores()
|
||||
{
|
||||
return JsonOperationListResponse(_mockedGetAverageScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetSpecialRichest @ 00868C30
|
||||
* Callback: ZLeaderboard::GetScoresCallback @ 007FD3D0
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getRichestScores = new()
|
||||
{
|
||||
Name = "GetRichestScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.ScoreEntry)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "filter",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "startindex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "range",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetRichestScores")]
|
||||
public IActionResult GetRichestScores()
|
||||
{
|
||||
return JsonFeedResponse(_mockedGetScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetScoreComparison @ 00458D00
|
||||
* Callback: ZLeaderboard::GetScoreComparisonCallback @ 00624360
|
||||
* ReturnType: ZOEntry
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getScoreComparison = new()
|
||||
{
|
||||
Name = "GetScoreComparison",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"{SchemaNamespace}.ScoreComparison",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardtype",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetScoreComparison")]
|
||||
public IActionResult GetScoreComparison()
|
||||
{
|
||||
return JsonEntryResponse(new ScoreComparison
|
||||
{
|
||||
//NOTE: Has to be a SteamID
|
||||
FriendName = "76561198161220058",
|
||||
FriendScore = 1337,
|
||||
CountryAverage = 101,
|
||||
WorldAverage = 101
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetScores @ 007FA160
|
||||
* Callback: ZLeaderboard::GetScoresCallback @ 007FD3D0
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getScores = new()
|
||||
{
|
||||
Name = "GetScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.ScoreEntry)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardtype",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "filter",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "startindex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "range",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetScores")]
|
||||
public IActionResult GetScores()
|
||||
{
|
||||
return JsonFeedResponse(_mockedGetScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::RetrieveUserOverviewData @ 006DF920
|
||||
* Callback: ZContractManager::RetrieveUserOverviewDataCallback @ 00554640
|
||||
* ReturnType: ZOEntry
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getUserOverviewData = new()
|
||||
{
|
||||
Name = "GetUserOverviewData",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"{SchemaNamespace}.GetUserOverviewData",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetUserOverviewData")]
|
||||
public IActionResult GetUserOverviewData()
|
||||
{
|
||||
return JsonEntryResponse(new GetUserOverviewData
|
||||
{
|
||||
ContractPlays = 1337,
|
||||
CompetitionPlays = 1337,
|
||||
ContractsCreated = 1337,
|
||||
ContractsCreatedLikes = 1337,
|
||||
DeadliestAverage = 1337,
|
||||
DeadliestRank = 1337,
|
||||
PopularAverage = 1337,
|
||||
PopularRank = 1337,
|
||||
RichestAverage = 1337,
|
||||
RichestRank = 1337,
|
||||
TrophiesEarned = 1337,
|
||||
WalletAmount = 1337
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::GetUserWallet @ 00525090
|
||||
* Callback: ZContractManager::GetUserWalletCallback @ 008BBBC0
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getUserWallet = new()
|
||||
{
|
||||
Name = "GetUserWallet",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetUserWallet")]
|
||||
public IActionResult GetUserWallet()
|
||||
{
|
||||
return JsonOperationValueResponse(1_000_000);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::UpdateCompetition @ 006E50B0
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _inviteToCompetition = new()
|
||||
{
|
||||
Name = "InviteToCompetition",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "fromId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "participants",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "competitionId",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("InviteToCompetition")]
|
||||
public IActionResult InviteToCompetition()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractPlayer::Activate @ 006DFD10
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _markContractAsPlayed = new()
|
||||
{
|
||||
Name = "MarkContractAsPlayed",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "contractId",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("MarkContractAsPlayed")]
|
||||
public IActionResult MarkContractAsPlayed()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::MergeUserTokensAsync @ 00683F60
|
||||
* Callback: ZContractManager::MergeUserTokensAsyncCallback @ 0089A170
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _mergeUserTokens = new()
|
||||
{
|
||||
Name = "MergeUserTokens",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.UserTokenData)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "tokenData",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("MergeUserTokens")]
|
||||
public IActionResult MergeUserTokens()
|
||||
{
|
||||
//NOTE: tokenData needs further parsing
|
||||
return JsonFeedResponse(new List<UserTokenData>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using HM5.Server.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
public partial class HitmanController
|
||||
{
|
||||
[HttpGet]
|
||||
[Route("os_getStatus")]
|
||||
public IActionResult GetStatus()
|
||||
{
|
||||
return JsonGenericResponse(new OSGetStatus
|
||||
{
|
||||
ClientIP = "127.0.0.1"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
public partial class HitmanController
|
||||
{
|
||||
[HttpGet]
|
||||
[Route("$os_metadata")]
|
||||
public IActionResult Metadata()
|
||||
{
|
||||
return JsonGenericResponse(_metadataService.GetMetadata());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::UploadScore @ 00915670
|
||||
* Callback: ZLeaderboard::UploadScoreCallback @ 004630A0
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _putScore = new()
|
||||
{
|
||||
Name = "PutScore",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardtype",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "score",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "rating",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("PutScore")]
|
||||
public IActionResult PutScore()
|
||||
{
|
||||
//NOTE: Appears to be the difference between your new and last (personal best) score
|
||||
return JsonOperationValueResponse(1337);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::AddContractToQueue @ 004DCF90
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _queueAddContract = new()
|
||||
{
|
||||
Name = "QueueAddContract",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "contractid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("QueueAddContract")]
|
||||
public IActionResult QueueAddContract()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::ChangeLevel @ 00646AD0
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _queueRemoveContract = new()
|
||||
{
|
||||
Name = "QueueRemoveContract",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "contractid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("QueueRemoveContract")]
|
||||
public IActionResult QueueRemoveContract()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke:
|
||||
* - ZContractManager::ReportContract @ 0044DDF0
|
||||
* - ZContractManager::ReportContract @ 0049E220
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _reportContract = new()
|
||||
{
|
||||
Name = "ReportContract",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "contractid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "reason",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("ReportContract")]
|
||||
public IActionResult ReportContract()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractSearchEngine::Retrieve @ 0051C9F0
|
||||
* Callback: ZContractSearchEngine::RetrieveCallback @ 5DF560
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _searchForContracts2 = new()
|
||||
{
|
||||
Name = "SearchForContracts2",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.Contract)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "view",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "sort",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "levelindex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "checkpointid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "categoryid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "difficulty",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "contractid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "contractname",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "startindex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "range",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("SearchForContracts2")]
|
||||
public IActionResult SearchForContracts2()
|
||||
{
|
||||
return JsonFeedResponse(new List<Contract>
|
||||
{
|
||||
_mockedContractWithoutCompetition,
|
||||
_mockedContractWithCompetition
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke:
|
||||
* - ZMessageManager::SendMessageToSelf @ 005B5A20
|
||||
* - ZMessageManager::SendMessageToUsersFriends @ 0073AB00
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _sendTemplatedMessage = new()
|
||||
{
|
||||
Name = "SendTemplatedMessage",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "fromId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "toUserId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "tabgroup",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "category",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "templateId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "data",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("SendTemplatedMessage")]
|
||||
public IActionResult SendTemplatedMessage()
|
||||
{
|
||||
//NOTE: toUserId will be "----Friends----" if it's called from SendMessageToUsersFriends
|
||||
//NOTE: tabgroup will be "1" if it's called from SendMessageToSelf
|
||||
//NOTE: data might contain data that needs additional parsing
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZMessageManager::MarkMessageAsRead @ 0083A8A0
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _setMessageReadStatus = new()
|
||||
{
|
||||
Name = "SetMessageReadStatus",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "messageId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "isRead",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("SetMessageReadStatus")]
|
||||
public IActionResult SetMessageReadStatus()
|
||||
{
|
||||
//NOTE: isRead will always be set to "true"
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractManager::UpdateLikesDislikes @ 0060FC20
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _updateContractLikeDislikes = new()
|
||||
{
|
||||
Name = "UpdateContractLikeDislikes",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "fromUserId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "contractId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "likesIncrement",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "dislikesIncrement",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UpdateContractLikeDislikes")]
|
||||
public IActionResult UpdateContractLikeDislikes()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZOnlineManager::UploadDLCToken @ 0042AA0
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _updateDLCInfo = new()
|
||||
{
|
||||
Name = "UpdateDLCInfo",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "dlctokens",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UpdateDLCInfo")]
|
||||
public IActionResult UpdateDLCInfo()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZOnlineManager::UploadProfile @ 007ADF30
|
||||
* Callback: ZOnlineManager::OnUpdateUserProfile @ 006FB440
|
||||
* ReturnType: None, but 200 - OK.
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _updateUserInfo = new()
|
||||
{
|
||||
Name = "UpdateUserInfo",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "displayName",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "country",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "friends",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UpdateUserInfo")]
|
||||
public IActionResult UpdateUserInfo()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZOnlineManager::UploadProfileChallenges @ 008DE580
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _updateUserProfileChallenges = new()
|
||||
{
|
||||
Name = "UpdateUserProfileChallenges",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "data",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UpdateUserProfileChallenges")]
|
||||
public IActionResult UpdateUserProfileChallenges()
|
||||
{
|
||||
//NOTE: data contains a data that needs to be parsed
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZOnlineManager::UploadProfileGameStats @ 0090A2D0
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _updateUserProfileGameStats = new()
|
||||
{
|
||||
Name = "UpdateUserProfileGameStats",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "data",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UpdateUserProfileGameStats")]
|
||||
public IActionResult UpdateUserProfileGameStats()
|
||||
{
|
||||
//NOTE: data contains a data that needs to be parsed
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZOnlineManager::UploadProfileLevelProgression @ 004613F0
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _updateUserProfileLevelProgression = new()
|
||||
{
|
||||
Name = "UpdateUserProfileLevelProgression",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "data",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UpdateUserProfileLevelProgression")]
|
||||
public IActionResult UpdateUserProfileLevelProgression()
|
||||
{
|
||||
//NOTE: data contains a data that needs to be parsed
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZOnlineManager::UploadProfileSpecialRatings @ 0054AB20
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _updateUserProfileSpecialRatings = new()
|
||||
{
|
||||
Name = "UpdateUserProfileSpecialRatings",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "data",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UpdateUserProfileSpecialRatings")]
|
||||
public IActionResult UpdateUserProfileSpecialRatings()
|
||||
{
|
||||
//NOTE: data contains a data that needs to be parsed
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Hitman
|
||||
{
|
||||
/**
|
||||
* Invoke: ZContractCreator::SaveContract @ 005A7150
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class HitmanController
|
||||
{
|
||||
private static readonly EdmFunctionImport _uploadContract = new()
|
||||
{
|
||||
Name = "UploadContract",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "levelIndex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "checkpointIndex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "difficulty",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "exitId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "title",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "description",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "score",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "startingweapontoken",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "startingoutfittoken",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "competitionParticipants",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "competitionAllowInvites",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "competitionDuration",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "targetsJson",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "restrictionsJson",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "metacategoriesJson",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UploadContract")]
|
||||
public IActionResult UploadContract()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
using HM5.Server.Interfaces;
|
||||
using HM5.Server.Models;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
[Route("sniper")]
|
||||
public partial class SniperController : BaseController
|
||||
{
|
||||
private readonly List<SniperScoreEntry> _mockedGetScoresResponse = new()
|
||||
{
|
||||
new SniperScoreEntry
|
||||
{
|
||||
UserId = "76561197989140534",
|
||||
Rank = 1,
|
||||
Score = 1989
|
||||
},
|
||||
new SniperScoreEntry
|
||||
{
|
||||
UserId = "76561198025604927",
|
||||
Rank = 2,
|
||||
Score = 1989
|
||||
},
|
||||
new SniperScoreEntry
|
||||
{
|
||||
UserId = "76561198215015615",
|
||||
Rank = 3,
|
||||
Score = 1989
|
||||
},
|
||||
new SniperScoreEntry
|
||||
{
|
||||
UserId = "76561198161220058",
|
||||
Rank = 4,
|
||||
Score = 1989
|
||||
}
|
||||
};
|
||||
|
||||
public const string SchemaNamespace = "Sniper";
|
||||
|
||||
private readonly IMetadataService _metadataService;
|
||||
|
||||
public SniperController(
|
||||
ISimpleLogger simpleLogger,
|
||||
IMetadataServiceForSniper metadataService
|
||||
)
|
||||
: base(simpleLogger)
|
||||
{
|
||||
_metadataService = metadataService;
|
||||
}
|
||||
|
||||
public static List<EdmFunctionImport> GetEdmFunctionImports()
|
||||
{
|
||||
return new List<EdmFunctionImport>
|
||||
{
|
||||
_sendTemplatedMessage,
|
||||
_setMessageReadStatus,
|
||||
_getMessages,
|
||||
_getNewMessageCount,
|
||||
_updateUserProfile,
|
||||
_putScore,
|
||||
_getScores,
|
||||
_getPerformanceIndexAll
|
||||
};
|
||||
}
|
||||
|
||||
public static List<Type> GetEdmEntityTypes()
|
||||
{
|
||||
return new List<Type>
|
||||
{
|
||||
typeof(SniperScoreEntry),
|
||||
typeof(SniperMessage)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
public partial class SniperController
|
||||
{
|
||||
[HttpPost]
|
||||
[Route("AddMetrics")]
|
||||
public IActionResult AddMetrics([FromBody] JsonDocument json)
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
/**
|
||||
* Invoke:
|
||||
* - ZMessageManager::GetOnlineMessages @ 00800AA00
|
||||
* - ZMessageManager::GetNewOnlineMessages @ 00800E60
|
||||
* Callback:
|
||||
* - ZMessageManager::OnGetMessagesComplete @ 00800780
|
||||
* - ZMessageManager::OnGetNewMessagesComplete @ 008009F0
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class SniperController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getMessages = new()
|
||||
{
|
||||
Name = "GetMessages",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.Message)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "tabgroup",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "languageId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "skip",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "limit",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetMessages")]
|
||||
public IActionResult GetMessages()
|
||||
{
|
||||
return JsonFeedResponse(new List<SniperMessage>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = 5000,
|
||||
FromId = "76561198161220058",
|
||||
Category = 1,
|
||||
TextTemplateId = 0,
|
||||
TemplateData = "Heya!",
|
||||
TimestampUTC = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
||||
},
|
||||
new()
|
||||
{
|
||||
Id = 5001,
|
||||
FromId = "76561198161220058",
|
||||
Category = 1,
|
||||
TextTemplateId = 0,
|
||||
TemplateData = "Heya {userid}!",
|
||||
TimestampUTC = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
/**
|
||||
* Invoke: ZMessageManager::Update @ 00801320
|
||||
* Callback: ZMessageManager::OnGetNewMessageCountComplete @ 008011F0
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class SniperController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getNewMessageCount = new()
|
||||
{
|
||||
Name = "GetNewMessageCount",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userId",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetNewMessageCount")]
|
||||
public IActionResult GetNewMessageCount()
|
||||
{
|
||||
//NOTE: GetNewMessageCount doesn't care for the name of the Key
|
||||
return JsonOperationValueResponse(10);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
/**
|
||||
* Invoke: ZUnknown::GetPerformanceIndexAll @ 0080E890
|
||||
* Callback: ZUnknown::GetPerformanceIndexAllCallback @ 0080E4B0
|
||||
* ReturnType: ZOServiceOperationResult
|
||||
*/
|
||||
public partial class SniperController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getPerformanceIndexAll = new()
|
||||
{
|
||||
Name = "GetPerformanceIndexAll",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetPerformanceIndexAll")]
|
||||
public IActionResult GetPerformanceIndexAll()
|
||||
{
|
||||
//NOTE: Different performance percentages are at: 0, 0.55, 0.65, 0.75 and 1
|
||||
return JsonOperationListResponse(new List<float>
|
||||
{
|
||||
1, //Global
|
||||
0.65f, //Global percentage
|
||||
1, //National
|
||||
0.55f, //National percentage
|
||||
1, //Friends
|
||||
0.75f //Friends percentage
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::GetScores @ 0080E630
|
||||
* Callback: ZLeaderboard::GetScoresCallback @ 0080DF80
|
||||
* ReturnType: ZOFeed
|
||||
*/
|
||||
public partial class SniperController
|
||||
{
|
||||
private static readonly EdmFunctionImport _getScores = new()
|
||||
{
|
||||
Name = "GetScores",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = $"Collection({SchemaNamespace}.ScoreEntry)",
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "filter",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "startindex",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "range",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("GetScores")]
|
||||
public IActionResult GetScores()
|
||||
{
|
||||
//NOTE: leaderboardid is always 0
|
||||
return JsonFeedResponse(_mockedGetScoresResponse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using HM5.Server.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
public partial class SniperController
|
||||
{
|
||||
[HttpGet]
|
||||
[Route("os_getStatus")]
|
||||
public IActionResult GetStatus()
|
||||
{
|
||||
return JsonGenericResponse(new OSGetStatus
|
||||
{
|
||||
ClientIP = "127.0.0.1"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
public partial class SniperController
|
||||
{
|
||||
[HttpGet]
|
||||
[Route("$os_metadata")]
|
||||
public IActionResult Metadata()
|
||||
{
|
||||
return JsonGenericResponse(_metadataService.GetMetadata());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
/**
|
||||
* Invoke: ZLeaderboard::UploadScore @ 0080DE00
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class SniperController
|
||||
{
|
||||
private static readonly EdmFunctionImport _putScore = new()
|
||||
{
|
||||
Name = "PutScore",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "leaderboardid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "score",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("PutScore")]
|
||||
public IActionResult PutScore()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
/**
|
||||
* Invoke:
|
||||
* - ZMessageManager::SendMessageToUsersFriends @ 007FF900
|
||||
* - ZMessageManager::SendMessageToSelf @ 007FFCC0
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class SniperController
|
||||
{
|
||||
private static readonly EdmFunctionImport _sendTemplatedMessage = new()
|
||||
{
|
||||
Name = "SendTemplatedMessage",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "fromId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "toUserId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "tabgroup",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "category",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "templateId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "data",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("SendTemplatedMessage")]
|
||||
public IActionResult SendTemplatedMessage()
|
||||
{
|
||||
//NOTE: toUserId will be "----Friends----" if it's called from SendMessageToUsersFriends
|
||||
//NOTE: tabgroup will be "1" if it's called from SendMessageToSelf
|
||||
//NOTE: data might contain data that needs additional parsing
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
/**
|
||||
* Invoke: ZMessageManager::MarkMessageAsRead @ 00800010
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class SniperController
|
||||
{
|
||||
private static readonly EdmFunctionImport _setMessageReadStatus = new()
|
||||
{
|
||||
Name = "SetMessageReadStatus",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "messageId",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "isRead",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("SetMessageReadStatus")]
|
||||
public IActionResult SetMessageReadStatus()
|
||||
{
|
||||
//NOTE: isRead will always be set to "true"
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using HM5.Server.Enums;
|
||||
using HM5.Server.Models.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HM5.Server.Controllers.Sniper
|
||||
{
|
||||
/**
|
||||
* Invoke: ZOnlineManager::UploadProfile @ 0080DB10
|
||||
* Callback: None
|
||||
*/
|
||||
public partial class SniperController
|
||||
{
|
||||
private static readonly EdmFunctionImport _updateUserProfile = new()
|
||||
{
|
||||
Name = "UpdateUserProfile",
|
||||
HttpMethod = HttpMethods.GET,
|
||||
ReturnType = null,
|
||||
Parameters = new List<SFunctionParameter>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "userid",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "country",
|
||||
Type = EdmTypes.String
|
||||
},
|
||||
new()
|
||||
{
|
||||
Name = "friends",
|
||||
Type = EdmTypes.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
[Route("UpdateUserProfile")]
|
||||
public IActionResult UpdateUserProfile()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace HM5.Server.Enums
|
||||
{
|
||||
public enum ERestrictionType
|
||||
{
|
||||
TargetOnly = 0,
|
||||
SuitOnly = 1,
|
||||
PerfectShooter = 2,
|
||||
EraseTraces = 3,
|
||||
NoWitnesses = 4,
|
||||
Invalid = 255
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
namespace HM5.Server.Enums
|
||||
{
|
||||
public static class EdmTypes
|
||||
{
|
||||
public const string Null = "Null"; //0
|
||||
public const string Binary = "Edm.Binary"; //1
|
||||
public const string Boolean = "Edm.Boolean"; //2
|
||||
public const string Byte = "Edm.Byte"; //3
|
||||
public const string DateTime = "Edm.DateTime"; //4
|
||||
public const string DateTimeOffset = "Edm.DateTimeOffset"; //5
|
||||
public const string Decimal = "Edm.Decimal"; //6
|
||||
public const string Double = "Edm.Double"; //7
|
||||
public const string Guid = "Edm.Guid"; //8
|
||||
public const string Int16 = "Edm.Int16"; //9
|
||||
public const string Int32 = "Edm.Int32"; //10
|
||||
public const string Int64 = "Edm.Int64"; //11
|
||||
public const string SByte = "Edm.SByte"; //12
|
||||
public const string Single = "Edm.Single"; //13
|
||||
public const string String = "Edm.String"; //14
|
||||
public const string Time = "Edm.Time"; //15
|
||||
public const string ComplexType = "ComplexType"; //16
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace HM5.Server.Enums
|
||||
{
|
||||
public static class HttpMethods
|
||||
{
|
||||
public const string GET = "GET";
|
||||
public const string POST = "POST";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace HM5.Server.Enums
|
||||
{
|
||||
public static class Multiplicity
|
||||
{
|
||||
public const string Zero = "0";
|
||||
public const string One = "1";
|
||||
public const string Many = "*";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace HM5.Server.Enums
|
||||
{
|
||||
public static class Nullable
|
||||
{
|
||||
public const string True = "true";
|
||||
public const string False = "false";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace HM5.Server.Extensions
|
||||
{
|
||||
public static class ModelBindingContextExtensions
|
||||
{
|
||||
public static string NormalizeString(this ModelBindingContext bindingContext)
|
||||
{
|
||||
return bindingContext.ValueProvider
|
||||
.GetValue(bindingContext.ModelName).Values
|
||||
.FirstOrDefault()?
|
||||
.Trim('\'');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
global using HttpMethods = HM5.Server.Enums.HttpMethods;
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Logs\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,7 @@
|
|||
namespace HM5.Server.Interfaces
|
||||
{
|
||||
public interface IEdmEntity
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using HM5.Server.Models;
|
||||
|
||||
namespace HM5.Server.Interfaces
|
||||
{
|
||||
public interface IMetadataService
|
||||
{
|
||||
OSMetadata GetMetadata();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace HM5.Server.Interfaces
|
||||
{
|
||||
public interface IMetadataServiceForHitman : IMetadataService
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace HM5.Server.Interfaces
|
||||
{
|
||||
public interface IMetadataServiceForSniper : IMetadataService
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace HM5.Server.Interfaces
|
||||
{
|
||||
public interface ISimpleLogger
|
||||
{
|
||||
void WriteLine(string message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace HM5.Server.Json
|
||||
{
|
||||
public class AnyToJsonStringConverter<T> : JsonConverter<T>
|
||||
{
|
||||
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
||||
{
|
||||
//NOTE: options is purposely not passed on to the Serialize method, since the in-game JSON parser used to Deserialize this actually works fine with the default options.
|
||||
writer.WriteStringValue(JsonSerializer.Serialize(value));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Nullable = HM5.Server.Enums.Nullable;
|
||||
|
||||
namespace HM5.Server.Json
|
||||
{
|
||||
public class BooleanToStringConverter : JsonConverter<bool>
|
||||
{
|
||||
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value ? Nullable.True : Nullable.False);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace HM5.Server.Json
|
||||
{
|
||||
public class FloatToStringConverter : JsonConverter<float>
|
||||
{
|
||||
public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace HM5.Server.Json
|
||||
{
|
||||
public class IntegerToStringConverter : JsonConverter<int>
|
||||
{
|
||||
public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace HM5.Server.Models.Base
|
||||
{
|
||||
public class EdmAssociation
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<EdmEndRole> Ends { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace HM5.Server.Models.Base
|
||||
{
|
||||
public class EdmClientConfiguration
|
||||
{
|
||||
public int MetricsThreshold { get; set; }
|
||||
public int MetricsPriorityThreshold { get; set; }
|
||||
public bool UsageTrackingEnabled { get; set; }
|
||||
public int UsageTrackingSamplingInterval { get; set; }
|
||||
public int UsageTrackingMetricsInterval { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace HM5.Server.Models.Base
|
||||
{
|
||||
public class EdmComplexType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<EdmProperty> Properties { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace HM5.Server.Models.Base
|
||||
{
|
||||
public class EdmEndRole
|
||||
{
|
||||
public string Role { get; set; }
|
||||
public string Type { get; set; }
|
||||
|
||||
//NOTE: Game converts Many to 2, default is 0.
|
||||
public string Multiplicity { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace HM5.Server.Models.Base
|
||||
{
|
||||
public class EdmEntitySet
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string EntityType { get; set; }
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue