From aef0d1c1268ab7d4bc18996c9c6b4da16a40aadc Mon Sep 17 00:00:00 2001 From: navewindre Date: Mon, 4 Dec 2023 18:06:10 +0100 Subject: bbbbbbbbwaaaaaaaaaaa --- sourcemod/scripting/gokz-global/api.sp | 142 +++++++++++++ sourcemod/scripting/gokz-global/ban_player.sp | 42 ++++ sourcemod/scripting/gokz-global/commands.sp | 169 +++++++++++++++ sourcemod/scripting/gokz-global/maptop_menu.sp | 249 +++++++++++++++++++++++ sourcemod/scripting/gokz-global/points.sp | 147 +++++++++++++ sourcemod/scripting/gokz-global/print_records.sp | 190 +++++++++++++++++ sourcemod/scripting/gokz-global/send_run.sp | 143 +++++++++++++ 7 files changed, 1082 insertions(+) create mode 100644 sourcemod/scripting/gokz-global/api.sp create mode 100644 sourcemod/scripting/gokz-global/ban_player.sp create mode 100644 sourcemod/scripting/gokz-global/commands.sp create mode 100644 sourcemod/scripting/gokz-global/maptop_menu.sp create mode 100644 sourcemod/scripting/gokz-global/points.sp create mode 100644 sourcemod/scripting/gokz-global/print_records.sp create mode 100644 sourcemod/scripting/gokz-global/send_run.sp (limited to 'sourcemod/scripting/gokz-global') diff --git a/sourcemod/scripting/gokz-global/api.sp b/sourcemod/scripting/gokz-global/api.sp new file mode 100644 index 0000000..23caa15 --- /dev/null +++ b/sourcemod/scripting/gokz-global/api.sp @@ -0,0 +1,142 @@ +static GlobalForward H_OnNewTopTime; +static GlobalForward H_OnPointsUpdated; + + + +// =====[ FORWARDS ]===== + +void CreateGlobalForwards() +{ + H_OnNewTopTime = new GlobalForward("GOKZ_GL_OnNewTopTime", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Float); + H_OnPointsUpdated = new GlobalForward("GOKZ_GL_OnPointsUpdated", ET_Ignore, Param_Cell, Param_Cell); +} + +void Call_OnNewTopTime(int client, int course, int mode, int timeType, int rank, int rankOverall, float time) +{ + Call_StartForward(H_OnNewTopTime); + Call_PushCell(client); + Call_PushCell(course); + Call_PushCell(mode); + Call_PushCell(timeType); + Call_PushCell(rank); + Call_PushCell(rankOverall); + Call_PushFloat(time); + Call_Finish(); +} + +void Call_OnPointsUpdated(int client, int mode) +{ + Call_StartForward(H_OnPointsUpdated); + Call_PushCell(client); + Call_PushCell(mode); + Call_Finish(); +} + + + +// =====[ NATIVES ]===== + +void CreateNatives() +{ + CreateNative("GOKZ_GL_PrintRecords", Native_PrintRecords); + CreateNative("GOKZ_GL_DisplayMapTopMenu", Native_DisplayMapTopMenu); + CreateNative("GOKZ_GL_GetPoints", Native_GetPoints); + CreateNative("GOKZ_GL_GetMapPoints", Native_GetMapPoints); + CreateNative("GOKZ_GL_GetRankPoints", Native_GetRankPoints); + CreateNative("GOKZ_GL_GetFinishes", Native_GetFinishes); + CreateNative("GOKZ_GL_UpdatePoints", Native_UpdatePoints); + CreateNative("GOKZ_GL_GetAPIKeyValid", Native_GetAPIKeyValid); + CreateNative("GOKZ_GL_GetPluginsValid", Native_GetPluginsValid); + CreateNative("GOKZ_GL_GetSettingsEnforcerValid", Native_GetSettingsEnforcerValid); + CreateNative("GOKZ_GL_GetMapValid", Native_GetMapValid); + CreateNative("GOKZ_GL_GetPlayerValid", Native_GetPlayerValid); +} + +public int Native_PrintRecords(Handle plugin, int numParams) +{ + char map[33], steamid[32]; + GetNativeString(2, map, sizeof(map)); + GetNativeString(5, steamid, sizeof(steamid)); + + if (StrEqual(map, "")) + { + PrintRecords(GetNativeCell(1), gC_CurrentMap, GetNativeCell(3), GetNativeCell(4), steamid); + } + else + { + PrintRecords(GetNativeCell(1), map, GetNativeCell(3), GetNativeCell(4), steamid); + } + return 0; +} + +public int Native_DisplayMapTopMenu(Handle plugin, int numParams) +{ + char pluginName[32]; + GetPluginFilename(plugin, pluginName, sizeof(pluginName)); + bool localRanksCall = StrEqual(pluginName, "gokz-localranks.smx", false); + + char map[33]; + GetNativeString(2, map, sizeof(map)); + + if (StrEqual(map, "")) + { + DisplayMapTopSubmenu(GetNativeCell(1), gC_CurrentMap, GetNativeCell(3), GetNativeCell(4), GetNativeCell(5), localRanksCall); + } + else + { + DisplayMapTopSubmenu(GetNativeCell(1), map, GetNativeCell(3), GetNativeCell(4), GetNativeCell(5), localRanksCall); + } + return 0; +} + +public int Native_GetPoints(Handle plugin, int numParams) +{ + return GetPoints(GetNativeCell(1), GetNativeCell(2), GetNativeCell(3)); +} + +public int Native_GetMapPoints(Handle plugin, int numParams) +{ + return GetMapPoints(GetNativeCell(1), GetNativeCell(2), GetNativeCell(3)); +} + +public int Native_GetRankPoints(Handle plugin, int numParams) +{ + return GetRankPoints(GetNativeCell(1), GetNativeCell(2)); +} + +public int Native_GetFinishes(Handle plugin, int numParams) +{ + return GetFinishes(GetNativeCell(1), GetNativeCell(2), GetNativeCell(3)); +} + +public int Native_UpdatePoints(Handle plugin, int numParams) +{ + // We're gonna always force an update here, cause otherwise the call doesn't really make sense + UpdatePoints(GetNativeCell(1), true, GetNativeCell(2)); + return 0; +} + +public int Native_GetAPIKeyValid(Handle plugin, int numParams) +{ + return view_as(gB_APIKeyCheck); +} + +public int Native_GetPluginsValid(Handle plugin, int numParams) +{ + return view_as(gB_BannedCommandsCheck); +} + +public int Native_GetSettingsEnforcerValid(Handle plugin, int numParams) +{ + return view_as(gCV_gokz_settings_enforcer.BoolValue && gB_EnforcerOnFreshMap); +} + +public int Native_GetMapValid(Handle plugin, int numParams) +{ + return view_as(MapCheck()); +} + +public int Native_GetPlayerValid(Handle plugin, int numParams) +{ + return view_as(gB_GloballyVerified[GetNativeCell(1)]); +} diff --git a/sourcemod/scripting/gokz-global/ban_player.sp b/sourcemod/scripting/gokz-global/ban_player.sp new file mode 100644 index 0000000..835d9e5 --- /dev/null +++ b/sourcemod/scripting/gokz-global/ban_player.sp @@ -0,0 +1,42 @@ +/* + Globally ban players when they are suspected by gokz-anticheat. +*/ + + + +// =====[ PUBLIC ]===== + +void GlobalBanPlayer(int client, ACReason reason, const char[] notes, const char[] stats) +{ + char playerName[MAX_NAME_LENGTH], steamid[32], ip[32]; + + GetClientName(client, playerName, sizeof(playerName)); + GetClientAuthId(client, AuthId_Steam2, steamid, sizeof(steamid)); + GetClientIP(client, ip, sizeof(ip)); + + DataPack dp = new DataPack(); + dp.WriteString(playerName); + dp.WriteString(steamid); + + switch (reason) + { + case ACReason_BhopHack:GlobalAPI_CreateBan(BanPlayerCallback, dp, steamid, "bhop_hack", stats, notes, ip); + case ACReason_BhopMacro:GlobalAPI_CreateBan(BanPlayerCallback, dp, steamid, "bhop_macro", stats, notes, ip); + } +} + +public int BanPlayerCallback(JSON_Object response, GlobalAPIRequestData request, DataPack dp) +{ + char playerName[MAX_NAME_LENGTH], steamid[32]; + + dp.Reset(); + dp.ReadString(playerName, sizeof(playerName)); + dp.ReadString(steamid, sizeof(steamid)); + delete dp; + + if (request.Failure) + { + LogError("Failed to globally ban %s (%s).", playerName, steamid); + } + return 0; +} diff --git a/sourcemod/scripting/gokz-global/commands.sp b/sourcemod/scripting/gokz-global/commands.sp new file mode 100644 index 0000000..8ee7c32 --- /dev/null +++ b/sourcemod/scripting/gokz-global/commands.sp @@ -0,0 +1,169 @@ +void RegisterCommands() +{ + RegConsoleCmd("sm_globalcheck", CommandGlobalCheck, "[KZ] Show whether global records are currently enabled in chat."); + RegConsoleCmd("sm_gc", CommandGlobalCheck, "[KZ] Show whether global records are currently enabled in chat."); + RegConsoleCmd("sm_tier", CommandTier, "[KZ] Show the map's tier in chat."); + RegConsoleCmd("sm_gpb", CommandPrintPBs, "[KZ] Show main course global personal best in chat. Usage: !gpb "); + RegConsoleCmd("sm_gr", CommandPrintRecords, "[KZ] Show main course global record times in chat. Usage: !gr "); + RegConsoleCmd("sm_gwr", CommandPrintRecords, "[KZ] Show main course global record times in chat. Usage: !gwr "); + RegConsoleCmd("sm_gbpb", CommandPrintBonusPBs, "[KZ] Show bonus global personal best in chat. Usage: !gbpb <#bonus> "); + RegConsoleCmd("sm_gbr", CommandPrintBonusRecords, "[KZ] Show bonus global record times in chat. Usage: !bgr <#bonus> "); + RegConsoleCmd("sm_gbwr", CommandPrintBonusRecords, "[KZ] Show bonus global record times in chat. Usage: !bgwr <#bonus> "); + RegConsoleCmd("sm_gmaptop", CommandMapTop, "[KZ] Open a menu showing the top global main course times of a map. Usage: !gmaptop "); + RegConsoleCmd("sm_gbmaptop", CommandBonusMapTop, "[KZ] Open a menu showing the top global bonus times of a map. Usage: !gbmaptop <#bonus> "); +} + +public Action CommandGlobalCheck(int client, int args) +{ + PrintGlobalCheckToChat(client); + return Plugin_Handled; +} + +public Action CommandTier(int client, int args) +{ + if (gI_MapTier != -1) + { + GOKZ_PrintToChat(client, true, "%t", "Map Tier", gC_CurrentMap, gI_MapTier); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Map Tier (Unknown)", gC_CurrentMap); + } + return Plugin_Handled; +} + +public Action CommandPrintPBs(int client, int args) +{ + char steamid[32]; + GetClientAuthId(client, AuthId_Steam2, steamid, sizeof(steamid)); + return CommandPrintRecordsHelper(client, args, steamid); +} + +public Action CommandPrintRecords(int client, int args) +{ + return CommandPrintRecordsHelper(client, args); +} + +static Action CommandPrintRecordsHelper(int client, int args, const char[] steamid = DEFAULT_STRING) +{ + KZPlayer player = KZPlayer(client); + int mode = player.Mode; + + if (args == 0) + { // Print record times for current map and their current mode + PrintRecords(client, gC_CurrentMap, 0, mode, steamid); + } + else if (args >= 1) + { // Print record times for specified map and their current mode + char argMap[33]; + GetCmdArg(1, argMap, sizeof(argMap)); + PrintRecords(client, argMap, 0, mode, steamid); + } + return Plugin_Handled; +} + +public Action CommandPrintBonusPBs(int client, int args) +{ + char steamid[32]; + GetClientAuthId(client, AuthId_Steam2, steamid, sizeof(steamid)); + return CommandPrintBonusRecordsHelper(client, args, steamid); +} + +public Action CommandPrintBonusRecords(int client, int args) +{ + return CommandPrintBonusRecordsHelper(client, args); +} + +static Action CommandPrintBonusRecordsHelper(int client, int args, const char[] steamid = DEFAULT_STRING) +{ + KZPlayer player = KZPlayer(client); + int mode = player.Mode; + + if (args == 0) + { // Print Bonus 1 record times for current map and their current mode + PrintRecords(client, gC_CurrentMap, 1, mode, steamid); + } + else if (args == 1) + { // Print specified Bonus # record times for current map and their current mode + char argBonus[4]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + PrintRecords(client, gC_CurrentMap, bonus, mode, steamid); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + else if (args >= 2) + { // Print specified Bonus # record times for specified map and their current mode + char argBonus[4], argMap[33]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + GetCmdArg(2, argMap, sizeof(argMap)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + PrintRecords(client, argMap, bonus, mode, steamid); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + return Plugin_Handled; +} + +public Action CommandMapTop(int client, int args) +{ + if (args <= 0) + { // Open global map top for current map + DisplayMapTopModeMenu(client, gC_CurrentMap, 0); + } + else if (args >= 1) + { // Open global map top for specified map + char argMap[64]; + GetCmdArg(1, argMap, sizeof(argMap)); + DisplayMapTopModeMenu(client, argMap, 0); + } + return Plugin_Handled; +} + +public Action CommandBonusMapTop(int client, int args) +{ + if (args == 0) + { // Open global Bonus 1 top for current map + DisplayMapTopModeMenu(client, gC_CurrentMap, 1); + } + else if (args == 1) + { // Open specified global Bonus # top for current map + char argBonus[4]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DisplayMapTopModeMenu(client, gC_CurrentMap, bonus); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + else if (args >= 2) + { // Open specified global Bonus # top for specified map + char argBonus[4], argMap[33]; + GetCmdArg(1, argBonus, sizeof(argBonus)); + GetCmdArg(2, argMap, sizeof(argMap)); + int bonus = StringToInt(argBonus); + if (GOKZ_IsValidCourse(bonus, true)) + { + DisplayMapTopModeMenu(client, argMap, bonus); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "Invalid Bonus Number", argBonus); + } + } + return Plugin_Handled; +} diff --git a/sourcemod/scripting/gokz-global/maptop_menu.sp b/sourcemod/scripting/gokz-global/maptop_menu.sp new file mode 100644 index 0000000..0c71346 --- /dev/null +++ b/sourcemod/scripting/gokz-global/maptop_menu.sp @@ -0,0 +1,249 @@ +/* + Menu with the top global times for a map course and mode. +*/ + +static bool cameFromLocalRanks[MAXPLAYERS + 1]; +static char mapTopMap[MAXPLAYERS + 1][64]; +static int mapTopCourse[MAXPLAYERS + 1]; +static int mapTopMode[MAXPLAYERS + 1]; + + + +// =====[ PUBLIC ]===== + +void DisplayMapTopModeMenu(int client, const char[] map, int course) +{ + FormatEx(mapTopMap[client], sizeof(mapTopMap[]), map); + mapTopCourse[client] = course; + + Menu menu = new Menu(MenuHandler_MapTopModeMenu); + MapTopModeMenuSetTitle(client, menu); + GOKZ_MenuAddModeItems(client, menu, false); + menu.Display(client, MENU_TIME_FOREVER); +} + +void DisplayMapTopMenu(int client, const char[] map, int course, int mode) +{ + FormatEx(mapTopMap[client], sizeof(mapTopMap[]), map); + mapTopCourse[client] = course; + mapTopMode[client] = mode; + + Menu menu = new Menu(MenuHandler_MapTopMenu); + MapTopMenuSetTitle(client, menu); + MapTopMenuAddItems(client, menu); + menu.Display(client, MENU_TIME_FOREVER); +} + +void DisplayMapTopSubmenu(int client, const char[] map, int course, int mode, int timeType, bool fromLocalRanks = false) +{ + char modeStr[32]; + + cameFromLocalRanks[client] = fromLocalRanks; + + DataPack dp = new DataPack(); + dp.WriteCell(GetClientUserId(client)); + dp.WriteCell(timeType); + + FormatEx(mapTopMap[client], sizeof(mapTopMap[]), map); + mapTopCourse[client] = course; + mapTopMode[client] = mode; + GOKZ_GL_GetModeString(mode, modeStr, sizeof(modeStr)); + + // TODO Hard coded 128 tick + // TODO Hard coded cap at top 20 + // TODO Not true NUB yet + GlobalAPI_GetRecordsTop(DisplayMapTopSubmenuCallback, dp, _, _, _, map, 128, course, modeStr, + timeType == TimeType_Nub ? DEFAULT_BOOL : false, _, 0, 20); +} + + + +// =====[ EVENTS ]===== + +public int MenuHandler_MapTopModeMenu(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + // param1 = client, param2 = mode + DisplayMapTopMenu(param1, mapTopMap[param1], mapTopCourse[param1], param2); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_MapTopMenu(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + char info[8]; + menu.GetItem(param2, info, sizeof(info)); + int timeType = StringToInt(info); + DisplayMapTopSubmenu(param1, mapTopMap[param1], mapTopCourse[param1], mapTopMode[param1], timeType); + } + if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + DisplayMapTopModeMenu(param1, mapTopMap[param1], mapTopCourse[param1]); + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +public int MenuHandler_MapTopSubmenu(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Cancel && param2 == MenuCancel_Exit) + { + if (cameFromLocalRanks[param1]) + { + GOKZ_LR_ReopenMapTopMenu(param1); + } + else + { + DisplayMapTopMenu(param1, mapTopMap[param1], mapTopCourse[param1], mapTopMode[param1]); + } + } + if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + + + +// =====[ PRIVATE ]===== + +static void MapTopModeMenuSetTitle(int client, Menu menu) +{ + if (mapTopCourse[client] == 0) + { + menu.SetTitle("%T", "Global Map Top Mode Menu - Title", client, mapTopMap[client]); + } + else + { + menu.SetTitle("%T", "Global Map Top Mode Menu - Title (Bonus)", client, mapTopMap[client], mapTopCourse[client]); + } +} + +static void MapTopMenuSetTitle(int client, Menu menu) +{ + if (mapTopCourse[client] == 0) + { + menu.SetTitle("%T", "Global Map Top Menu - Title", client, mapTopMap[client], gC_ModeNames[mapTopMode[client]]); + } + else + { + menu.SetTitle("%T", "Global Map Top Menu - Title (Bonus)", client, mapTopMap[client], mapTopCourse[client], gC_ModeNames[mapTopMode[client]]); + } +} + +static void MapTopMenuAddItems(int client, Menu menu) +{ + char display[32]; + for (int i = 0; i < TIMETYPE_COUNT; i++) + { + FormatEx(display, sizeof(display), "%T", "Global Map Top Menu - Top", client, gC_TimeTypeNames[i]); + menu.AddItem(IntToStringEx(i), display); + } +} + +public int DisplayMapTopSubmenuCallback(JSON_Object top, GlobalAPIRequestData request, DataPack dp) +{ + dp.Reset(); + int client = GetClientOfUserId(dp.ReadCell()); + int timeType = dp.ReadCell(); + delete dp; + + if (request.Failure) + { + LogError("Failed to get top records with Global API."); + return 0; + } + + if (!top.IsArray) + { + LogError("GlobalAPI returned a malformed response while looking up the top records."); + return 0; + } + + if (!IsValidClient(client)) + { + return 0; + } + + Menu menu = new Menu(MenuHandler_MapTopSubmenu); + if (mapTopCourse[client] == 0) + { + menu.SetTitle("%T", "Global Map Top Submenu - Title", client, + gC_TimeTypeNames[timeType], mapTopMap[client], gC_ModeNames[mapTopMode[client]]); + } + else + { + menu.SetTitle("%T", "Global Map Top Submenu - Title (Bonus)", client, + gC_TimeTypeNames[timeType], mapTopMap[client], mapTopCourse[client], gC_ModeNames[mapTopMode[client]]); + } + + if (MapTopSubmenuAddItems(menu, top, timeType) == 0) + { // If no records found + if (timeType == TimeType_Pro) + { + GOKZ_PrintToChat(client, true, "%t", "No Global Times Found (PRO)"); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "No Global Times Found"); + } + + if (cameFromLocalRanks[client]) + { + GOKZ_LR_ReopenMapTopMenu(client); + } + else + { + DisplayMapTopMenu(client, mapTopMap[client], mapTopCourse[client], mapTopMode[client]); + } + } + else + { + menu.Pagination = 5; + menu.Display(client, MENU_TIME_FOREVER); + } + return 0; +} + +// Returns number of record times added to the menu +static int MapTopSubmenuAddItems(Menu menu, JSON_Object records, int timeType) +{ + char playerName[MAX_NAME_LENGTH]; + char display[128]; + + for (int i = 0; i < records.Length; i++) + { + APIRecord record = view_as(records.GetObjectIndexed(i)); + + record.GetPlayerName(playerName, sizeof(playerName)); + + switch (timeType) + { + case TimeType_Nub: + { + FormatEx(display, sizeof(display), "#%-2d %11s %3d TP %s", + i + 1, GOKZ_FormatTime(record.Time), record.Teleports, playerName); + } + case TimeType_Pro: + { + FormatEx(display, sizeof(display), "#%-2d %11s %s", + i + 1, GOKZ_FormatTime(record.Time), playerName); + } + } + + menu.AddItem("", display, ITEMDRAW_DISABLED); + } + + return records.Length; +} \ No newline at end of file diff --git a/sourcemod/scripting/gokz-global/points.sp b/sourcemod/scripting/gokz-global/points.sp new file mode 100644 index 0000000..7758318 --- /dev/null +++ b/sourcemod/scripting/gokz-global/points.sp @@ -0,0 +1,147 @@ + +int pointsTotal[MAXPLAYERS + 1][MODE_COUNT][TIMETYPE_COUNT]; +int finishes[MAXPLAYERS + 1][MODE_COUNT][TIMETYPE_COUNT]; +int pointsMap[MAXPLAYERS + 1][MODE_COUNT][TIMETYPE_COUNT]; +int requestsInProgress[MAXPLAYERS + 1]; + + + +void ResetPoints(int client) +{ + for (int mode = 0; mode < MODE_COUNT; mode++) + { + for (int type = 0; type < TIMETYPE_COUNT; type++) + { + pointsTotal[client][mode][type] = -1; + finishes[client][mode][type] = -1; + pointsMap[client][mode][type] = -1; + } + } + requestsInProgress[client] = 0; +} + +void ResetMapPoints(int client) +{ + for (int mode = 0; mode < MODE_COUNT; mode++) + { + for (int type = 0; type < TIMETYPE_COUNT; type++) + { + pointsMap[client][mode][type] = -1; + } + } + requestsInProgress[client] = 0; +} + +int GetRankPoints(int client, int mode) +{ + return pointsTotal[client][mode][TimeType_Nub]; +} + +int GetPoints(int client, int mode, int timeType) +{ + return pointsTotal[client][mode][timeType]; +} + +int GetMapPoints(int client, int mode, int timeType) +{ + return pointsMap[client][mode][timeType]; +} + +int GetFinishes(int client, int mode, int timeType) +{ + return finishes[client][mode][timeType]; +} + +// Note: This only gets 128 tick records +void UpdatePoints(int client, bool force = false, int mode = -1) +{ + if (requestsInProgress[client] != 0) + { + return; + } + + if (mode == -1) + { + mode = GOKZ_GetCoreOption(client, Option_Mode); + } + + if (!force || pointsTotal[client][mode][TimeType_Nub] == -1) + { + GetPlayerRanks(client, mode, TimeType_Nub); + GetPlayerRanks(client, mode, TimeType_Pro); + requestsInProgress[client] += 2; + } + + if (gI_MapID != -1 && (!force || pointsMap[client][mode][TimeType_Nub] == -1)) + { + GetPlayerRanks(client, mode, TimeType_Nub, gI_MapID); + GetPlayerRanks(client, mode, TimeType_Pro, gI_MapID); + requestsInProgress[client] += 2; + } +} + +static void GetPlayerRanks(int client, int mode, int timeType, int mapID = DEFAULT_INT) +{ + char steamid[21]; + int modes[1], mapIDs[1]; + + modes[0] = view_as(GOKZ_GL_GetGlobalMode(mode)); + mapIDs[0] = mapID; + GetClientAuthId(client, AuthId_SteamID64, steamid, sizeof(steamid)); + + DataPack dp = new DataPack(); + dp.WriteCell(GetClientUserId(client)); + dp.WriteCell(mode); + dp.WriteCell(timeType); + dp.WriteCell(mapID == DEFAULT_INT); + GlobalAPI_GetPlayerRanks(UpdatePointsCallback, dp, _, _, _, _, steamid, _, _, + mapIDs, mapID == DEFAULT_INT ? DEFAULT_INT : 1, { 0 }, 1, + modes, 1, { 128 }, 1, timeType == TimeType_Nub ? DEFAULT_BOOL : false, _, _); +} + +static void UpdatePointsCallback(JSON_Object ranks, GlobalAPIRequestData request, DataPack dp) +{ + dp.Reset(); + int client = GetClientOfUserId(dp.ReadCell()); + int mode = dp.ReadCell(); + int timeType = dp.ReadCell(); + bool isTotal = dp.ReadCell(); + delete dp; + + requestsInProgress[client]--; + + if (client == 0) + { + return; + } + + int points, totalFinishes; + if (request.Failure || !ranks.IsArray || ranks.Length == 0) + { + points = 0; + totalFinishes = 0; + } + else + { + APIPlayerRank rank = view_as(ranks.GetObjectIndexed(0)); + // points = timeType == TimeType_Nub ? rank.PointsOverall : rank.Points; + points = points == -1 ? 0 : rank.Points; + totalFinishes = rank.Finishes == -1 ? 0 : rank.Finishes; + } + + if (isTotal) + { + pointsTotal[client][mode][timeType] = points; + finishes[client][mode][timeType] = totalFinishes; + } + else + { + pointsMap[client][mode][timeType] = points; + } + + // We always do that cause not all of the requests might have failed + if (requestsInProgress[client] == 0) + { + Call_OnPointsUpdated(client, mode); + } +} diff --git a/sourcemod/scripting/gokz-global/print_records.sp b/sourcemod/scripting/gokz-global/print_records.sp new file mode 100644 index 0000000..3966ed5 --- /dev/null +++ b/sourcemod/scripting/gokz-global/print_records.sp @@ -0,0 +1,190 @@ +/* + Prints the global record times for a map course and mode. +*/ + + +static bool inProgress[MAXPLAYERS + 1]; +static bool waitingForOtherCallback[MAXPLAYERS + 1]; +static bool isPBQuery[MAXPLAYERS + 1]; +static char printRecordsMap[MAXPLAYERS + 1][64]; +static int printRecordsCourse[MAXPLAYERS + 1]; +static int printRecordsMode[MAXPLAYERS + 1]; +static bool printRecordsTimeExists[MAXPLAYERS + 1][TIMETYPE_COUNT]; +static float printRecordsTimes[MAXPLAYERS + 1][TIMETYPE_COUNT]; +static char printRecordsPlayerNames[MAXPLAYERS + 1][TIMETYPE_COUNT][MAX_NAME_LENGTH]; + + + +// =====[ PUBLIC ]===== + +void PrintRecords(int client, const char[] map, int course, int mode, const char[] steamid = DEFAULT_STRING) +{ + char mode_str[32]; + + if (inProgress[client]) + { + GOKZ_PrintToChat(client, true, "%t", "Please Wait Before Using Command Again"); + return; + } + + GOKZ_GL_GetModeString(mode, mode_str, sizeof(mode_str)); + + DataPack dpNUB = CreateDataPack(); + dpNUB.WriteCell(GetClientUserId(client)); + dpNUB.WriteCell(TimeType_Nub); + GlobalAPI_GetRecordsTop(PrintRecordsCallback, dpNUB, steamid, _, _, map, 128, course, mode_str, _, _, 0, 1); + + DataPack dpPRO = CreateDataPack(); + dpPRO.WriteCell(GetClientUserId(client)); + dpPRO.WriteCell(TimeType_Pro); + GlobalAPI_GetRecordsTop(PrintRecordsCallback, dpPRO, steamid, _, _, map, 128, course, mode_str, false, _, 0, 1); + + inProgress[client] = true; + waitingForOtherCallback[client] = true; + isPBQuery[client] = !StrEqual(steamid, DEFAULT_STRING); + FormatEx(printRecordsMap[client], sizeof(printRecordsMap[]), map); + printRecordsCourse[client] = course; + printRecordsMode[client] = mode; +} + +public int PrintRecordsCallback(JSON_Object records, GlobalAPIRequestData request, DataPack dp) +{ + dp.Reset(); + int client = GetClientOfUserId(dp.ReadCell()); + int timeType = dp.ReadCell(); + delete dp; + + if (request.Failure) + { + LogError("Failed to retrieve record from the Global API for printing."); + return 0; + } + + if (!IsValidClient(client)) + { + return 0; + } + + if (records.Length <= 0) + { + printRecordsTimeExists[client][timeType] = false; + } + else + { + APIRecord record = view_as(records.GetObjectIndexed(0)); + printRecordsTimeExists[client][timeType] = true; + printRecordsTimes[client][timeType] = record.Time; + record.GetPlayerName(printRecordsPlayerNames[client][timeType], sizeof(printRecordsPlayerNames[][])); + } + + if (!waitingForOtherCallback[client]) + { + if (isPBQuery[client]) + { + PrintPBsFinally(client); + } + else + { + PrintRecordsFinally(client); + } + inProgress[client] = false; + } + else + { + waitingForOtherCallback[client] = false; + } + return 0; +} + + + +// =====[ EVENTS ]===== + +void OnClientPutInServer_PrintRecords(int client) +{ + inProgress[client] = false; +} + + + +// =====[ PRIVATE ]===== + +static void PrintPBsFinally(int client) +{ + // Print GPB header to chat + if (printRecordsCourse[client] == 0) + { + GOKZ_PrintToChat(client, true, "%t", "GPB Header", + printRecordsMap[client], + gC_ModeNamesShort[printRecordsMode[client]]); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "GPB Header (Bonus)", + printRecordsMap[client], + printRecordsCourse[client], + gC_ModeNamesShort[printRecordsMode[client]]); + } + + // Print GPB times to chat + if (!printRecordsTimeExists[client][TimeType_Nub]) + { + GOKZ_PrintToChat(client, false, "%t", "No Global Times Found"); + } + else if (!printRecordsTimeExists[client][TimeType_Pro]) + { + GOKZ_PrintToChat(client, false, "%t", "GPB Time - NUB", + GOKZ_FormatTime(printRecordsTimes[client][TimeType_Nub]), + printRecordsPlayerNames[client][TimeType_Nub]); + GOKZ_PrintToChat(client, false, "%t", "GPB Time - No PRO Time"); + } + else + { + GOKZ_PrintToChat(client, false, "%t", "GPB Time - NUB", + GOKZ_FormatTime(printRecordsTimes[client][TimeType_Nub]), + printRecordsPlayerNames[client][TimeType_Nub]); + GOKZ_PrintToChat(client, false, "%t", "GPB Time - PRO", + GOKZ_FormatTime(printRecordsTimes[client][TimeType_Pro]), + printRecordsPlayerNames[client][TimeType_Pro]); + } +} + +static void PrintRecordsFinally(int client) +{ + // Print GWR header to chat + if (printRecordsCourse[client] == 0) + { + GOKZ_PrintToChat(client, true, "%t", "GWR Header", + printRecordsMap[client], + gC_ModeNamesShort[printRecordsMode[client]]); + } + else + { + GOKZ_PrintToChat(client, true, "%t", "GWR Header (Bonus)", + printRecordsMap[client], + printRecordsCourse[client], + gC_ModeNamesShort[printRecordsMode[client]]); + } + + // Print GWR times to chat + if (!printRecordsTimeExists[client][TimeType_Nub]) + { + GOKZ_PrintToChat(client, false, "%t", "No Global Times Found"); + } + else if (!printRecordsTimeExists[client][TimeType_Pro]) + { + GOKZ_PrintToChat(client, false, "%t", "GWR Time - NUB", + GOKZ_FormatTime(printRecordsTimes[client][TimeType_Nub]), + printRecordsPlayerNames[client][TimeType_Nub]); + GOKZ_PrintToChat(client, false, "%t", "GWR Time - No PRO Time"); + } + else + { + GOKZ_PrintToChat(client, false, "%t", "GWR Time - NUB", + GOKZ_FormatTime(printRecordsTimes[client][TimeType_Nub]), + printRecordsPlayerNames[client][TimeType_Nub]); + GOKZ_PrintToChat(client, false, "%t", "GWR Time - PRO", + GOKZ_FormatTime(printRecordsTimes[client][TimeType_Pro]), + printRecordsPlayerNames[client][TimeType_Pro]); + } +} diff --git a/sourcemod/scripting/gokz-global/send_run.sp b/sourcemod/scripting/gokz-global/send_run.sp new file mode 100644 index 0000000..f560958 --- /dev/null +++ b/sourcemod/scripting/gokz-global/send_run.sp @@ -0,0 +1,143 @@ +/* + Sends a run to the global API and delete the replay if it is a temporary replay. +*/ + + + +char storedReplayPath[MAXPLAYERS + 1][512]; +int lastRecordId[MAXPLAYERS + 1], storedCourse[MAXPLAYERS + 1], storedTimeType[MAXPLAYERS + 1], storedUserId[MAXPLAYERS + 1]; +float storedTime[MAXPLAYERS + 1]; +bool deleteRecord[MAXPLAYERS + 1]; + +// =====[ PUBLIC ]===== + +void SendTime(int client, int course, float time, int teleportsUsed) +{ + char steamid[32], modeStr[32]; + KZPlayer player = KZPlayer(client); + int mode = player.Mode; + + if (GlobalsEnabled(mode)) + { + DataPack dp = CreateDataPack(); + dp.WriteCell(GetClientUserId(client)); + dp.WriteCell(course); + dp.WriteCell(mode); + dp.WriteCell(GOKZ_GetTimeTypeEx(teleportsUsed)); + dp.WriteFloat(time); + + GetClientAuthId(client, AuthId_Steam2, steamid, sizeof(steamid)); + GOKZ_GL_GetModeString(mode, modeStr, sizeof(modeStr)); + GlobalAPI_CreateRecord(SendTimeCallback, dp, steamid, gI_MapID, modeStr, course, 128, teleportsUsed, time); + } +} + +public int SendTimeCallback(JSON_Object response, GlobalAPIRequestData request, DataPack dp) +{ + dp.Reset(); + int userID = dp.ReadCell(); + int client = GetClientOfUserId(userID); + int course = dp.ReadCell(); + int mode = dp.ReadCell(); + int timeType = dp.ReadCell(); + float time = dp.ReadFloat(); + delete dp; + + if (!IsValidClient(client)) + { + return 0; + } + + if (request.Failure) + { + LogError("Failed to send a time to the global API."); + return 0; + } + + int top_place = response.GetInt("top_100"); + int top_overall_place = response.GetInt("top_100_overall"); + + if (top_place > 0) + { + Call_OnNewTopTime(client, course, mode, timeType, top_place, top_overall_place, time); + } + + // Don't like doing this here, but seems to be the most efficient place + UpdatePoints(client, true); + + // Check if we can send the replay + lastRecordId[client] = response.GetInt("record_id"); + if (IsReplayReadyToSend(client, course, timeType, time)) + { + SendReplay(client); + } + else + { + storedUserId[client] = userID; + storedCourse[client] = course; + storedTimeType[client] = timeType; + storedTime[client] = time; + } + return 0; +} + +public void OnReplaySaved_SendReplay(int client, int replayType, const char[] map, int course, int timeType, float time, const char[] filePath, bool tempReplay) +{ + strcopy(storedReplayPath[client], sizeof(storedReplayPath[]), filePath); + if (IsReplayReadyToSend(client, course, timeType, time)) + { + SendReplay(client); + } + else + { + lastRecordId[client] = -1; + storedUserId[client] = GetClientUserId(client); + storedCourse[client] = course; + storedTimeType[client] = timeType; + storedTime[client] = time; + deleteRecord[client] = tempReplay; + } +} + +bool IsReplayReadyToSend(int client, int course, int timeType, float time) +{ + // Not an error, just not ready yet + if (lastRecordId[client] == -1 || storedReplayPath[client][0] == '\0') + { + return false; + } + + if (storedUserId[client] == GetClientUserId(client) && storedCourse[client] == course + && storedTimeType[client] == timeType && storedTime[client] == time) + { + return true; + } + else + { + LogError("Failed to upload replay to the global API. Record mismatch."); + return false; + } +} + +public void SendReplay(int client) +{ + DataPack dp = new DataPack(); + dp.WriteString(deleteRecord[client] ? storedReplayPath[client] : ""); + GlobalAPI_CreateReplayForRecordId(SendReplayCallback, dp, lastRecordId[client], storedReplayPath[client]); + lastRecordId[client] = -1; + storedReplayPath[client] = ""; +} + +public int SendReplayCallback(JSON_Object response, GlobalAPIRequestData request, DataPack dp) +{ + // Delete the temporary replay file if needed. + dp.Reset(); + char replayPath[PLATFORM_MAX_PATH]; + dp.ReadString(replayPath, sizeof(replayPath)); + if (replayPath[0] != '\0') + { + DeleteFile(replayPath); + } + delete dp; + return 0; +} -- cgit v1.2.3