Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cac8fcf8c | ||
|
|
9134c66117 | ||
|
|
8ff9f9e5e8 |
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"Name": "fvnkhead.killstat",
|
"Name": "fvnkhead.killstat",
|
||||||
"Description": "Gather kill statistics and sends them to Tone API server.",
|
"Description": "Gather kill statistics and sends them to Tone API server.",
|
||||||
"Version": "3.0.2",
|
"Version": "3.0.4",
|
||||||
"LoadPriority": 2,
|
"LoadPriority": 1,
|
||||||
"RequiredOnClient": false,
|
"RequiredOnClient": false,
|
||||||
"ConVars": [
|
"ConVars": [
|
||||||
{
|
{
|
||||||
"Name": "toneapi_version",
|
"Name": "killstat_version",
|
||||||
"DefaultValue": "3.0.2"
|
"DefaultValue": "ks_3.0.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "Tone_URI",
|
"Name": "Tone_URI",
|
||||||
"DefaultValue": "https://tone.sleepycat.date/v3/server"
|
"DefaultValue": "https://toneapi.ovh/v2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "Tone_token",
|
"Name": "Tone_token",
|
||||||
@@ -23,20 +23,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Scripts": [
|
"Scripts": [
|
||||||
{
|
|
||||||
"Path": "toneapi.nut",
|
|
||||||
"RunOn": "SERVER",
|
|
||||||
"ServerCallback": {
|
|
||||||
"After": "toneapi_Init"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Path": "matchstat.nut",
|
|
||||||
"RunOn": "SERVER",
|
|
||||||
"ServerCallback": {
|
|
||||||
"After": "matchstat_Init"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"Path": "killstat.nut",
|
"Path": "killstat.nut",
|
||||||
"RunOn": "SERVER",
|
"RunOn": "SERVER",
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
array<int> MAIN_DAMAGE_SOURCES = [
|
|
||||||
// primaries
|
|
||||||
eDamageSourceId.mp_weapon_car,
|
|
||||||
eDamageSourceId.mp_weapon_r97,
|
|
||||||
eDamageSourceId.mp_weapon_alternator_smg,
|
|
||||||
eDamageSourceId.mp_weapon_hemlok_smg,
|
|
||||||
eDamageSourceId.mp_weapon_hemlok,
|
|
||||||
eDamageSourceId.mp_weapon_vinson,
|
|
||||||
eDamageSourceId.mp_weapon_g2,
|
|
||||||
eDamageSourceId.mp_weapon_rspn101,
|
|
||||||
eDamageSourceId.mp_weapon_rspn101_og,
|
|
||||||
eDamageSourceId.mp_weapon_esaw,
|
|
||||||
eDamageSourceId.mp_weapon_lstar,
|
|
||||||
eDamageSourceId.mp_weapon_lmg,
|
|
||||||
eDamageSourceId.mp_weapon_shotgun,
|
|
||||||
eDamageSourceId.mp_weapon_mastiff,
|
|
||||||
eDamageSourceId.mp_weapon_dmr,
|
|
||||||
eDamageSourceId.mp_weapon_sniper,
|
|
||||||
eDamageSourceId.mp_weapon_doubletake,
|
|
||||||
eDamageSourceId.mp_weapon_pulse_lmg,
|
|
||||||
eDamageSourceId.mp_weapon_smr,
|
|
||||||
eDamageSourceId.mp_weapon_softball,
|
|
||||||
eDamageSourceId.mp_weapon_epg,
|
|
||||||
eDamageSourceId.mp_weapon_shotgun_pistol,
|
|
||||||
eDamageSourceId.mp_weapon_wingman_n,
|
|
||||||
|
|
||||||
// secondaries
|
|
||||||
eDamageSourceId.mp_weapon_smart_pistol,
|
|
||||||
eDamageSourceId.mp_weapon_wingman,
|
|
||||||
eDamageSourceId.mp_weapon_semipistol,
|
|
||||||
eDamageSourceId.mp_weapon_autopistol,
|
|
||||||
|
|
||||||
// anti-titan
|
|
||||||
eDamageSourceId.mp_weapon_mgl,
|
|
||||||
eDamageSourceId.mp_weapon_rocket_launcher,
|
|
||||||
eDamageSourceId.mp_weapon_arc_launcher,
|
|
||||||
eDamageSourceId.mp_weapon_defender
|
|
||||||
]
|
|
||||||
|
|
||||||
void function DumpWeaponModBitFields() {
|
|
||||||
Log("[DumpWeaponModBitFields]")
|
|
||||||
foreach (int damageSourceId in MAIN_DAMAGE_SOURCES) {
|
|
||||||
string weaponName = DamageSourceIDToString(damageSourceId)
|
|
||||||
array<string> mods = GetWeaponMods_Global(weaponName)
|
|
||||||
array<string> list = [weaponName]
|
|
||||||
foreach (string mod in mods) {
|
|
||||||
list.append(mod)
|
|
||||||
}
|
|
||||||
|
|
||||||
Log("[DumpWeaponModBitFields] " + ToPythonList(list))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string function ToPythonList(array<string> list) {
|
|
||||||
array<string> quoted = []
|
|
||||||
foreach (string s in list) {
|
|
||||||
quoted.append("'" + s + "'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return "\"[" + join(quoted, ", ") + "]\""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string function join(array<string> list, string separator) {
|
|
||||||
string s = ""
|
|
||||||
for (int i = 0; i < list.len(); i++) {
|
|
||||||
s += list[i]
|
|
||||||
if (i < list.len() - 1) {
|
|
||||||
s += separator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
int function WeaponNameSort(entity a, entity b) {
|
|
||||||
return SortStringAlphabetize(a.GetWeaponClassName(), b.GetWeaponClassName())
|
|
||||||
}
|
|
||||||
+256
-204
@@ -1,26 +1,94 @@
|
|||||||
global function killstat_Init
|
global function killstat_Init
|
||||||
|
|
||||||
void function killstat_Init() {
|
struct Parameter {
|
||||||
if(GetMapName() == "mp_lobby") {
|
string name
|
||||||
return
|
string value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct {
|
||||||
|
string killstatVersion
|
||||||
|
string Tone_URI
|
||||||
|
string Tone_protocol
|
||||||
|
string servername
|
||||||
|
string Tone_token
|
||||||
|
bool connected
|
||||||
|
//remove this in the future
|
||||||
|
array<Parameter> customParameters
|
||||||
|
|
||||||
|
int matchId
|
||||||
|
string gameMode
|
||||||
|
string map
|
||||||
|
} file
|
||||||
|
|
||||||
|
void function killstat_Init() {
|
||||||
|
file.killstatVersion = GetConVarString("killstat_version")
|
||||||
|
file.Tone_URI = GetConVarString("Tone_URI")
|
||||||
|
file.Tone_token = GetConVarString("Tone_token")
|
||||||
|
file.connected = false
|
||||||
|
file.servername = GetConVarString("ns_server_name")
|
||||||
|
//register to Tone API if default or invalid token
|
||||||
|
Tone_Test_Auth()
|
||||||
|
|
||||||
|
// custom parameters
|
||||||
|
string customParameterString = GetConVarString("killstat_custom_parameters")
|
||||||
|
array<string> customParameterEntries = split(customParameterString, ",")
|
||||||
|
file.customParameters = []
|
||||||
|
foreach (string customParameterEntry in customParameterEntries) {
|
||||||
|
array<string> customParameterPair = split(customParameterEntry, "=")
|
||||||
|
if (customParameterPair.len() != 2) {
|
||||||
|
Log("[WARN] ignoring invalid custom parameter: " + customParameterEntry)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter customParameter
|
||||||
|
customParameter.name = strip(customParameterPair[0])
|
||||||
|
customParameter.value = strip(customParameterPair[1])
|
||||||
|
file.customParameters.append(customParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
AddCallback_GameStateEnter(eGameState.Playing, killstat_Begin)
|
||||||
AddCallback_OnPlayerKilled(killstat_Record)
|
AddCallback_OnPlayerKilled(killstat_Record)
|
||||||
|
AddCallback_GameStateEnter(eGameState.Postmatch, killstat_End)
|
||||||
|
AddCallback_OnClientConnected(JoinMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter function NewParameter(string name, string value) {
|
||||||
|
Parameter p
|
||||||
|
p.name = name
|
||||||
|
p.value = value
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
string prefix = "\x1b[38;5;81m[TONE API]\x1b[0m "
|
||||||
|
|
||||||
|
void function JoinMessage(entity player) {
|
||||||
|
//Chat_ServerPrivateMessage(player, prefix + "This server collects data using the Tone API. Check your data here: \x1b[34mtoneapi.com/" + player.GetPlayerName()+ "\x1b[0m", false, false)
|
||||||
|
Chat_ServerPrivateMessage(player, prefix + "This server collects data using the WIP Tone API. View statistics at https://toneapi.ovh", false, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void function killstat_Begin() {
|
||||||
|
//DumpWeaponModBitFields()
|
||||||
|
//TODO : request MatchID from API ------------------------------------------------------------------------------------------------
|
||||||
|
//TODO : request anonymization data from API
|
||||||
|
file.matchId = RandomInt(2000000000)
|
||||||
|
file.gameMode = GameRules_GetGameMode()
|
||||||
|
file.map = StringReplace(GetMapName(), "mp_", "")
|
||||||
|
|
||||||
|
Log("-----BEGIN KILLSTAT-----")
|
||||||
|
Log("Sending kill data to " + file.Tone_URI + "/server/kill")
|
||||||
}
|
}
|
||||||
|
|
||||||
void function killstat_Record(entity victim, entity attacker, var damageInfo) {
|
void function killstat_Record(entity victim, entity attacker, var damageInfo) {
|
||||||
if ( !victim.IsPlayer() || !attacker.IsPlayer() || GetGameState() != eGameState.Playing )
|
if ( !victim.IsPlayer() || !attacker.IsPlayer() || GetGameState() != eGameState.Playing )
|
||||||
return
|
return
|
||||||
if(!toneapi_data.matchId){
|
|
||||||
ToneAPI_Log("[ERRR] Match is not registered!")
|
table values = {}
|
||||||
return
|
//remove this in the future
|
||||||
|
foreach (Parameter p in file.customParameters) {
|
||||||
|
values[p] <- p.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
table attackerValues = {}
|
|
||||||
table < string,
|
|
||||||
var > victimValues = {}
|
|
||||||
|
|
||||||
array<entity> attackerWeapons = attacker.GetMainWeapons()
|
array<entity> attackerWeapons = attacker.GetMainWeapons()
|
||||||
array<entity> victimWeapons = victim.GetMainWeapons()
|
array<entity> victimWeapons = victim.GetMainWeapons()
|
||||||
array<entity> attackerOffhandWeapons = attacker.GetOffhandWeapons()
|
array<entity> attackerOffhandWeapons = attacker.GetOffhandWeapons()
|
||||||
@@ -42,199 +110,79 @@ void function killstat_Record(entity victim, entity attacker, var damageInfo) {
|
|||||||
entity vow2 = GetNthWeapon(victimOffhandWeapons, 1)
|
entity vow2 = GetNthWeapon(victimOffhandWeapons, 1)
|
||||||
entity vow3 = GetNthWeapon(victimOffhandWeapons, 2)
|
entity vow3 = GetNthWeapon(victimOffhandWeapons, 2)
|
||||||
|
|
||||||
|
values["killstat_version"] <- file.killstatVersion
|
||||||
|
values["match_id"] <- format("%08x", file.matchId)
|
||||||
|
values["servername"] <- file.servername
|
||||||
|
values["game_mode"] <- file.gameMode
|
||||||
|
values["map"] <- file.map
|
||||||
|
values["game_time"] <- format("%.3f", Time())
|
||||||
|
values["player_count"] <- format("%d", GetPlayerArray().len())
|
||||||
|
values["attacker_name"] <- attacker.GetPlayerName()
|
||||||
|
values["attacker_id"] <- attacker.GetUID()
|
||||||
|
values["attacker_current_weapon"] <- GetWeaponName(attacker.GetLatestPrimaryWeapon())
|
||||||
|
values["attacker_current_weapon_mods"] <- GetWeaponMods(attacker.GetLatestPrimaryWeapon())
|
||||||
|
values["attacker_weapon_1"] <- GetWeaponName(aw1)
|
||||||
|
values["attacker_weapon_1_mods"] <- GetWeaponMods(aw1)
|
||||||
|
values["attacker_weapon_2"] <- GetWeaponName(aw2)
|
||||||
|
values["attacker_weapon_2_mods"] <- GetWeaponMods(aw2)
|
||||||
|
values["attacker_weapon_3"] <- GetWeaponName(aw3)
|
||||||
|
values["attacker_weapon_3_mods"] <- GetWeaponMods(aw3)
|
||||||
|
values["attacker_offhand_weapon_1"] <- GetWeaponName(aow1)
|
||||||
|
values["attacker_offhand_weapon_1_mods"] <- GetWeaponMods(aow1)
|
||||||
|
values["attacker_offhand_weapon_2"] <- GetWeaponName(aow2)
|
||||||
|
values["attacker_offhand_weapon_2_mods"] <- GetWeaponMods(aow1)
|
||||||
|
values["attacker_titan"] <- GetTitan(attacker)
|
||||||
|
|
||||||
|
values["victim_name"] <- victim.GetPlayerName()
|
||||||
|
values["victim_id"] <- victim.GetUID()
|
||||||
|
values["victim_current_weapon"] <- GetWeaponName(victim.GetLatestPrimaryWeapon())
|
||||||
|
values["victim_current_weapon_mods"] <- GetWeaponMods(victim.GetLatestPrimaryWeapon())
|
||||||
|
values["victim_weapon_1"] <- GetWeaponName(vw1)
|
||||||
|
values["victim_weapon_1_mods"] <- GetWeaponMods(vw1)
|
||||||
|
values["victim_weapon_2"] <- GetWeaponName(vw2)
|
||||||
|
values["victim_weapon_2_mods"] <- GetWeaponMods(vw2)
|
||||||
|
values["victim_weapon_3"] <- GetWeaponName(vw3)
|
||||||
|
values["victim_weapon_3_mods"] <- GetWeaponMods(vw3)
|
||||||
|
values["victim_offhand_weapon_1"] <- GetWeaponName(vow1)
|
||||||
|
values["victim_offhand_weapon_1_mods"] <- GetWeaponMods(vow1)
|
||||||
|
values["victim_offhand_weapon_2"] <- GetWeaponName(vow2)
|
||||||
|
values["victim_offhand_weapon_2_mods"] <- GetWeaponMods(vow2)
|
||||||
|
values["victim_titan"] <- GetTitan(victim)
|
||||||
|
|
||||||
int damageSourceId = DamageInfo_GetDamageSourceIdentifier(damageInfo)
|
int damageSourceId = DamageInfo_GetDamageSourceIdentifier(damageInfo)
|
||||||
string damageName = DamageSourceIDToString(damageSourceId)
|
string damageName = DamageSourceIDToString(damageSourceId)
|
||||||
|
values["cause_of_death"] <- damageName
|
||||||
|
|
||||||
float dist = Distance(attacker.GetOrigin(), victim.GetOrigin())
|
float dist = Distance(attacker.GetOrigin(), victim.GetOrigin())
|
||||||
|
values["distance"] <- format("%.3f", dist)
|
||||||
table values = {
|
|
||||||
version = toneapi_data.version
|
|
||||||
match_id = toneapi_data.matchId
|
|
||||||
game_time = Time()
|
|
||||||
player_count = GetPlayerArray().len()
|
|
||||||
cause_of_death = damageName
|
|
||||||
distance = dist
|
|
||||||
attacker = {
|
|
||||||
id = attacker.GetUID()
|
|
||||||
velocity = Distance( < 0, 0, 0 > , attacker.GetVelocity())
|
|
||||||
cloaked = attacker.IsCloaked(true)
|
|
||||||
state = GetMovementState(attacker)
|
|
||||||
current_weapon = {
|
|
||||||
id = GetWeaponName(attacker.GetLatestPrimaryWeapon())
|
|
||||||
mods = GetWeaponMods(attacker.GetLatestPrimaryWeapon())
|
|
||||||
}
|
|
||||||
loadout = {
|
|
||||||
primary = {
|
|
||||||
id = GetWeaponName(aw1)
|
|
||||||
mods = GetWeaponMods(aw1)
|
|
||||||
}
|
|
||||||
secondary = {
|
|
||||||
id = GetWeaponName(aw2)
|
|
||||||
mods = GetWeaponMods(aw2)
|
|
||||||
}
|
|
||||||
anti_titan = {
|
|
||||||
id = GetWeaponName(aw3)
|
|
||||||
mods = GetWeaponMods(aw3)
|
|
||||||
}
|
|
||||||
ordnance = {
|
|
||||||
id = GetWeaponName(aow1)
|
|
||||||
mods = GetWeaponMods(aow1)
|
|
||||||
}
|
|
||||||
tactical = {
|
|
||||||
id = GetWeaponName(aow2)
|
|
||||||
mods = GetWeaponMods(aow2)
|
|
||||||
}
|
|
||||||
passive1 = getPlayerPassive1(attacker)
|
|
||||||
passive2 = getPlayerPassive2(attacker)
|
|
||||||
titan = GetTitan(attacker)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
victim = {
|
|
||||||
id = victim.GetUID()
|
|
||||||
velocity = Distance( < 0, 0, 0 > , victim.GetVelocity())
|
|
||||||
cloaked = victim.IsCloaked(true)
|
|
||||||
state = GetMovementState(victim)
|
|
||||||
current_weapon = {
|
|
||||||
id = GetWeaponName(victim.GetLatestPrimaryWeapon())
|
|
||||||
mods = GetWeaponMods(victim.GetLatestPrimaryWeapon())
|
|
||||||
}
|
|
||||||
loadout = {
|
|
||||||
primary = {
|
|
||||||
id = GetWeaponName(vw1)
|
|
||||||
mods = GetWeaponMods(vw1)
|
|
||||||
}
|
|
||||||
secondary = {
|
|
||||||
id = GetWeaponName(vw2)
|
|
||||||
mods = GetWeaponMods(vw2)
|
|
||||||
}
|
|
||||||
anti_titan = {
|
|
||||||
id = GetWeaponName(vw3)
|
|
||||||
mods = GetWeaponMods(vw3)
|
|
||||||
}
|
|
||||||
ordnance = {
|
|
||||||
id = GetWeaponName(vow1)
|
|
||||||
mods = GetWeaponMods(vow1)
|
|
||||||
}
|
|
||||||
tactical = {
|
|
||||||
id = GetWeaponName(vow2)
|
|
||||||
mods = GetWeaponMods(vow2)
|
|
||||||
}
|
|
||||||
passive1 = getPlayerPassive1(victim)
|
|
||||||
passive2 = getPlayerPassive2(victim)
|
|
||||||
titan = GetTitan(victim)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HttpRequest request
|
HttpRequest request
|
||||||
request.method = HttpRequestMethod.POST
|
request.method = HttpRequestMethod.POST
|
||||||
request.url = toneapi_data.Tone_URI + "/kill"
|
request.url = file.Tone_URI + "/server/kill"
|
||||||
|
request.headers = {Authorization = ["Bearer " + file.Tone_token]}
|
||||||
request.body = EncodeJSON(values)
|
request.body = EncodeJSON(values)
|
||||||
|
|
||||||
Tone_HTTP_Request(
|
void functionref( HttpRequestResponse ) onSuccess = void function ( HttpRequestResponse response )
|
||||||
request,
|
{
|
||||||
void
|
if(response.statusCode == 200 || response.statusCode == 201){
|
||||||
function(HttpRequestResponse response) {}
|
print("[Tone API] Kill data sent!")
|
||||||
)
|
}else{
|
||||||
|
print("[Tone API][WARN] Couldn't send kill data")
|
||||||
|
print("[Tone API][WARN] " + response.body )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string function GetMovementState(entity player) {
|
void functionref( HttpRequestFailure ) onFailure = void function ( HttpRequestFailure failure )
|
||||||
Assert(IsPilot(player))
|
{
|
||||||
//IsPhaseShifted
|
print("[Tone API][WARN] Couldn't send kill data")
|
||||||
//IsStanding
|
print("[Tone API][WARN] " + failure.errorMessage )
|
||||||
if (player.IsWallHanging())
|
}
|
||||||
return "WallHanging"
|
NSHttpRequest(request, onSuccess, onFailure)
|
||||||
if (player.IsWallRunning())
|
|
||||||
return "WallRunning"
|
|
||||||
if (player.IsZiplining())
|
|
||||||
return "Ziplining"
|
|
||||||
if (!player.IsOnGround())
|
|
||||||
return "Airborne"
|
|
||||||
if (player.IsCrouched())
|
|
||||||
return "Crouching"
|
|
||||||
return "OnGround"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should sort main weapons in following order:
|
void function killstat_End() {
|
||||||
// 1. primary
|
Log("-----END KILLSTAT-----")
|
||||||
// 2. secondary
|
|
||||||
// 3. anti-titan
|
|
||||||
int function MainWeaponSort(entity a, entity b) {
|
|
||||||
int aID = a.GetDamageSourceID()
|
|
||||||
int bID = b.GetDamageSourceID()
|
|
||||||
|
|
||||||
int aIdx = MAIN_DAMAGE_SOURCES.find(aID)
|
|
||||||
int bIdx = MAIN_DAMAGE_SOURCES.find(bID)
|
|
||||||
|
|
||||||
if (aIdx == bIdx) {
|
|
||||||
return 0
|
|
||||||
} else if (aIdx != -1 && bIdx == -1) {
|
|
||||||
return -1
|
|
||||||
} else if (aIdx == -1 && bIdx != -1) {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return aIdx < bIdx ? -1 : 1
|
|
||||||
}
|
|
||||||
|
|
||||||
entity function GetNthWeapon(array < entity > weapons, int index) {
|
|
||||||
return index < weapons.len() ? weapons[index] : null
|
|
||||||
}
|
|
||||||
|
|
||||||
var function GetWeaponData(entity weapon){
|
|
||||||
if(weapon != null) {
|
|
||||||
return {
|
|
||||||
id = weapon.GetWeaponClassName()
|
|
||||||
mods = weapon.GetModBitField()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
var function GetWeaponName(entity weapon) {
|
|
||||||
if (weapon != null) {
|
|
||||||
return weapon.GetWeaponClassName()
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
function GetWeaponMods(entity weapon) {
|
|
||||||
if (weapon == null) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
int modBits = weapon.GetModBitField()
|
|
||||||
// return format("%d", modBits)
|
|
||||||
return modBits
|
|
||||||
}
|
|
||||||
|
|
||||||
var function GetTitan(entity player) {
|
|
||||||
if (player.IsTitan()){
|
|
||||||
return GetTitanCharacterName(player)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
var function getPlayerPassive1(entity player) {
|
|
||||||
foreach (string key, int val in ePassives){
|
|
||||||
if (PlayerHasPassive(player, val)) {
|
|
||||||
if(passive1Names.find(key) != -1){
|
|
||||||
return key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
var function getPlayerPassive2(entity player) {
|
|
||||||
foreach (string key, int val in ePassives){
|
|
||||||
if (PlayerHasPassive(player, val)) {
|
|
||||||
if(passive2Names.find(key) != -1){
|
|
||||||
return key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
array<int> MAIN_DAMAGE_SOURCES = [
|
array<int> MAIN_DAMAGE_SOURCES = [
|
||||||
@@ -276,19 +224,123 @@ array < int > MAIN_DAMAGE_SOURCES = [
|
|||||||
eDamageSourceId.mp_weapon_defender
|
eDamageSourceId.mp_weapon_defender
|
||||||
]
|
]
|
||||||
|
|
||||||
|
void function DumpWeaponModBitFields() {
|
||||||
|
Log("[DumpWeaponModBitFields]")
|
||||||
|
foreach (int damageSourceId in MAIN_DAMAGE_SOURCES) {
|
||||||
|
string weaponName = DamageSourceIDToString(damageSourceId)
|
||||||
|
array<string> mods = GetWeaponMods_Global(weaponName)
|
||||||
|
array<string> list = [weaponName]
|
||||||
|
foreach (string mod in mods) {
|
||||||
|
list.append(mod)
|
||||||
|
}
|
||||||
|
|
||||||
array < string > passive1Names = [
|
Log("[DumpWeaponModBitFields] " + ToPythonList(list))
|
||||||
"pas_ordnance_pack",
|
}
|
||||||
"pas_power_cell",
|
}
|
||||||
"pas_fast_embark",
|
|
||||||
"pas_fast_health_regen"
|
// Should sort main weapons in following order:
|
||||||
]
|
// 1. primary
|
||||||
|
// 2. secondary
|
||||||
|
// 3. anti-titan
|
||||||
|
int function MainWeaponSort(entity a, entity b) {
|
||||||
|
int aID = a.GetDamageSourceID()
|
||||||
|
int bID = b.GetDamageSourceID()
|
||||||
|
|
||||||
|
int aIdx = MAIN_DAMAGE_SOURCES.find(aID)
|
||||||
|
int bIdx = MAIN_DAMAGE_SOURCES.find(bID)
|
||||||
|
|
||||||
|
if (aIdx == bIdx) {
|
||||||
|
return 0
|
||||||
|
} else if (aIdx != -1 && bIdx == -1) {
|
||||||
|
return -1
|
||||||
|
} else if (aIdx == -1 && bIdx != -1) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return aIdx < bIdx ? -1 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
int function WeaponNameSort(entity a, entity b) {
|
||||||
|
return SortStringAlphabetize(a.GetWeaponClassName(), b.GetWeaponClassName())
|
||||||
|
}
|
||||||
|
|
||||||
|
entity function GetNthWeapon(array<entity> weapons, int index) {
|
||||||
|
return index < weapons.len() ? weapons[index] : null
|
||||||
|
}
|
||||||
|
|
||||||
|
string function GetWeaponName(entity weapon) {
|
||||||
|
string s = "null"
|
||||||
|
if (weapon != null) {
|
||||||
|
s = weapon.GetWeaponClassName()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
string function GetWeaponMods(entity weapon) {
|
||||||
|
if (weapon == null) {
|
||||||
|
return "null"
|
||||||
|
}
|
||||||
|
int modBits = weapon.GetModBitField()
|
||||||
|
return format("%d", modBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
string function GetTitan(entity player) {
|
||||||
|
if(!player.IsTitan()) return "null"
|
||||||
|
return GetTitanCharacterName(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
string function Anonymize(entity player) {
|
||||||
|
return "null" // unused
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
array < string > passive2Names = [
|
string function ToPythonList(array<string> list) {
|
||||||
"pas_stealth_movement",
|
array<string> quoted = []
|
||||||
"pas_wallhang",
|
foreach (string s in list) {
|
||||||
"pas_ads_hover",
|
quoted.append("'" + s + "'")
|
||||||
"pas_enemy_death_icons",
|
}
|
||||||
"pas_at_hunter"
|
|
||||||
]
|
return "\"[" + join(quoted, ", ") + "]\""
|
||||||
|
}
|
||||||
|
|
||||||
|
void function Log(string s) {
|
||||||
|
print("[fvnkhead.killstat] " + s)
|
||||||
|
}
|
||||||
|
string function join(array<string> list, string separator) {
|
||||||
|
string s = ""
|
||||||
|
for (int i = 0; i < list.len(); i++) {
|
||||||
|
s += list[i]
|
||||||
|
if (i < list.len() - 1) {
|
||||||
|
s += separator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void function Tone_Test_Auth(){
|
||||||
|
HttpRequest request
|
||||||
|
request.method = HttpRequestMethod.POST
|
||||||
|
request.url = file.Tone_URI + "/server"
|
||||||
|
request.headers = {Authorization = ["Bearer "+ file.Tone_token]}
|
||||||
|
void functionref( HttpRequestResponse ) onSuccess = void function ( HttpRequestResponse response )
|
||||||
|
{
|
||||||
|
if(response.statusCode == 200){
|
||||||
|
print("[Tone API] Tone API Online !")
|
||||||
|
file.connected = true
|
||||||
|
}else{
|
||||||
|
print("[Tone API] Tone API login failed")
|
||||||
|
print("[Tone API] " + response.body )
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void functionref( HttpRequestFailure ) onFailure = void function ( HttpRequestFailure failure )
|
||||||
|
{
|
||||||
|
print("[Tone API] Tone API login failed")
|
||||||
|
print("[Tone API] " + failure.errorMessage )
|
||||||
|
}
|
||||||
|
|
||||||
|
NSHttpRequest(request, onSuccess, onFailure)
|
||||||
|
}
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
global function matchstat_Init
|
|
||||||
|
|
||||||
typedef playerSpecificStats table < string, var >
|
|
||||||
typedef playerStats table < string, playerSpecificStats >
|
|
||||||
typedef players table < string, playerStats >
|
|
||||||
struct {
|
|
||||||
table < string, players > weaponsUsed
|
|
||||||
} file
|
|
||||||
|
|
||||||
void function matchstat_Init(){
|
|
||||||
WeaponFireCallbacks_AddCallbackOnOwnerClassFired("player", OnWeaponFired)
|
|
||||||
AddDamageCallback("player", OnDamage)
|
|
||||||
AddCallback_OnPlayerRespawned( TrackPlayer )
|
|
||||||
// AddCallback_GameStateEnter(eGameState.WinnerDetermined, StopTrackPlayer)
|
|
||||||
// FlagInit( "" )
|
|
||||||
AddCallback_GameStateEnter(eGameState.Postmatch, ToneAPI_CloseMatch)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var function incrementVar(var value){
|
|
||||||
return expect float(value) + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
void function CreatePlayer(entity player){
|
|
||||||
string playerUID = player.GetUID()
|
|
||||||
if(!(playerUID in file.weaponsUsed)){
|
|
||||||
var playerName = player.GetPlayerName()
|
|
||||||
file.weaponsUsed[playerUID] <- {}
|
|
||||||
file.weaponsUsed[playerUID].weapons <- {}
|
|
||||||
file.weaponsUsed[playerUID].titans <- {}
|
|
||||||
file.weaponsUsed[playerUID].stats <- {}
|
|
||||||
file.weaponsUsed[playerUID].stats.distance <- {
|
|
||||||
ground = 0.0,
|
|
||||||
wall = 0.0,
|
|
||||||
air = 0.0
|
|
||||||
}
|
|
||||||
file.weaponsUsed[playerUID].stats.time <- {
|
|
||||||
ground = 0.0,
|
|
||||||
wall = 0.0,
|
|
||||||
air = 0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void function CreateWeaponStats(string weaponName, entity player){
|
|
||||||
CreatePlayer(player)
|
|
||||||
string playerUID = player.GetUID()
|
|
||||||
if(!(weaponName in file.weaponsUsed[playerUID].weapons)){
|
|
||||||
// Has to make ints floats because you can't mix types apparently
|
|
||||||
playerSpecificStats stats = {
|
|
||||||
shotsFired = 0.0,
|
|
||||||
shotsHit = 0.0,
|
|
||||||
shotsCrit = 0.0,
|
|
||||||
shotsHeadshot = 0.0,
|
|
||||||
shotsRichochet = 0.0,
|
|
||||||
playtime = 0.0
|
|
||||||
}
|
|
||||||
file.weaponsUsed[playerUID].weapons[weaponName] <- stats
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void function CreateTitanStats(string titanName, entity player){
|
|
||||||
CreatePlayer(player)
|
|
||||||
string playerUID = player.GetUID()
|
|
||||||
if(!(titanName in file.weaponsUsed[playerUID].titans)){
|
|
||||||
// Has to make ints floats because you can't mix types apparently
|
|
||||||
playerSpecificStats stats = {
|
|
||||||
shotsFired = 0.0,
|
|
||||||
shotsHit = 0.0,
|
|
||||||
shotsCrit = 0.0,
|
|
||||||
shotsHeadshot = 0.0,
|
|
||||||
shotsRichochet = 0.0,
|
|
||||||
playtime = 0.0
|
|
||||||
}
|
|
||||||
file.weaponsUsed[playerUID].titans[titanName] <- stats
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void function OnWeaponFired(entity weapon, WeaponPrimaryAttackParams attackParams, var ammoUsed){
|
|
||||||
entity player = weapon.GetOwner()
|
|
||||||
string weaponName = weapon.GetWeaponClassName()
|
|
||||||
if(!IsValid(player) || !player.IsPlayer()){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
string playerUID = player.GetUID()
|
|
||||||
CreateWeaponStats(weaponName, player)
|
|
||||||
file.weaponsUsed[playerUID].weapons[weaponName].shotsFired = incrementVar(file.weaponsUsed[playerUID].weapons[weaponName].shotsFired)
|
|
||||||
if(player.IsTitan()){
|
|
||||||
string titanName = GetTitanCharacterName(player)
|
|
||||||
CreateTitanStats(titanName, player)
|
|
||||||
file.weaponsUsed[playerUID].titans[titanName].shotsFired = incrementVar(file.weaponsUsed[playerUID].titans[titanName].shotsFired)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void function OnDamage( entity victim, var damageInfo){
|
|
||||||
entity player = DamageInfo_GetAttacker( damageInfo )
|
|
||||||
|
|
||||||
if(!IsValid(player) || !player.IsPlayer()){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
string playerUID = player.GetUID()
|
|
||||||
entity weapon = DamageInfo_GetWeapon( damageInfo )
|
|
||||||
entity inflictor = DamageInfo_GetInflictor( damageInfo )
|
|
||||||
string weaponName
|
|
||||||
if(weapon){
|
|
||||||
weaponName = weapon.GetWeaponClassName()
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
if ( inflictor && inflictor instanceof CProjectile && inflictor.IsProjectile() ){
|
|
||||||
weaponName = inflictor.ProjectileGetWeaponClassName()
|
|
||||||
}else{
|
|
||||||
ToneAPI_Log("[ERRR] Couldn't get weapon information")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CreateWeaponStats(weaponName, player)
|
|
||||||
file.weaponsUsed[playerUID].weapons[weaponName].shotsHit = incrementVar(file.weaponsUsed[playerUID].weapons[weaponName].shotsHit)
|
|
||||||
if(player.IsTitan()){
|
|
||||||
string titanName = GetTitanCharacterName(player)
|
|
||||||
CreateTitanStats(titanName, player)
|
|
||||||
file.weaponsUsed[playerUID].titans[titanName].shotsHit = incrementVar(file.weaponsUsed[playerUID].titans[titanName].shotsHit)
|
|
||||||
}
|
|
||||||
int damageType = DamageInfo_GetCustomDamageType( damageInfo )
|
|
||||||
bool crit = bool( damageType & DF_CRITICAL )
|
|
||||||
bool headshot = bool( damageType & DF_HEADSHOT )
|
|
||||||
// if(crit){
|
|
||||||
// file.weaponsUsed[playerUID].weapons[weaponName].shotsCrit = incrementVar(file.weaponsUsed[playerUID].weapons[weaponName].shotsCrit)
|
|
||||||
// if(player.IsTitan()){
|
|
||||||
// file.weaponsUsed[playerUID].titans[titanName].shotsCrit = incrementVar(file.weaponsUsed[playerUID].titans[titanName].shotsCrit)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
if(headshot || crit){
|
|
||||||
file.weaponsUsed[playerUID].weapons[weaponName].shotsHeadshot = incrementVar(file.weaponsUsed[playerUID].weapons[weaponName].shotsHeadshot)
|
|
||||||
if(player.IsTitan()){
|
|
||||||
string titanName = GetTitanCharacterName(player)
|
|
||||||
file.weaponsUsed[playerUID].titans[titanName].shotsHeadshot = incrementVar(file.weaponsUsed[playerUID].titans[titanName].shotsHeadshot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( inflictor && inflictor.IsProjectile() ){
|
|
||||||
if(inflictor.proj.projectileBounceCount > 1){
|
|
||||||
file.weaponsUsed[playerUID].weapons[weaponName].shotsRichochet = incrementVar(file.weaponsUsed[playerUID].weapons[weaponName].shotsRichochet)
|
|
||||||
if(player.IsTitan()){
|
|
||||||
string titanName = GetTitanCharacterName(player)
|
|
||||||
file.weaponsUsed[playerUID].titans[titanName].shotsRichochet = incrementVar(file.weaponsUsed[playerUID].titans[titanName].shotsRichochet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void function TrackPlayer(entity player) {
|
|
||||||
string playerUID = player.GetUID()
|
|
||||||
CreatePlayer(player)
|
|
||||||
thread TrackPlayer_Threaded(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
// void function StopTrackPlayer() {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
void function TrackPlayer_Threaded(entity player){
|
|
||||||
player.EndSignal( "OnDestroy" )
|
|
||||||
player.EndSignal( "OnDeath" )
|
|
||||||
vector position = player.GetOrigin()
|
|
||||||
string playerUID = player.GetUID()
|
|
||||||
float interval = 0.2
|
|
||||||
while(true){
|
|
||||||
wait interval
|
|
||||||
// Hmm
|
|
||||||
Assert( IsValid( player ) )
|
|
||||||
if(!IsValid(player)) return
|
|
||||||
|
|
||||||
// Ugly, should probably use flags
|
|
||||||
if(GetGameState() == eGameState.WinnerDetermined) return
|
|
||||||
|
|
||||||
entity weapon = player.GetActiveWeapon()
|
|
||||||
if(weapon){
|
|
||||||
string weaponName = weapon.GetWeaponClassName()
|
|
||||||
CreateWeaponStats(weaponName, player)
|
|
||||||
file.weaponsUsed[playerUID].weapons[weaponName].playtime = expect float(file.weaponsUsed[playerUID].weapons[weaponName].playtime) + interval
|
|
||||||
}else{
|
|
||||||
CreatePlayer(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(player.IsTitan()){
|
|
||||||
string titanName = GetTitanCharacterName(player)
|
|
||||||
CreateTitanStats(titanName, player)
|
|
||||||
file.weaponsUsed[playerUID].titans[titanName].playtime = expect float(file.weaponsUsed[playerUID].titans[titanName].playtime) + interval
|
|
||||||
}else if(player.IsPlayer()){
|
|
||||||
// Could be a little inaccurate but should work fine if interval is small enough
|
|
||||||
if(player.IsWallRunning()){
|
|
||||||
file.weaponsUsed[playerUID].stats.time.wall = expect float(file.weaponsUsed[playerUID].stats.time.wall) + interval
|
|
||||||
file.weaponsUsed[playerUID].stats.distance.wall = expect float(file.weaponsUsed[playerUID].stats.distance.wall) + Distance(position, player.GetOrigin())
|
|
||||||
}
|
|
||||||
else if(!player.IsOnGround()){
|
|
||||||
file.weaponsUsed[playerUID].stats.time.air = expect float(file.weaponsUsed[playerUID].stats.time.air) + interval
|
|
||||||
file.weaponsUsed[playerUID].stats.distance.air = expect float(file.weaponsUsed[playerUID].stats.distance.air) + Distance(position, player.GetOrigin())
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
file.weaponsUsed[playerUID].stats.time.ground = expect float(file.weaponsUsed[playerUID].stats.time.ground) + interval
|
|
||||||
file.weaponsUsed[playerUID].stats.distance.ground = expect float(file.weaponsUsed[playerUID].stats.distance.ground) + Distance(position, player.GetOrigin())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
position = player.GetOrigin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void function ToneAPI_CloseMatch(){
|
|
||||||
if(!toneapi_data.matchId){
|
|
||||||
ToneAPI_Log("[ERRR] Match is not registered!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest request
|
|
||||||
request.method = HttpRequestMethod.POST
|
|
||||||
request.url = toneapi_data.Tone_URI + "/match/" + string(toneapi_data.matchId) + "/close"
|
|
||||||
request.body = EncodeJSON(file.weaponsUsed)
|
|
||||||
Tone_HTTP_Request(
|
|
||||||
request,
|
|
||||||
void
|
|
||||||
function(HttpRequestResponse response) {}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
global function toneapi_Init
|
|
||||||
global function Tone_HTTP_Request
|
|
||||||
global function ToneAPI_Log
|
|
||||||
|
|
||||||
string prefix = "\x1b[38;5;81m[TONE API]\x1b[0m "
|
|
||||||
|
|
||||||
global struct toneapi_struct {
|
|
||||||
string version
|
|
||||||
string Tone_URI
|
|
||||||
string Tone_protocol
|
|
||||||
string Tone_token
|
|
||||||
bool connected
|
|
||||||
|
|
||||||
int ornull matchId
|
|
||||||
string gameMode
|
|
||||||
string map
|
|
||||||
}
|
|
||||||
|
|
||||||
global toneapi_struct toneapi_data
|
|
||||||
|
|
||||||
void function toneapi_Init(){
|
|
||||||
//TODO : request anonymization data from API
|
|
||||||
if(GetMapName() == "mp_lobby") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
toneapi_data.version = GetConVarString("toneapi_version")
|
|
||||||
toneapi_data.Tone_URI = GetConVarString("Tone_URI")
|
|
||||||
toneapi_data.Tone_token = GetConVarString("Tone_token")
|
|
||||||
toneapi_data.connected = false
|
|
||||||
|
|
||||||
//Test auth and print result to console when server start
|
|
||||||
// Tone_Test_Auth()
|
|
||||||
|
|
||||||
//We should probably blacklist mp_lobby this
|
|
||||||
Tone_Register_Match()
|
|
||||||
|
|
||||||
AddCallback_OnClientConnected(JoinMessage)
|
|
||||||
// AddCallback_OnClientConnected(RegisterPlayer)
|
|
||||||
}
|
|
||||||
|
|
||||||
void function JoinMessage(entity player) {
|
|
||||||
//Chat_ServerPrivateMessage(player, prefix + "This server collects data using the Tone API. Check your data here: \x1b[34mtoneapi.com/" + player.GetPlayerName()+ "\x1b[0m", false, false)
|
|
||||||
Chat_ServerPrivateMessage(player, prefix + "This server collects data using the WIP Tone API. View statistics at https://toneapi.github.io/ToneAPI_webclient/", false, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void function Tone_HTTP_Request(HttpRequest request, void functionref(HttpRequestResponse) cbSuccess) {
|
|
||||||
if (!request.method) request.method = HttpRequestMethod.POST
|
|
||||||
if (request.url == "") {
|
|
||||||
ToneAPI_Log("[ERRR] Couldn't find URI for request. This should be reported")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
request.headers = {
|
|
||||||
Authorization = ["Bearer " + toneapi_data.Tone_token]
|
|
||||||
}
|
|
||||||
|
|
||||||
NSHttpRequest(
|
|
||||||
request,
|
|
||||||
void function(HttpRequestResponse response): (cbSuccess) {
|
|
||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
|
||||||
cbSuccess(response)
|
|
||||||
} else {
|
|
||||||
if(response.statusCode == 401){
|
|
||||||
ToneAPI_Log("[WARN] Something might be wrong with your token")
|
|
||||||
}else{
|
|
||||||
ToneAPI_Log("[WARN] Something went wrong ! You'd better report this")
|
|
||||||
}
|
|
||||||
ToneAPI_Log("[WARN] " + response.statusCode)
|
|
||||||
ToneAPI_Log("[WARN] " + response.body)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
void function(HttpRequestFailure failure) {
|
|
||||||
ToneAPI_Log("[WARN] Couldn't request the server! ToneAPI may be down.")
|
|
||||||
ToneAPI_Log("[WARN] " + failure.errorCode)
|
|
||||||
ToneAPI_Log("[WARN] " + failure.errorMessage)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
void function Tone_Test_Auth() {
|
|
||||||
HttpRequest request
|
|
||||||
request.method = HttpRequestMethod.POST
|
|
||||||
request.url = toneapi_data.Tone_URI + "/"
|
|
||||||
Tone_HTTP_Request(
|
|
||||||
request,
|
|
||||||
void function(HttpRequestResponse response) {
|
|
||||||
ToneAPI_Log("Tone API Initialized")
|
|
||||||
toneapi_data.connected = true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
bool function hasCustomAirAccel(){
|
|
||||||
return Code_GetCurrentPlaylistVarOrUseValue("custom_air_accel_pilot", "null") != "null"
|
|
||||||
}
|
|
||||||
|
|
||||||
void function Tone_Register_Match() {
|
|
||||||
HttpRequest request
|
|
||||||
request.method = HttpRequestMethod.POST
|
|
||||||
request.url = toneapi_data.Tone_URI + "/match"
|
|
||||||
request.body = EncodeJSON({
|
|
||||||
gamemode = GameRules_GetGameMode()
|
|
||||||
game_map = StringReplace(GetMapName(), "mp_", "")
|
|
||||||
server_name = GetConVarString("ns_server_name")
|
|
||||||
air_accel = hasCustomAirAccel()
|
|
||||||
})
|
|
||||||
Tone_HTTP_Request(
|
|
||||||
request,
|
|
||||||
void function(HttpRequestResponse response) {
|
|
||||||
table data = DecodeJSON(response.body)
|
|
||||||
toneapi_data.matchId = expect int(data.match)
|
|
||||||
ToneAPI_Log("Tone API Online !")
|
|
||||||
ToneAPI_Log("Sending kills with match ID : " + data.match)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
void function ToneAPI_Log(string s) {
|
|
||||||
print(prefix + s)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user