mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2025-01-03 16:13:36 +08:00
feat(lua): Allow lua scripts to flag modders with a custom reason if needed. (#2248)
This commit is contained in:
parent
3323e1c43f
commit
5515c841a1
@ -18,6 +18,7 @@ class DocKind(Enum):
|
|||||||
Constructor = "constructor"
|
Constructor = "constructor"
|
||||||
Function = "function"
|
Function = "function"
|
||||||
Tabs = "tabs"
|
Tabs = "tabs"
|
||||||
|
Infraction = "infraction"
|
||||||
|
|
||||||
|
|
||||||
class Table:
|
class Table:
|
||||||
@ -324,7 +325,10 @@ def parse_lua_api_doc(folder_path):
|
|||||||
.lower()
|
.lower()
|
||||||
)
|
)
|
||||||
|
|
||||||
if doc_kind is not DocKind.Tabs:
|
if (
|
||||||
|
doc_kind is not DocKind.Tabs
|
||||||
|
and doc_kind is not DocKind.Infraction
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if doc_kind is not None and "//" in line:
|
if doc_kind is not None and "//" in line:
|
||||||
@ -367,7 +371,10 @@ def parse_lua_api_doc(folder_path):
|
|||||||
line,
|
line,
|
||||||
line_lower,
|
line_lower,
|
||||||
)
|
)
|
||||||
case DocKind.Tabs: parse_tabs_doc(file)
|
case DocKind.Tabs:
|
||||||
|
parse_tabs_doc(file)
|
||||||
|
case DocKind.Infraction:
|
||||||
|
parse_infraction_doc(file)
|
||||||
case _:
|
case _:
|
||||||
# print("unsupported doc kind: " + str(doc_kind))
|
# print("unsupported doc kind: " + str(doc_kind))
|
||||||
pass
|
pass
|
||||||
@ -386,6 +393,7 @@ def parse_table_doc(cur_table, line, line_lower):
|
|||||||
|
|
||||||
return cur_table
|
return cur_table
|
||||||
|
|
||||||
|
|
||||||
def parse_class_doc(cur_class, line, line_lower):
|
def parse_class_doc(cur_class, line, line_lower):
|
||||||
if is_lua_doc_comment_startswith(line_lower, "name"):
|
if is_lua_doc_comment_startswith(line_lower, "name"):
|
||||||
class_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
class_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
||||||
@ -402,28 +410,43 @@ def parse_class_doc(cur_class, line, line_lower):
|
|||||||
|
|
||||||
|
|
||||||
def parse_function_doc(cur_function, cur_table, cur_class, line, line_lower):
|
def parse_function_doc(cur_function, cur_table, cur_class, line, line_lower):
|
||||||
if is_lua_doc_comment_startswith(line_lower, "table") and lua_api_comment_separator in line_lower:
|
if (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "table")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
table_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
table_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
||||||
cur_table = make_table(table_name)
|
cur_table = make_table(table_name)
|
||||||
|
|
||||||
cur_function = Function("Didnt get name yet", cur_table, [], None, "", "")
|
cur_function = Function("Didnt get name yet", cur_table, [], None, "", "")
|
||||||
cur_table.functions.append(cur_function)
|
cur_table.functions.append(cur_function)
|
||||||
elif is_lua_doc_comment_startswith(line_lower, "class") and lua_api_comment_separator in line_lower:
|
elif (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "class")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
class_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
class_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
||||||
cur_class = make_class(class_name)
|
cur_class = make_class(class_name)
|
||||||
|
|
||||||
cur_function = Function("Didnt get name yet", cur_class, [], None, "", "")
|
cur_function = Function("Didnt get name yet", cur_class, [], None, "", "")
|
||||||
cur_class.functions.append(cur_function)
|
cur_class.functions.append(cur_function)
|
||||||
elif is_lua_doc_comment_startswith(line_lower, "name") and lua_api_comment_separator in line_lower:
|
elif (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "name")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
function_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
function_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
||||||
cur_function.name = function_name
|
cur_function.name = function_name
|
||||||
|
|
||||||
if function_name not in functions:
|
if function_name not in functions:
|
||||||
functions[function_name] = cur_function
|
functions[function_name] = cur_function
|
||||||
elif is_lua_doc_comment_startswith(line_lower, "param") and lua_api_comment_separator in line_lower:
|
elif (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "param")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
parameter = make_parameter_from_doc_line(line)
|
parameter = make_parameter_from_doc_line(line)
|
||||||
cur_function.parameters.append(parameter)
|
cur_function.parameters.append(parameter)
|
||||||
elif is_lua_doc_comment_startswith(line_lower, "return") and lua_api_comment_separator in line_lower:
|
elif (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "return")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
return_info = line.split(lua_api_comment_separator, 2)
|
return_info = line.split(lua_api_comment_separator, 2)
|
||||||
try:
|
try:
|
||||||
cur_function.return_type = return_info[1].strip()
|
cur_function.return_type = return_info[1].strip()
|
||||||
@ -439,19 +462,28 @@ def parse_function_doc(cur_function, cur_table, cur_class, line, line_lower):
|
|||||||
|
|
||||||
|
|
||||||
def parse_field_doc(cur_field, cur_table, cur_class, line, line_lower):
|
def parse_field_doc(cur_field, cur_table, cur_class, line, line_lower):
|
||||||
if is_lua_doc_comment_startswith(line_lower, "table") and lua_api_comment_separator in line_lower:
|
if (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "table")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
table_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
table_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
||||||
cur_table = make_table(table_name)
|
cur_table = make_table(table_name)
|
||||||
|
|
||||||
cur_field = Field("Didnt get name yet", "", "")
|
cur_field = Field("Didnt get name yet", "", "")
|
||||||
cur_table.fields.append(cur_field)
|
cur_table.fields.append(cur_field)
|
||||||
elif is_lua_doc_comment_startswith(line_lower, "class") and lua_api_comment_separator in line_lower:
|
elif (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "class")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
class_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
class_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
||||||
cur_class = make_class(class_name)
|
cur_class = make_class(class_name)
|
||||||
|
|
||||||
cur_field = Field("Didnt get name yet", "", "")
|
cur_field = Field("Didnt get name yet", "", "")
|
||||||
cur_class.fields.append(cur_field)
|
cur_class.fields.append(cur_field)
|
||||||
elif is_lua_doc_comment_startswith(line_lower, "field") and lua_api_comment_separator in line_lower:
|
elif (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "field")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
field_info = line.split(lua_api_comment_separator, 2)
|
field_info = line.split(lua_api_comment_separator, 2)
|
||||||
cur_field.name = field_info[1].strip()
|
cur_field.name = field_info[1].strip()
|
||||||
cur_field.type_ = field_info[2].strip()
|
cur_field.type_ = field_info[2].strip()
|
||||||
@ -467,13 +499,19 @@ def parse_field_doc(cur_field, cur_table, cur_class, line, line_lower):
|
|||||||
|
|
||||||
|
|
||||||
def parse_constructor_doc(cur_constructor, cur_class, line, line_lower):
|
def parse_constructor_doc(cur_constructor, cur_class, line, line_lower):
|
||||||
if is_lua_doc_comment_startswith(line_lower, "class") and lua_api_comment_separator in line_lower:
|
if (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "class")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
class_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
class_name = line.split(lua_api_comment_separator, 1)[1].strip()
|
||||||
cur_class = make_class(class_name)
|
cur_class = make_class(class_name)
|
||||||
|
|
||||||
cur_constructor = Constructor(cur_class, [], "")
|
cur_constructor = Constructor(cur_class, [], "")
|
||||||
cur_class.constructors.append(cur_constructor)
|
cur_class.constructors.append(cur_constructor)
|
||||||
elif is_lua_doc_comment_startswith(line_lower, "param") and lua_api_comment_separator in line_lower:
|
elif (
|
||||||
|
is_lua_doc_comment_startswith(line_lower, "param")
|
||||||
|
and lua_api_comment_separator in line_lower
|
||||||
|
):
|
||||||
parameter = make_parameter_from_doc_line(line)
|
parameter = make_parameter_from_doc_line(line)
|
||||||
cur_constructor.parameters.append(parameter)
|
cur_constructor.parameters.append(parameter)
|
||||||
else:
|
else:
|
||||||
@ -485,6 +523,8 @@ def parse_constructor_doc(cur_constructor, cur_class, line, line_lower):
|
|||||||
|
|
||||||
|
|
||||||
tabs_enum = []
|
tabs_enum = []
|
||||||
|
|
||||||
|
|
||||||
def parse_tabs_doc(file):
|
def parse_tabs_doc(file):
|
||||||
start_parsing = False
|
start_parsing = False
|
||||||
for line in file:
|
for line in file:
|
||||||
@ -503,7 +543,29 @@ def parse_tabs_doc(file):
|
|||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
tabs_enum.append(line.replace(",", "").strip())
|
tabs_enum.append(line.replace(",", "").strip())
|
||||||
|
|
||||||
|
|
||||||
|
infraction_enum = []
|
||||||
|
|
||||||
|
|
||||||
|
def parse_infraction_doc(file):
|
||||||
|
start_parsing = False
|
||||||
|
for line in file:
|
||||||
|
if "enum class" in line.lower():
|
||||||
|
start_parsing = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if start_parsing:
|
||||||
|
if "};" in line.lower():
|
||||||
|
return
|
||||||
|
if "{" == line.lower().strip():
|
||||||
|
continue
|
||||||
|
if "//" in line.lower():
|
||||||
|
continue
|
||||||
|
if "" == line.lower().strip():
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
infraction_enum.append(line.replace(",", "").strip())
|
||||||
|
|
||||||
|
|
||||||
def make_parameter_from_doc_line(line):
|
def make_parameter_from_doc_line(line):
|
||||||
@ -519,13 +581,15 @@ def make_parameter_from_doc_line(line):
|
|||||||
|
|
||||||
return Parameter(param_name, param_type, param_desc)
|
return Parameter(param_name, param_type, param_desc)
|
||||||
|
|
||||||
|
|
||||||
def sanitize_description(line):
|
def sanitize_description(line):
|
||||||
if line.startswith("// ") and line[3] != ' ':
|
if line.startswith("// ") and line[3] != " ":
|
||||||
line = line[3:]
|
line = line[3:]
|
||||||
if line.startswith("//"):
|
if line.startswith("//"):
|
||||||
line = line[2:]
|
line = line[2:]
|
||||||
return line.rstrip()
|
return line.rstrip()
|
||||||
|
|
||||||
|
|
||||||
def is_lua_doc_comment_startswith(line_lower, starts_with_text):
|
def is_lua_doc_comment_startswith(line_lower, starts_with_text):
|
||||||
return line_lower.replace("//", "").strip().startswith(starts_with_text)
|
return line_lower.replace("//", "").strip().startswith(starts_with_text)
|
||||||
|
|
||||||
@ -550,7 +614,8 @@ if os.path.exists(tabs_file_name):
|
|||||||
os.remove(tabs_file_name)
|
os.remove(tabs_file_name)
|
||||||
f = open(tabs_file_name, "a")
|
f = open(tabs_file_name, "a")
|
||||||
|
|
||||||
f.write("""# Tabs
|
f.write(
|
||||||
|
"""# Tabs
|
||||||
|
|
||||||
All the tabs from the menu are listed below, used as parameter for adding gui elements to them.
|
All the tabs from the menu are listed below, used as parameter for adding gui elements to them.
|
||||||
|
|
||||||
@ -565,16 +630,42 @@ end)
|
|||||||
|
|
||||||
For a complete list of available gui functions, please refer to the tab class documentation and the gui table documentation.
|
For a complete list of available gui functions, please refer to the tab class documentation and the gui table documentation.
|
||||||
|
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
f.write(f"## Tab Count: {len(tabs_enum)}\n\n")
|
f.write(f"## Tab Count: {len(tabs_enum)}\n\n")
|
||||||
|
|
||||||
# Minus the first, because it's the `NONE` tab, minus the last one because it's for runtime defined tabs.
|
# Minus the first, because it's the `NONE` tab, minus the last one because it's for runtime defined tabs.
|
||||||
for i in range(1, len(tabs_enum) - 1 ):
|
for i in range(1, len(tabs_enum) - 1):
|
||||||
f.write("### `GUI_TAB_" + tabs_enum[i] + "`\n")
|
f.write("### `GUI_TAB_" + tabs_enum[i] + "`\n")
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
infraction_file_name = f"../lua/infraction.md"
|
||||||
|
if os.path.exists(infraction_file_name):
|
||||||
|
os.remove(infraction_file_name)
|
||||||
|
f = open(infraction_file_name, "a")
|
||||||
|
|
||||||
|
f.write(
|
||||||
|
"""# Infraction
|
||||||
|
|
||||||
|
All the infraction from the menu are listed below, used as parameter for adding an infraction to a given player, for flagging them as modder.
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
```lua
|
||||||
|
network.flag_player_as_modder(player_index, infraction.CUSTOM_REASON, "My custom reason on why the player is flagged as a modder")
|
||||||
|
```
|
||||||
|
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
f.write(f"## Infraction Count: {len(infraction_enum)}\n\n")
|
||||||
|
|
||||||
|
for i in range(0, len(infraction_enum)):
|
||||||
|
f.write("### `" + infraction_enum[i] + "`\n")
|
||||||
|
|
||||||
|
f.close()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.makedirs("./classes/")
|
os.makedirs("./classes/")
|
||||||
except:
|
except:
|
||||||
@ -589,13 +680,13 @@ for class_name, class_ in classes.items():
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
commands_file_name = f"./commands.md"
|
commands_file_name = f"./commands.md"
|
||||||
if os.path.exists(commands_file_name):
|
if os.path.exists(commands_file_name):
|
||||||
os.remove(commands_file_name)
|
os.remove(commands_file_name)
|
||||||
f = open(commands_file_name, "a")
|
f = open(commands_file_name, "a")
|
||||||
|
|
||||||
f.write("""# Commands
|
f.write(
|
||||||
|
"""# Commands
|
||||||
|
|
||||||
All the current commands from the menu are listed below.
|
All the current commands from the menu are listed below.
|
||||||
|
|
||||||
@ -608,7 +699,8 @@ command.call_player(somePlayerIndex, "spawn", {joaat("adder")})
|
|||||||
|
|
||||||
For a complete list of available command functions, please refer to the command table documentation.
|
For a complete list of available command functions, please refer to the command table documentation.
|
||||||
|
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
commands = []
|
commands = []
|
||||||
@ -629,4 +721,4 @@ for cmd in commands:
|
|||||||
f.write(f"Arg Count: {arg_count}\n")
|
f.write(f"Arg Count: {arg_count}\n")
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
|
23
docs/lua/infraction.md
Normal file
23
docs/lua/infraction.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Infraction
|
||||||
|
|
||||||
|
All the infraction from the menu are listed below, used as parameter for adding an infraction to a given player, for flagging them as modder.
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
```lua
|
||||||
|
network.flag_player_as_modder(player_index, infraction.CUSTOM_REASON, "My custom reason on why the player is flagged as a modder")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Infraction Count: 12
|
||||||
|
|
||||||
|
### `TRIGGERED_ANTICHEAT`
|
||||||
|
### `TRIED_CRASH_PLAYER`
|
||||||
|
### `TRIED_KICK_PLAYER`
|
||||||
|
### `ATTACKING_WITH_GODMODE`
|
||||||
|
### `ATTACKING_WITH_INVISIBILITY`
|
||||||
|
### `ATTACKING_WHEN_HIDDEN_FROM_PLAYER_LIST`
|
||||||
|
### `SPOOFED_DATA`
|
||||||
|
### `SPOOFED_HOST_TOKEN`
|
||||||
|
### `INVALID_PLAYER_MODEL`
|
||||||
|
### `SUPER_JUMP`
|
||||||
|
### `UNDEAD_OTR`
|
||||||
|
### `CUSTOM_REASON`
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Table containing helper functions for network related features.
|
Table containing helper functions for network related features.
|
||||||
|
|
||||||
## Functions (10)
|
## Functions (11)
|
||||||
|
|
||||||
### `trigger_script_event(bitset, _args)`
|
### `trigger_script_event(bitset, _args)`
|
||||||
|
|
||||||
@ -79,16 +79,18 @@ integer = network.get_selected_player()
|
|||||||
integer = network.get_selected_database_player_rockstar_id()
|
integer = network.get_selected_database_player_rockstar_id()
|
||||||
```
|
```
|
||||||
|
|
||||||
### `flag_player_as_modder(player_idx)`
|
### `flag_player_as_modder(player_idx, reason, custom_reason)`
|
||||||
|
|
||||||
Flags the given player as a modder in our local database.
|
Flags the given player as a modder in our local database.
|
||||||
|
|
||||||
- **Parameters:**
|
- **Parameters:**
|
||||||
- `player_idx` (integer): Index of the player.
|
- `player_idx` (integer): Index of the player.
|
||||||
|
- `reason` (Infraction): Reason why the player is flagged as a modder, if the infraction is CUSTOM_REASON, then the custom_reason string is added in the local database. For a full list of the possible infraction reasons to use, please check the infraction page.
|
||||||
|
- `custom_reason` (string): Optional, required only when the infraction is CUSTOM_REASON. The custom reason why the player is flagged as a modder.
|
||||||
|
|
||||||
**Example Usage:**
|
**Example Usage:**
|
||||||
```lua
|
```lua
|
||||||
network.flag_player_as_modder(player_idx)
|
network.flag_player_as_modder(player_idx, reason, custom_reason)
|
||||||
```
|
```
|
||||||
|
|
||||||
### `is_player_flagged_as_modder(player_idx)`
|
### `is_player_flagged_as_modder(player_idx)`
|
||||||
@ -104,6 +106,19 @@ network.flag_player_as_modder(player_idx)
|
|||||||
boolean = network.is_player_flagged_as_modder(player_idx)
|
boolean = network.is_player_flagged_as_modder(player_idx)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `get_flagged_modder_reason(player_idx)`
|
||||||
|
|
||||||
|
- **Parameters:**
|
||||||
|
- `player_idx` (integer): Index of the player.
|
||||||
|
|
||||||
|
- **Returns:**
|
||||||
|
- `string`: Returns a string which contains the reason(s) why the player is flagged as a modder.
|
||||||
|
|
||||||
|
**Example Usage:**
|
||||||
|
```lua
|
||||||
|
string = network.get_flagged_modder_reason(player_idx)
|
||||||
|
```
|
||||||
|
|
||||||
### `force_script_host(script_name)`
|
### `force_script_host(script_name)`
|
||||||
|
|
||||||
Try to force ourself to be host for the given GTA Script.
|
Try to force ourself to be host for the given GTA Script.
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "gta/joaat.hpp"
|
|
||||||
|
|
||||||
namespace big
|
namespace big
|
||||||
{
|
{
|
||||||
// Add new values to the bottom
|
// Lua API: Infraction
|
||||||
enum class Infraction
|
enum class Infraction
|
||||||
{
|
{
|
||||||
|
// Add new values to the bottom (for serialization)
|
||||||
|
|
||||||
DESYNC_PROTECTION, // do not use
|
DESYNC_PROTECTION, // do not use
|
||||||
BREAKUP_KICK_DETECTED, // do not use
|
BREAKUP_KICK_DETECTED, // do not use
|
||||||
LOST_CONNECTION_KICK_DETECTED, // do not use
|
LOST_CONNECTION_KICK_DETECTED, // do not use
|
||||||
@ -22,24 +23,7 @@ namespace big
|
|||||||
INVALID_PLAYER_MODEL,
|
INVALID_PLAYER_MODEL,
|
||||||
SUPER_JUMP,
|
SUPER_JUMP,
|
||||||
UNDEAD_OTR,
|
UNDEAD_OTR,
|
||||||
};
|
// So that lua scripts can add a custom runtime reason.
|
||||||
|
CUSTOM_REASON,
|
||||||
inline std::unordered_map<Infraction, const char*> infraction_desc = {
|
|
||||||
{Infraction::DESYNC_PROTECTION, "Used desync protections"},
|
|
||||||
{Infraction::BREAKUP_KICK_DETECTED, "Kicked someone using breakup kick"},
|
|
||||||
{Infraction::LOST_CONNECTION_KICK_DETECTED, "Tried to kick someone using lost connection kick"},
|
|
||||||
{Infraction::SPOOFED_ROCKSTAR_ID, "Had spoofed RID"},
|
|
||||||
{Infraction::TRIGGERED_ANTICHEAT, "Triggered Rockstar's anticheat"},
|
|
||||||
{Infraction::TRIED_CRASH_PLAYER, "Tried to crash you"},
|
|
||||||
{Infraction::TRIED_KICK_PLAYER, "Tried to kick you"},
|
|
||||||
{Infraction::BLAME_EXPLOSION_DETECTED, "Tried to blame someone for their explosion"},
|
|
||||||
{Infraction::ATTACKING_WITH_GODMODE, "Attacked someone while using godmode"},
|
|
||||||
{Infraction::ATTACKING_WITH_INVISIBILITY, "Attacked someone while being invisible"},
|
|
||||||
{Infraction::ATTACKING_WHEN_HIDDEN_FROM_PLAYER_LIST, "Attacked someone while being hidden from the player list"},
|
|
||||||
{Infraction::SPOOFED_DATA, "Had spoofed data"},
|
|
||||||
{Infraction::SPOOFED_HOST_TOKEN, "Had spoofed their host token"},
|
|
||||||
{Infraction::INVALID_PLAYER_MODEL, "Had used an invalid player model"},
|
|
||||||
{Infraction::SUPER_JUMP, "Had used super jump"},
|
|
||||||
{Infraction::UNDEAD_OTR, "Had used undead OTR"},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -6,6 +6,7 @@
|
|||||||
#include "services/player_database/player_database_service.hpp"
|
#include "services/player_database/player_database_service.hpp"
|
||||||
#include "util/notify.hpp"
|
#include "util/notify.hpp"
|
||||||
#include "util/scripts.hpp"
|
#include "util/scripts.hpp"
|
||||||
|
#include "util/session.hpp"
|
||||||
#include "util/system.hpp"
|
#include "util/system.hpp"
|
||||||
#include "util/teleport.hpp"
|
#include "util/teleport.hpp"
|
||||||
|
|
||||||
@ -100,19 +101,26 @@ namespace lua::network
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void flag_player_as_modder(int player_idx, big::Infraction reason)
|
||||||
|
{
|
||||||
|
if (auto player = big::g_player_service->get_by_id(player_idx))
|
||||||
|
{
|
||||||
|
big::session::add_infraction(player, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Lua API: Function
|
// Lua API: Function
|
||||||
// Table: network
|
// Table: network
|
||||||
// Name: flag_player_as_modder
|
// Name: flag_player_as_modder
|
||||||
// Param: player_idx: integer: Index of the player.
|
// Param: player_idx: integer: Index of the player.
|
||||||
|
// Param: reason: Infraction: Reason why the player is flagged as a modder, if the infraction is CUSTOM_REASON, then the custom_reason string is added in the local database. For a full list of the possible infraction reasons to use, please check the infraction page.
|
||||||
|
// Param: custom_reason: string: Optional, required only when the infraction is CUSTOM_REASON. The custom reason why the player is flagged as a modder.
|
||||||
// Flags the given player as a modder in our local database.
|
// Flags the given player as a modder in our local database.
|
||||||
static void flag_player_as_modder(int player_idx)
|
static void flag_player_as_modder_custom_reason(int player_idx, big::Infraction reason, const std::string& custom_reason)
|
||||||
{
|
{
|
||||||
if (auto player = big::g_player_service->get_by_id(player_idx))
|
if (auto player = big::g_player_service->get_by_id(player_idx))
|
||||||
{
|
{
|
||||||
auto pers = big::g_player_database_service->get_or_create_player(player);
|
big::session::add_infraction(player, reason, custom_reason);
|
||||||
pers->is_modder = true;
|
|
||||||
big::g_player_database_service->save();
|
|
||||||
player->is_modder = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +137,21 @@ namespace lua::network
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lua API: Function
|
||||||
|
// Table: network
|
||||||
|
// Name: get_flagged_modder_reason
|
||||||
|
// Param: player_idx: integer: Index of the player.
|
||||||
|
// Returns: string: Returns a string which contains the reason(s) why the player is flagged as a modder.
|
||||||
|
static std::string get_flagged_modder_reason(int player_idx)
|
||||||
|
{
|
||||||
|
if (auto player = big::g_player_service->get_by_id(player_idx))
|
||||||
|
{
|
||||||
|
return big::g_player_database_service->get_or_create_player(player)->get_all_infraction_descriptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
// Lua API: Function
|
// Lua API: Function
|
||||||
// Table: network
|
// Table: network
|
||||||
// Name: force_script_host
|
// Name: force_script_host
|
||||||
@ -158,16 +181,39 @@ namespace lua::network
|
|||||||
|
|
||||||
void bind(sol::state& state)
|
void bind(sol::state& state)
|
||||||
{
|
{
|
||||||
auto ns = state["network"].get_or_create<sol::table>();
|
state.new_enum<big::Infraction>("infraction",
|
||||||
|
{
|
||||||
|
{"ATTACKING_WHEN_HIDDEN_FROM_PLAYER_LIST", big::Infraction::ATTACKING_WHEN_HIDDEN_FROM_PLAYER_LIST},
|
||||||
|
{"ATTACKING_WITH_GODMODE", big::Infraction::ATTACKING_WITH_GODMODE},
|
||||||
|
{"ATTACKING_WITH_INVISIBILITY", big::Infraction::ATTACKING_WITH_INVISIBILITY},
|
||||||
|
{"BLAME_EXPLOSION_DETECTED", big::Infraction::BLAME_EXPLOSION_DETECTED},
|
||||||
|
{"BREAKUP_KICK_DETECTED", big::Infraction::BREAKUP_KICK_DETECTED},
|
||||||
|
{"CUSTOM_REASON", big::Infraction::CUSTOM_REASON},
|
||||||
|
{"DESYNC_PROTECTION", big::Infraction::DESYNC_PROTECTION},
|
||||||
|
{"INVALID_PLAYER_MODEL", big::Infraction::INVALID_PLAYER_MODEL},
|
||||||
|
{"LOST_CONNECTION_KICK_DETECTED", big::Infraction::LOST_CONNECTION_KICK_DETECTED},
|
||||||
|
{"SPOOFED_DATA", big::Infraction::SPOOFED_DATA},
|
||||||
|
{"SPOOFED_HOST_TOKEN", big::Infraction::SPOOFED_HOST_TOKEN},
|
||||||
|
{"SPOOFED_ROCKSTAR_ID", big::Infraction::SPOOFED_ROCKSTAR_ID},
|
||||||
|
{"SUPER_JUMP", big::Infraction::SUPER_JUMP},
|
||||||
|
{"TRIED_CRASH_PLAYER", big::Infraction::TRIED_CRASH_PLAYER},
|
||||||
|
{"TRIED_KICK_PLAYER", big::Infraction::TRIED_KICK_PLAYER},
|
||||||
|
{"TRIGGERED_ANTICHEAT", big::Infraction::TRIGGERED_ANTICHEAT},
|
||||||
|
{"UNDEAD_OTR", big::Infraction::UNDEAD_OTR},
|
||||||
|
});
|
||||||
|
|
||||||
|
auto ns = state["network"].get_or_create<sol::table>();
|
||||||
|
|
||||||
ns["trigger_script_event"] = trigger_script_event;
|
ns["trigger_script_event"] = trigger_script_event;
|
||||||
ns["give_pickup_rewards"] = give_pickup_rewards;
|
ns["give_pickup_rewards"] = give_pickup_rewards;
|
||||||
ns["set_player_coords"] = set_player_coords;
|
ns["set_player_coords"] = set_player_coords;
|
||||||
ns["set_all_player_coords"] = set_all_player_coords;
|
ns["set_all_player_coords"] = set_all_player_coords;
|
||||||
ns["get_selected_player"] = get_selected_player;
|
ns["get_selected_player"] = get_selected_player;
|
||||||
ns["get_selected_database_player_rockstar_id"] = get_selected_database_player_rockstar_id;
|
ns["get_selected_database_player_rockstar_id"] = get_selected_database_player_rockstar_id;
|
||||||
ns["flag_player_as_modder"] = flag_player_as_modder;
|
ns["flag_player_as_modder"] = sol::overload(flag_player_as_modder, flag_player_as_modder_custom_reason);
|
||||||
ns["is_player_flagged_as_modder"] = is_player_flagged_as_modder;
|
ns["is_player_flagged_as_modder"] = is_player_flagged_as_modder;
|
||||||
ns["force_script_host"] = force_script_host;
|
ns["get_flagged_modder_reason"] = get_flagged_modder_reason;
|
||||||
ns["send_chat_message"] = send_chat_message;
|
ns["force_script_host"] = force_script_host;
|
||||||
|
ns["send_chat_message"] = send_chat_message;
|
||||||
}
|
}
|
||||||
}
|
}
|
63
src/services/player_database/persistent_player.cpp
Normal file
63
src/services/player_database/persistent_player.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "persistent_player.hpp"
|
||||||
|
|
||||||
|
#include "core/data/infractions.hpp"
|
||||||
|
|
||||||
|
namespace big
|
||||||
|
{
|
||||||
|
static std::unordered_map<Infraction, const char*> infraction_desc = {
|
||||||
|
{Infraction::DESYNC_PROTECTION, "Used desync protections"},
|
||||||
|
{Infraction::BREAKUP_KICK_DETECTED, "Kicked someone using breakup kick"},
|
||||||
|
{Infraction::LOST_CONNECTION_KICK_DETECTED, "Tried to kick someone using lost connection kick"},
|
||||||
|
{Infraction::SPOOFED_ROCKSTAR_ID, "Had spoofed RID"},
|
||||||
|
{Infraction::TRIGGERED_ANTICHEAT, "Triggered Rockstar's anticheat"},
|
||||||
|
{Infraction::TRIED_CRASH_PLAYER, "Tried to crash you"},
|
||||||
|
{Infraction::TRIED_KICK_PLAYER, "Tried to kick you"},
|
||||||
|
{Infraction::BLAME_EXPLOSION_DETECTED, "Tried to blame someone for their explosion"},
|
||||||
|
{Infraction::ATTACKING_WITH_GODMODE, "Attacked someone while using godmode"},
|
||||||
|
{Infraction::ATTACKING_WITH_INVISIBILITY, "Attacked someone while being invisible"},
|
||||||
|
{Infraction::ATTACKING_WHEN_HIDDEN_FROM_PLAYER_LIST, "Attacked someone while being hidden from the player list"},
|
||||||
|
{Infraction::SPOOFED_DATA, "Had spoofed data"},
|
||||||
|
{Infraction::SPOOFED_HOST_TOKEN, "Had spoofed their host token"},
|
||||||
|
{Infraction::INVALID_PLAYER_MODEL, "Had used an invalid player model"},
|
||||||
|
{Infraction::SUPER_JUMP, "Had used super jump"},
|
||||||
|
{Infraction::UNDEAD_OTR, "Had used undead OTR"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* persistent_player::get_infraction_description(int infraction)
|
||||||
|
{
|
||||||
|
if (static_cast<Infraction>(infraction) == Infraction::CUSTOM_REASON)
|
||||||
|
{
|
||||||
|
return custom_infraction_reason.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
return infraction_desc[static_cast<Infraction>(infraction)];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string persistent_player::get_all_infraction_descriptions()
|
||||||
|
{
|
||||||
|
if (!infractions.size())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto separator = ", ";
|
||||||
|
constexpr size_t separator_length = (std::string(separator)).size();
|
||||||
|
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
for (const auto infr : infractions)
|
||||||
|
{
|
||||||
|
s += get_infraction_description(infr);
|
||||||
|
s += separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove last useless separator
|
||||||
|
for (size_t i = 0; i < separator_length; i++)
|
||||||
|
{
|
||||||
|
s.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "core/data/infractions.hpp"
|
|
||||||
#include "json_util.hpp"
|
#include "json_util.hpp"
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@ -43,12 +42,13 @@ namespace big
|
|||||||
struct persistent_player
|
struct persistent_player
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
uint64_t rockstar_id = 0;
|
uint64_t rockstar_id = 0;
|
||||||
bool block_join = false;
|
bool block_join = false;
|
||||||
int block_join_reason = 1;
|
int block_join_reason = 1;
|
||||||
bool is_modder = false;
|
bool is_modder = false;
|
||||||
bool notify_online = false;
|
bool notify_online = false;
|
||||||
std::unordered_set<int> infractions;
|
std::unordered_set<int> infractions;
|
||||||
|
std::string custom_infraction_reason = "";
|
||||||
std::string notes = "";
|
std::string notes = "";
|
||||||
std::optional<CommandAccessLevel> command_access_level = std::nullopt;
|
std::optional<CommandAccessLevel> command_access_level = std::nullopt;
|
||||||
bool join_redirect = false;
|
bool join_redirect = false;
|
||||||
@ -66,7 +66,9 @@ namespace big
|
|||||||
std::string game_mode_id = "";
|
std::string game_mode_id = "";
|
||||||
rage::rlSessionInfo redirect_info{};
|
rage::rlSessionInfo redirect_info{};
|
||||||
|
|
||||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(persistent_player, name, rockstar_id, block_join, block_join_reason, is_modder, notify_online, infractions, notes, command_access_level, join_redirect, join_redirect_preference)
|
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(persistent_player, name, rockstar_id, block_join, block_join_reason, is_modder, notify_online, infractions, custom_infraction_reason, notes, command_access_level, join_redirect, join_redirect_preference)
|
||||||
};
|
|
||||||
|
|
||||||
|
const char* get_infraction_description(int infraction);
|
||||||
|
std::string get_all_infraction_descriptions();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "core/data/infractions.hpp"
|
||||||
#include "core/data/session_types.hpp"
|
#include "core/data/session_types.hpp"
|
||||||
#include "fiber_pool.hpp"
|
#include "fiber_pool.hpp"
|
||||||
#include "gta/joaat.hpp"
|
#include "gta/joaat.hpp"
|
||||||
@ -48,7 +49,7 @@ namespace big::session
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
*scr_globals::session.at(2).as<int*>() = 0;
|
*scr_globals::session.at(2).as<int*>() = 0;
|
||||||
*scr_globals::session2.as<int*>() = (int)session;
|
*scr_globals::session2.as<int*>() = (int)session;
|
||||||
}
|
}
|
||||||
|
|
||||||
*scr_globals::session.as<int*>() = 1;
|
*scr_globals::session.as<int*>() = 1;
|
||||||
@ -63,7 +64,7 @@ namespace big::session
|
|||||||
}
|
}
|
||||||
|
|
||||||
scr_functions::reset_session_data({true, true});
|
scr_functions::reset_session_data({true, true});
|
||||||
*scr_globals::session3.as<int*>() = 0;
|
*scr_globals::session3.as<int*>() = 0;
|
||||||
*scr_globals::session4.as<int*>() = 1;
|
*scr_globals::session4.as<int*>() = 1;
|
||||||
*scr_globals::session5.as<int*>() = 32;
|
*scr_globals::session5.as<int*>() = 32;
|
||||||
|
|
||||||
@ -158,7 +159,7 @@ namespace big::session
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void add_infraction(player_ptr player, Infraction infraction)
|
inline void add_infraction(player_ptr player, Infraction infraction, const std::string& custom_reason = "")
|
||||||
{
|
{
|
||||||
if (g.debug.fuzzer.enabled)
|
if (g.debug.fuzzer.enabled)
|
||||||
return;
|
return;
|
||||||
@ -168,8 +169,15 @@ namespace big::session
|
|||||||
{
|
{
|
||||||
plyr->is_modder = true;
|
plyr->is_modder = true;
|
||||||
player->is_modder = true;
|
player->is_modder = true;
|
||||||
|
|
||||||
plyr->infractions.insert((int)infraction);
|
plyr->infractions.insert((int)infraction);
|
||||||
|
if (infraction == Infraction::CUSTOM_REASON)
|
||||||
|
{
|
||||||
|
plyr->custom_infraction_reason += plyr->custom_infraction_reason.size() ? (std::string(", ") + custom_reason) : custom_reason;
|
||||||
|
}
|
||||||
|
|
||||||
g_player_database_service->save();
|
g_player_database_service->save();
|
||||||
|
|
||||||
g.reactions.modder_detection.process(player);
|
g.reactions.modder_detection.process(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ namespace big
|
|||||||
|
|
||||||
for (auto& infraction : current_player->infractions)
|
for (auto& infraction : current_player->infractions)
|
||||||
{
|
{
|
||||||
ImGui::BulletText(infraction_desc[(Infraction)infraction]);
|
ImGui::BulletText(current_player->get_infraction_description(infraction));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ namespace big
|
|||||||
{
|
{
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
for (auto infraction : sorted_player->infractions)
|
for (auto infraction : sorted_player->infractions)
|
||||||
ImGui::BulletText(infraction_desc[(Infraction)infraction]);
|
ImGui::BulletText(sorted_player->get_infraction_description(infraction));
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user