mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-06 18:08:26 +00:00
zones wip (#1143)
* backup a lot of this zone_cache_t stuff since i'm going to do something else first * AAAAAAAAAAAAAA * add the sTarget checking * this pr will get squashed so this message doesn't matter * wip Shavit_RemoveZone * wip ZF_Solid and TODO notes * move hook thing * do some zone insert stuff that doesn't reload *every* zone * condense some zone editing global variables * add some spaces to some ifs * remove gV_MapZones * remove random loop * big change * remove ClearZone() * . * .. * add speed to zone beam settings * add bhop_n0bs1_css stripper cfg for shit zone * ... * remove draw timer to OnConfigsExecuted because interval cvar * change string for mapfixes print * wew * rename iSource to iForm and add sSource * add Shavit_ReloadZones() and rename some source things * add shavit-zones-http.sp * add a getarray * adjust the http api format slightly * remove Shavit_GetStageZone() & fix zone inserts * api update * convar edits * increase buf size * wrong buf... * normalize points inside Shavit_AddZone * rename ZonesNotLocal to ZonesNotSQL * small cleanup * add the zone hooking menu stuff * make the confirm menu Exit button STOP DRAWING!!! * only try to draw trigger_multiples * asdf * typo * improvements * add distance to menu * use PassesTriggerFilters like rngfix * finish some docs * make dist be meters * more hooking tele things * remove all this migration stuff * add entity under crosshair * shorten stage translation message
This commit is contained in:
parent
affac70f99
commit
e3aac2d24e
@ -17,6 +17,13 @@
|
||||
"windows" "@CreateInterface"
|
||||
"linux" "@CreateInterface"
|
||||
}
|
||||
|
||||
"CreateInterface_Engine"
|
||||
{
|
||||
"library" "engine"
|
||||
"windows" "@CreateInterface"
|
||||
"linux" "@CreateInterface"
|
||||
}
|
||||
}
|
||||
|
||||
"Offsets"
|
||||
@ -39,6 +46,12 @@
|
||||
{
|
||||
"Offsets"
|
||||
{
|
||||
// todo
|
||||
"CBaseTrigger::PassesTriggerFilters"
|
||||
{
|
||||
"windows" "210"
|
||||
"linux" "211"
|
||||
}
|
||||
// search string: "start %f %f %f" and then check the function call offsets above it and convert them to vtable offsets (divide by 4 most likely or whatever)
|
||||
"CCSPlayer::GetPlayerMaxSpeed"
|
||||
{
|
||||
@ -73,6 +86,18 @@
|
||||
"windows" "8"
|
||||
"linux" "8"
|
||||
}
|
||||
// TODO
|
||||
"GetClusterForOrigin"
|
||||
{
|
||||
"windows" "12"
|
||||
"linux" "12"
|
||||
}
|
||||
// TODO
|
||||
"GetArea"
|
||||
{
|
||||
"windows" "65"
|
||||
"linux" "65"
|
||||
}
|
||||
}
|
||||
|
||||
"Signatures"
|
||||
@ -116,6 +141,12 @@
|
||||
{
|
||||
"Offsets"
|
||||
{
|
||||
// https://asherkin.github.io/vtable/
|
||||
"CBaseTrigger::PassesTriggerFilters"
|
||||
{
|
||||
"windows" "197"
|
||||
"linux" "198"
|
||||
}
|
||||
// https://asherkin.github.io/vtable/
|
||||
"CCSPlayer::GetPlayerMaxSpeed"
|
||||
{
|
||||
@ -173,6 +204,18 @@
|
||||
"windows" "5724"
|
||||
"linux" "5744" // +20 wow that's easy!
|
||||
}
|
||||
// TODO
|
||||
"GetClusterForOrigin"
|
||||
{
|
||||
"windows" "11"
|
||||
"linux" "11"
|
||||
}
|
||||
// TODO
|
||||
"GetArea"
|
||||
{
|
||||
"windows" "64"
|
||||
"linux" "64"
|
||||
}
|
||||
}
|
||||
|
||||
"Signatures"
|
||||
@ -223,6 +266,12 @@
|
||||
{
|
||||
"Offsets"
|
||||
{
|
||||
// https://asherkin.github.io/vtable/
|
||||
"CBaseTrigger::PassesTriggerFilters"
|
||||
{
|
||||
"windows" "201"
|
||||
"linux" "202"
|
||||
}
|
||||
// https://asherkin.github.io/vtable/
|
||||
"CGameRules::IsSpawnPointValid"
|
||||
{
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* shavit's Timer - area_and_cluster_stages.sp
|
||||
* by: carnifex
|
||||
*
|
||||
* This file is part of shavit's Timer.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// originally sourced from https://github.com/hermansimensen/mapstages
|
||||
|
||||
Address IVEngineServer;
|
||||
Handle gH_GetCluster;
|
||||
Handle gH_GetArea;
|
||||
|
||||
void LoadDHooks_mapstages(GameData gamedata)
|
||||
{
|
||||
StartPrepSDKCall(SDKCall_Static);
|
||||
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Signature, "CreateInterface"))
|
||||
{
|
||||
SetFailState("Failed to get CreateInterface");
|
||||
}
|
||||
|
||||
PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
|
||||
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL);
|
||||
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
||||
Handle CreateInterface = EndPrepSDKCall();
|
||||
|
||||
if (CreateInterface == null)
|
||||
{
|
||||
SetFailState("Unable to prepare SDKCall for CreateInterface");
|
||||
}
|
||||
|
||||
char interfaceName[64];
|
||||
if (!GameConfGetKeyValue(gamedata, "IVEngineServer", interfaceName, sizeof(interfaceName)))
|
||||
{
|
||||
SetFailState("Failed to get IVEngineServer interface name");
|
||||
}
|
||||
|
||||
IVEngineServer = SDKCall(CreateInterface, interfaceName, 0);
|
||||
|
||||
if (!IVEngineServer)
|
||||
{
|
||||
SetFailState("Failed to get IVEngineServer pointer");
|
||||
}
|
||||
|
||||
StartPrepSDKCall(SDKCall_Raw);
|
||||
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Virtual, "GetClusterForOrigin"))
|
||||
{
|
||||
SetFailState("Couldn't find GetClusterForOrigin offset");
|
||||
}
|
||||
PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_Plain);
|
||||
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
||||
gH_GetCluster = EndPrepSDKCall();
|
||||
|
||||
StartPrepSDKCall(SDKCall_Raw);
|
||||
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Virtual, "GetArea"))
|
||||
{
|
||||
SetFailState("Couldn't find GetArea offset");
|
||||
}
|
||||
PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_Plain);
|
||||
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
||||
gH_GetArea = EndPrepSDKCall();
|
||||
|
||||
delete CreateInterface;
|
||||
}
|
||||
|
||||
public int GetClusterForOrigin(const float pos[3])
|
||||
{
|
||||
return SDKCall(gH_GetCluster, IVEngineServer, pos);
|
||||
}
|
||||
|
||||
public int GetAreaForOrigin(const float pos[3])
|
||||
{
|
||||
return SDKCall(gH_GetArea, IVEngineServer, pos);
|
||||
}
|
||||
@ -30,6 +30,9 @@
|
||||
// god i fucking hate sourcemod. NULL_VECTOR isn't const so it's not guaranteed to be 0,0,0
|
||||
#define ZERO_VECTOR view_as<float>({0,0,0})
|
||||
|
||||
// stolen from boosterfix
|
||||
#define EXPAND_VECTOR(%1) %1[0], %1[1], %1[2]
|
||||
|
||||
#define SHAVIT_LOG_QUERIES 0
|
||||
|
||||
#include <shavit/bhopstats-timerified>
|
||||
|
||||
@ -47,6 +47,8 @@ enum
|
||||
Migration_Lowercase_startpositions,
|
||||
Migration_AddPlayertimesPointsCalcedFrom, // points calculated from wr float added to playertimes
|
||||
Migration_RemovePlayertimesPointsCalcedFrom, // lol
|
||||
Migration_NormalizeMapzonePoints,
|
||||
Migration_AddMapzonesFormAndTarget, // 25
|
||||
MIGRATIONS_END
|
||||
};
|
||||
|
||||
@ -194,7 +196,7 @@ public void SQL_CreateTables(Database2 hSQL, const char[] prefix, bool mysql)
|
||||
//
|
||||
|
||||
FormatEx(sQuery, sizeof(sQuery),
|
||||
"CREATE TABLE IF NOT EXISTS `%smapzones` (`id` INT AUTO_INCREMENT, `map` VARCHAR(255) NOT NULL, `type` INT, `corner1_x` FLOAT, `corner1_y` FLOAT, `corner1_z` FLOAT, `corner2_x` FLOAT, `corner2_y` FLOAT, `corner2_z` FLOAT, `destination_x` FLOAT NOT NULL DEFAULT 0, `destination_y` FLOAT NOT NULL DEFAULT 0, `destination_z` FLOAT NOT NULL DEFAULT 0, `track` INT NOT NULL DEFAULT 0, `flags` INT NOT NULL DEFAULT 0, `data` INT NOT NULL DEFAULT 0, `prebuilt` BOOL, PRIMARY KEY (`id`)) %s;",
|
||||
"CREATE TABLE IF NOT EXISTS `%smapzones` (`id` INT AUTO_INCREMENT, `map` VARCHAR(255) NOT NULL, `type` INT, `corner1_x` FLOAT, `corner1_y` FLOAT, `corner1_z` FLOAT, `corner2_x` FLOAT, `corner2_y` FLOAT, `corner2_z` FLOAT, `destination_x` FLOAT NOT NULL DEFAULT 0, `destination_y` FLOAT NOT NULL DEFAULT 0, `destination_z` FLOAT NOT NULL DEFAULT 0, `track` INT NOT NULL DEFAULT 0, `flags` INT NOT NULL DEFAULT 0, `data` INT NOT NULL DEFAULT 0, `form` TINYINT, `target` VARCHAR(63), PRIMARY KEY (`id`)) %s;",
|
||||
gS_SQLPrefix, sOptionalINNODB);
|
||||
hTrans.AddQuery2(sQuery);
|
||||
|
||||
@ -305,6 +307,8 @@ void ApplyMigration(int migration)
|
||||
case Migration_Lowercase_startpositions: ApplyMigration_LowercaseMaps("startpositions", migration);
|
||||
case Migration_AddPlayertimesPointsCalcedFrom: ApplyMigration_AddPlayertimesPointsCalcedFrom();
|
||||
case Migration_RemovePlayertimesPointsCalcedFrom: ApplyMigration_RemovePlayertimesPointsCalcedFrom();
|
||||
case Migration_NormalizeMapzonePoints: ApplyMigration_NormalizeMapzonePoints();
|
||||
case Migration_AddMapzonesFormAndTarget: ApplyMigration_AddMapzonesFormAndTarget();
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,9 +370,13 @@ void ApplyMigration_FixOldCompletionCounts()
|
||||
|
||||
void ApplyMigration_AddPrebuiltToMapZonesTable()
|
||||
{
|
||||
#if 0
|
||||
char sQuery[192];
|
||||
FormatEx(sQuery, 192, "ALTER TABLE `%smapzones` ADD COLUMN `prebuilt` BOOL;", gS_SQLPrefix);
|
||||
gH_SQL.Query2(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddPrebuiltToMapZonesTable, DBPrio_High);
|
||||
#else
|
||||
SQL_TableMigrationSingleQuery_Callback(null, null, "", Migration_AddPrebuiltToMapZonesTable);
|
||||
#endif
|
||||
}
|
||||
|
||||
// double up on this migration because some people may have used shavit-playtime which uses INT but I want FLOAT
|
||||
@ -411,6 +419,38 @@ void ApplyMigration_RemovePlayertimesPointsCalcedFrom()
|
||||
gH_SQL.Query2(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_RemovePlayertimesPointsCalcedFrom, DBPrio_High);
|
||||
}
|
||||
|
||||
void ApplyMigration_NormalizeMapzonePoints() // TODO: test with sqlite lol
|
||||
{
|
||||
char sQuery[666], greatest[16], least[16], id[16];
|
||||
greatest = gB_MySQL ? "GREATEST" : "MAX";
|
||||
least = gB_MySQL ? "LEAST" : "MIN";
|
||||
id = gB_MySQL ? "id" : "rowid";
|
||||
|
||||
FormatEx(sQuery, sizeof(sQuery),
|
||||
"UPDATE `%smapzones` A, `%smapzones` B SET \
|
||||
A.corner1_x=%s(B.corner1_x, B.corner2_x), \
|
||||
A.corner1_y=%s(B.corner1_y, B.corner2_y), \
|
||||
A.corner1_z=%s(B.corner1_z, B.corner2_z), \
|
||||
A.corner2_x=%s(B.corner1_x, B.corner2_x), \
|
||||
A.corner2_y=%s(B.corner1_y, B.corner2_y), \
|
||||
A.corner2_z=%s(B.corner1_z, B.corner2_z) \
|
||||
WHERE A.%s = B.%s;",
|
||||
gS_SQLPrefix, gS_SQLPrefix,
|
||||
least, least, least,
|
||||
greatest, greatest, greatest,
|
||||
id, id
|
||||
);
|
||||
|
||||
gH_SQL.Query2(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_NormalizeMapzonePoints, DBPrio_High);
|
||||
}
|
||||
|
||||
void ApplyMigration_AddMapzonesFormAndTarget()
|
||||
{
|
||||
char sQuery[192];
|
||||
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE `%smapzones` ADD COLUMN `form` TINYINT, ADD COLUMN `target` VARCHAR(63);", gS_SQLPrefix);
|
||||
gH_SQL.Query2(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddMapzonesFormAndTarget, DBPrio_High);
|
||||
}
|
||||
|
||||
public void SQL_TableMigrationSingleQuery_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||
{
|
||||
InsertMigration(data);
|
||||
|
||||
@ -24,8 +24,8 @@
|
||||
#endif
|
||||
#define _shavit_zones_included
|
||||
|
||||
#define MAX_ZONES 64
|
||||
#define MAX_STAGES 51 // 😐 kind of arbitrary but also some space between this and MAX_ZONES
|
||||
#define MAX_ZONES 128
|
||||
#define MAX_STAGES 69
|
||||
|
||||
enum
|
||||
{
|
||||
@ -37,7 +37,7 @@ enum
|
||||
Zone_Freestyle, // ignores style physics when at this zone. e.g. WASD when SWing
|
||||
Zone_CustomSpeedLimit, // overwrites velocity limit in the zone
|
||||
Zone_Teleport, // teleports to a defined point
|
||||
Zone_CustomSpawn, // << unused
|
||||
Zone_CustomSpawn, // spawn position for a track. not a physical zone.
|
||||
Zone_Easybhop, // forces easybhop whether if the player is in non-easy styles or if the server has different settings
|
||||
Zone_Slide, // allows players to slide, in order to fix parts like the 5th stage of bhop_arcane
|
||||
Zone_Airaccelerate, // custom sv_airaccelerate inside this,
|
||||
@ -51,7 +51,8 @@ enum
|
||||
enum
|
||||
{
|
||||
ZF_ForceRender = (1 << 0),
|
||||
ZF_Prebuilt = (1 << 1), // comes from mod_zone_* entities
|
||||
ZF_Hammerid = (1 << 1), // used by ZoneForm_{trigger_{multiple, teleport}, func_button} sometimes
|
||||
ZF_Solid = (1 << 2), // forces the zone to block people...
|
||||
};
|
||||
|
||||
// Zone Display type
|
||||
@ -90,33 +91,30 @@ enum
|
||||
ZoneWidth_Size
|
||||
};
|
||||
|
||||
#if 0
|
||||
enum
|
||||
{
|
||||
ZoneForm_Box,
|
||||
ZoneForm_trigger_multiple,
|
||||
ZoneForm_trigger_teleport,
|
||||
ZoneForm_func_button,
|
||||
ZoneForm_AreasAndClusters,
|
||||
};
|
||||
|
||||
enum struct zone_cache_t
|
||||
{
|
||||
bool bZoneInitialized;
|
||||
int iType;
|
||||
int iType; // The type of zone. Zone_Start, Zone_End, etc...
|
||||
int iTrack; // 0 - main, 1 - bonus1 etc
|
||||
int iEntity;
|
||||
int iDatabaseID; // when ZF_Prebuilt, this is the entity's m_iHammerID
|
||||
int iFlags;
|
||||
int iData;
|
||||
float fCorner1[3];
|
||||
float fCorner2[3];
|
||||
float fDestination[3];
|
||||
int iEntity; // Filled by Shavit_GetZone() if applicable.
|
||||
int iDatabaseID; // Can be the database ID (> 0) for "sql" sources. Non-sql sources can fill this with whatever.
|
||||
int iFlags; // The ZF_* flags.
|
||||
int iData; // Depends on the zone. Zone_Stage stores the stage number in this for example.
|
||||
float fCorner1[3]; // the hull mins. (or unused if ZoneForm_AreasAndClusters) // TODO, maybe reuse for cluster & areas?
|
||||
float fCorner2[3]; // the hull maxs. (or unused if ZoneForm_AreasAndClusters)
|
||||
float fDestination[3]; // Used by Zone_CustomSpawn, Zone_Teleport, and Zone_Stage.
|
||||
int iForm; // ZoneForm_*
|
||||
char sSource[16]; // "sql", "autobutton", "autozone", "sourcejump", "http", etc...
|
||||
char sTarget[64]; // either the hammerid or the targetname
|
||||
}
|
||||
#else
|
||||
enum struct zone_cache_t
|
||||
{
|
||||
bool bZoneInitialized;
|
||||
bool bPrebuilt; // comes from mod_zone_* entities
|
||||
int iZoneType;
|
||||
int iZoneTrack; // 0 - main, 1 - bonus etc
|
||||
int iEntityID;
|
||||
int iDatabaseID;
|
||||
int iZoneFlags;
|
||||
int iZoneData;
|
||||
}
|
||||
#endif
|
||||
|
||||
stock void GetZoneName(int client, int zoneType, char[] output, int size)
|
||||
{
|
||||
@ -136,15 +134,114 @@ stock void GetZoneName(int client, int zoneType, char[] output, int size)
|
||||
"Zone_Stage",
|
||||
"Zone_NoTimerGravity",
|
||||
"Zone_Gravity",
|
||||
"Zone_Speedmod"
|
||||
"Zone_Speedmod",
|
||||
};
|
||||
|
||||
if (zoneType >= ZONETYPES_SIZE)
|
||||
if (zoneType < 0 || zoneType >= ZONETYPES_SIZE)
|
||||
FormatEx(output, size, "%T", "Zone_Unknown", client);
|
||||
else
|
||||
FormatEx(output, size, "%T", sTranslationStrings[zoneType], client);
|
||||
}
|
||||
|
||||
// Please follow something like this:
|
||||
// mod_zone_start
|
||||
// mod_zone_end
|
||||
// mod_zone_checkpoint_X
|
||||
// mod_zone_bonus_X_start
|
||||
// mod_zone_bonus_X_end
|
||||
// mod_zone_bonus_X_checkpoint_X
|
||||
//
|
||||
// climb_startbutton
|
||||
// climb_endbutton
|
||||
// climb_bonusX_startbutton
|
||||
// climb_bonusX_endbutton
|
||||
//
|
||||
// climb_startzone
|
||||
// climb_endzone
|
||||
// climb_bonusX_startzone
|
||||
// climb_bonusX_endzone
|
||||
stock bool Shavit_ParseZoneTargetname(const char[] targetname, bool button, int& type, int& track, int& stage, const char[] mapname_for_log="")
|
||||
{
|
||||
track = Track_Main;
|
||||
type = -1;
|
||||
stage = 0;
|
||||
|
||||
if (strncmp(targetname, "climb_", 6) != 0
|
||||
&& (button || strncmp(targetname, "mod_zone_", 9) != 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrContains(targetname, "start") != -1)
|
||||
{
|
||||
type = Zone_Start;
|
||||
}
|
||||
else if (StrContains(targetname, "end") != -1)
|
||||
{
|
||||
type = Zone_End;
|
||||
}
|
||||
|
||||
int bonus = StrContains(targetname, "bonus");
|
||||
|
||||
if (bonus != -1)
|
||||
{
|
||||
track = Track_Bonus;
|
||||
bonus += 5; // skip past "bonus"
|
||||
if (targetname[bonus] == '_') bonus += 1;
|
||||
|
||||
if ('1' <= targetname[bonus] <= '9')
|
||||
{
|
||||
track = StringToInt(targetname[bonus]);
|
||||
|
||||
if (track < Track_Bonus || track > Track_Bonus_Last)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid track in prebuilt map zone (%s) on %s", targetname, mapname_for_log);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int checkpoint = StrContains(targetname, "checkpoint");
|
||||
|
||||
if (checkpoint != -1)
|
||||
{
|
||||
if (button)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid button (%s) (has checkpoint) on %s", targetname, mapname_for_log);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type != -1)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid type (start/end + checkpoint) in prebuilt map zone (%s) on %s", targetname, mapname_for_log);
|
||||
return false; // end/start & checkpoint...
|
||||
}
|
||||
|
||||
type = Zone_Stage;
|
||||
checkpoint += 10; // skip past "checkpoint"
|
||||
if (targetname[checkpoint] == '_') checkpoint += 1;
|
||||
|
||||
if ('1' <= targetname[checkpoint] <= '9')
|
||||
{
|
||||
stage = StringToInt(targetname[checkpoint]);
|
||||
|
||||
if (stage <= 0 || stage > MAX_STAGES)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid stage number in prebuilt map zone (%s) on %s", targetname, mapname_for_log);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == -1)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid zone type in prebuilt map zone (%s) on %s", targetname, mapname_for_log);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player enters a zone.
|
||||
*
|
||||
@ -171,6 +268,11 @@ forward void Shavit_OnEnterZone(int client, int type, int track, int id, int ent
|
||||
*/
|
||||
forward void Shavit_OnLeaveZone(int client, int type, int track, int id, int entity, int data);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
forward void Shavit_LoadZonesHere();
|
||||
|
||||
/**
|
||||
* Called when a player leaves a zone.
|
||||
*
|
||||
@ -182,16 +284,6 @@ forward void Shavit_OnLeaveZone(int client, int type, int track, int id, int ent
|
||||
*/
|
||||
forward Action Shavit_OnStageMessage(int client, int stageNumber, char[] message, int maxlen);
|
||||
|
||||
/**
|
||||
* Retrieve the zone ID for a given stage number.
|
||||
* Will return exception if stagenumber doesn't have a zone.
|
||||
*
|
||||
* @param stage Stage number.
|
||||
* @param track Track number.
|
||||
* @return Zone ID of stage.
|
||||
*/
|
||||
native int Shavit_GetStageZone(int stage, int track=Track_Main);
|
||||
|
||||
/**
|
||||
* Checks if a mapzone exists.
|
||||
*
|
||||
@ -314,15 +406,56 @@ native void Shavit_SetStart(int client, int track, bool anglesonly);
|
||||
*/
|
||||
native void Shavit_DeleteSetStart(int client, int track);
|
||||
|
||||
#if 0
|
||||
native void Shavit_RemoveAllZones();
|
||||
/**
|
||||
* Removes all zones from memory and then reloads zones from the database & any plugins.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_ReloadZones();
|
||||
|
||||
/**
|
||||
* Removes all zones from memory and unhooks any zones and kills any created entities.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_UnloadZones();
|
||||
|
||||
/**
|
||||
* Returns the number of zones that are currently loaded in memory.
|
||||
*
|
||||
* @return The number of zones currently loaded in memory.
|
||||
*/
|
||||
native int Shavit_GetZoneCount();
|
||||
|
||||
/**
|
||||
* Retrieves the zone_cache_t for a zone.
|
||||
*
|
||||
* @param index The zone index. 0 through Shavit_GetZoneCount()-1.
|
||||
* @param zonecache The zone_cache_t struct that is retrieved from the zone.
|
||||
* @param size sizeof(zone_cache_t) to make sure the caller has a matching struct version.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_GetZone(int index, any[] zonecache, int size = sizeof(zone_cache_t));
|
||||
|
||||
/**
|
||||
* Adds a zone to memory. (Does NOT insert into DB).
|
||||
*
|
||||
* @param zonecache The zone_cache_t struct that is used to create or hook a zone.
|
||||
* @param size sizeof(zone_cache_t) to make sure the caller has a matching struct version.
|
||||
*
|
||||
* @return The zone index on success (index for a particular zone can change). <0 on failure.
|
||||
*/
|
||||
native int Shavit_AddZone(any[] zonecache, int size = sizeof(zone_cache_t));
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Removes a zone from memory. (Does NOT delete from DB).
|
||||
* WARNING: If there are zones after `index`, then they will be moved down in memory to fill this slot after removal.
|
||||
* This unhooks the zone's entity too.
|
||||
*
|
||||
* @param index The zone's index.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_RemoveZone(int index);
|
||||
|
||||
public SharedPlugin __pl_shavit_zones =
|
||||
{
|
||||
@ -340,7 +473,6 @@ public void __pl_shavit_zones_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_GetZoneData");
|
||||
MarkNativeAsOptional("Shavit_GetZoneFlags");
|
||||
MarkNativeAsOptional("Shavit_GetStageZone");
|
||||
MarkNativeAsOptional("Shavit_GetStageCount");
|
||||
MarkNativeAsOptional("Shavit_InsideZone");
|
||||
MarkNativeAsOptional("Shavit_InsideZoneGetID");
|
||||
@ -353,5 +485,11 @@ public void __pl_shavit_zones_SetNTVOptional()
|
||||
MarkNativeAsOptional("Shavit_GetZoneTrack");
|
||||
MarkNativeAsOptional("Shavit_GetZoneType");
|
||||
MarkNativeAsOptional("Shavit_GetZoneID");
|
||||
MarkNativeAsOptional("Shavit_ReloadZones");
|
||||
MarkNativeAsOptional("Shavit_UnloadZones");
|
||||
MarkNativeAsOptional("Shavit_GetZoneCount");
|
||||
MarkNativeAsOptional("Shavit_GetZone");
|
||||
MarkNativeAsOptional("Shavit_AddZone");
|
||||
MarkNativeAsOptional("Shavit_RemoveZone");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -466,7 +466,7 @@ void LoadMapFixes()
|
||||
kv.GetSectionName(key, sizeof(key));
|
||||
kv.GetString(NULL_STRING, value, sizeof(value));
|
||||
|
||||
PrintToServer(">>>> mapfixes: %s \"%s\"", key, value);
|
||||
PrintToServer(">>>> shavit-misc/mapfixes: %s \"%s\"", key, value);
|
||||
|
||||
ConVar cvar = FindConVar(key);
|
||||
|
||||
|
||||
323
addons/sourcemod/scripting/shavit-zones-http.sp
Normal file
323
addons/sourcemod/scripting/shavit-zones-http.sp
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* shavit's Timer - HTTP API module for shavit-zones
|
||||
* by: rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sourcemod>
|
||||
#include <convar_class>
|
||||
|
||||
#include <shavit/core>
|
||||
#include <shavit/zones>
|
||||
|
||||
#define USE_RIPEXT 1
|
||||
#if USE_RIPEXT
|
||||
#include <ripext> // https://github.com/ErikMinekus/sm-ripext
|
||||
#else
|
||||
#include <json> // https://github.com/clugg/sm-json
|
||||
#include <SteamWorks> // HTTP stuff
|
||||
#endif
|
||||
|
||||
#undef REQUIRE_PLUGIN
|
||||
|
||||
|
||||
// todo: defines for JSON_Array & JSONArray?
|
||||
// todo: or even compile this including both and have cvar determine whether ripext or not is used?
|
||||
|
||||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
|
||||
|
||||
static char gS_ZoneTypes[ZONETYPES_SIZE][18] = {
|
||||
"start",
|
||||
"end",
|
||||
"respawn",
|
||||
"stop",
|
||||
"slay",
|
||||
"freestyle",
|
||||
"customspeedlimit",
|
||||
"teleport",
|
||||
"customspawn",
|
||||
"easybhop",
|
||||
"slide",
|
||||
"airaccel",
|
||||
"stage",
|
||||
"notimergravity",
|
||||
"gravity",
|
||||
"speedmod",
|
||||
};
|
||||
|
||||
|
||||
bool gB_YouCanLoadZonesNow = false;
|
||||
char gS_Map[PLATFORM_MAX_PATH];
|
||||
char gS_ZonesForMap[PLATFORM_MAX_PATH];
|
||||
ArrayList gA_Zones = null;
|
||||
|
||||
Convar gCV_Enable = null;
|
||||
Convar gCV_ApiUrl = null;
|
||||
Convar gCV_ApiKey = null;
|
||||
Convar gCV_Source = null;
|
||||
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "[shavit] Map Zones (HTTP API)",
|
||||
author = "rtldg, KiD Fearless",
|
||||
description = "Retrieves map zones for bhoptimer from an HTTP API.",
|
||||
version = SHAVIT_VERSION,
|
||||
url = "https://github.com/shavitush/bhoptimer"
|
||||
}
|
||||
|
||||
|
||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
||||
{
|
||||
RegPluginLibrary("shavit-zones-http");
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
gA_Zones = new ArrayList(sizeof(zone_cache_t));
|
||||
|
||||
gCV_Enable = new Convar("shavit_zones_http_enable", "1", "Whether to enable this or not...", 0, true, 0.0, true, 1.0);
|
||||
gCV_ApiUrl = new Convar("shavit_zones_http_url", "", "API URL. Will replace `{map}` and `{key}` with the mapname and api key.\nExample sourcejump url:\n https://sourcejump.net/api/v2/maps/{map}/zones", FCVAR_PROTECTED);
|
||||
gCV_ApiKey = new Convar("shavit_zones_http_key", "", "API key that some APIs might require.", FCVAR_PROTECTED);
|
||||
gCV_Source = new Convar("shavit_zones_http_src", "http", "A string used by plugins to identify where a zone came from (http, sourcejump, sql, etc)");
|
||||
|
||||
Convar.AutoExecConfig();
|
||||
}
|
||||
|
||||
public void OnMapEnd()
|
||||
{
|
||||
gB_YouCanLoadZonesNow = false;
|
||||
}
|
||||
|
||||
public void OnConfigsExecuted()
|
||||
{
|
||||
GetLowercaseMapName(gS_Map);
|
||||
|
||||
if (!StrEqual(gS_Map, gS_ZonesForMap))
|
||||
{
|
||||
RetrieveZones(gS_Map);
|
||||
}
|
||||
}
|
||||
|
||||
public void Shavit_LoadZonesHere()
|
||||
{
|
||||
gB_YouCanLoadZonesNow = true;
|
||||
|
||||
if (StrEqual(gS_Map, gS_ZonesForMap))
|
||||
{
|
||||
LoadCachedZones();
|
||||
}
|
||||
}
|
||||
|
||||
void LoadCachedZones()
|
||||
{
|
||||
if (!gCV_Enable.BoolValue)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < gA_Zones.Length; i++)
|
||||
{
|
||||
zone_cache_t cache;
|
||||
gA_Zones.GetArray(i, cache);
|
||||
Shavit_AddZone(cache);
|
||||
}
|
||||
}
|
||||
|
||||
void RetrieveZones(const char[] mapname)
|
||||
{
|
||||
if (!gCV_Enable.BoolValue)
|
||||
return;
|
||||
|
||||
char apikey[64], apiurl[333];
|
||||
gCV_ApiKey.GetString(apikey, sizeof(apikey));
|
||||
gCV_ApiUrl.GetString(apiurl, sizeof(apiurl));
|
||||
|
||||
if (!apiurl[0])
|
||||
{
|
||||
LogError("Missing API URL");
|
||||
return;
|
||||
}
|
||||
|
||||
ReplaceString(apiurl, sizeof(apiurl), "{map}", mapname);
|
||||
ReplaceString(apiurl, sizeof(apiurl), "{key}", apikey);
|
||||
|
||||
DataPack pack = new DataPack();
|
||||
pack.WriteString(mapname);
|
||||
|
||||
#if USE_RIPEXT
|
||||
HTTPRequest http = new HTTPRequest(apiurl);
|
||||
if (apikey[0])
|
||||
http.SetHeader("api-key", "%s", apikey);
|
||||
http.SetHeader("map", "%s", mapname);
|
||||
http.Get(RequestCallback_Ripext, pack);
|
||||
#else
|
||||
Handle request;
|
||||
if (!(request = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, apiurl))
|
||||
|| (apikey[0] && !SteamWorks_SetHTTPRequestHeaderValue(request, "api-key", apikey))
|
||||
|| !SteamWorks_SetHTTPRequestHeaderValue(request, "accept", "application/json")
|
||||
|| !SteamWorks_SetHTTPRequestContextValue(request, pack)
|
||||
|| !SteamWorks_SetHTTPRequestAbsoluteTimeoutMS(request, 4000)
|
||||
//|| !SteamWorks_SetHTTPRequestRequiresVerifiedCertificate(request, true)
|
||||
|| !SteamWorks_SetHTTPCallbacks(request, RequestCompletedCallback_Steamworks)
|
||||
|| !SteamWorks_SendHTTPRequest(request)
|
||||
)
|
||||
{
|
||||
CloseHandle(request);
|
||||
LogError("failed to setup & send HTTP request");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_RIPEXT
|
||||
void RequestCallback_Ripext(HTTPResponse response, DataPack pack, const char[] error)
|
||||
{
|
||||
if (response.Status != HTTPStatus_OK || response.Data == null)
|
||||
{
|
||||
LogError("HTTP API request failed");
|
||||
delete pack;
|
||||
return;
|
||||
}
|
||||
|
||||
handlestuff(pack, view_as<JSONArray>(response.Data));
|
||||
}
|
||||
#else
|
||||
public void RequestCompletedCallback_Steamworks(Handle request, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, DataPack pack)
|
||||
{
|
||||
if (bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK)
|
||||
{
|
||||
pack.Reset();
|
||||
char mapname[PLATFORM_MAX_PATH];
|
||||
pack.ReadString(mapname, sizeof(mapname));
|
||||
delete pack;
|
||||
LogError("HTTP API failed for '%s'. statuscode=%d", mapname, eStatusCode);
|
||||
return;
|
||||
}
|
||||
|
||||
SteamWorks_GetHTTPResponseBodyCallback(request, RequestCallback_Steamworks, pack);
|
||||
}
|
||||
|
||||
void RequestCallback_Steamworks(const char[] data, DataPack pack, int datalen)
|
||||
{
|
||||
JSON_Array records = view_as<JSON_Array>(json_decode(data));
|
||||
|
||||
if (records)
|
||||
{
|
||||
handlestuff(pack, records);
|
||||
json_cleanup(records);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_RIPEXT
|
||||
void ReadVec(const char[] key, JSONObject json, float vec[3])
|
||||
#else
|
||||
void ReadVec(const char[] key, JSON_Object json, float vec[3])
|
||||
#endif
|
||||
{
|
||||
if (json.HasKey(key))
|
||||
{
|
||||
#if USE_RIPEXT
|
||||
JSONArray arr = view_as<JSONArray>(json.Get(key));
|
||||
#else
|
||||
JSON_Array arr = view_as<JSON_Array>(json.GetObject(key));
|
||||
#endif
|
||||
vec[0] = arr.GetFloat(0);
|
||||
vec[1] = arr.GetFloat(1);
|
||||
vec[2] = arr.GetFloat(2);
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_RIPEXT
|
||||
void handlestuff(DataPack pack, JSONArray records)
|
||||
#else
|
||||
void handlestuff(DataPack pack, JSON_Array records)
|
||||
#endif
|
||||
{
|
||||
pack.Reset();
|
||||
char mapname[PLATFORM_MAX_PATH];
|
||||
pack.ReadString(mapname, sizeof(mapname));
|
||||
delete pack;
|
||||
|
||||
if (!StrEqual(mapname, gS_Map))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char source[16];
|
||||
gCV_Source.GetString(source, sizeof(source));
|
||||
if (!source[0]) source = "http";
|
||||
|
||||
gS_ZonesForMap = mapname;
|
||||
|
||||
gA_Zones.Clear();
|
||||
|
||||
for (int RN = 0; RN < records.Length; RN++)
|
||||
{
|
||||
#if USE_RIPEXT
|
||||
JSONObject json = view_as<JSONObject>(records.Get(RN));
|
||||
#else
|
||||
JSON_Object json = records.GetObject(RN);
|
||||
#endif
|
||||
|
||||
char buf[32];
|
||||
zone_cache_t cache;
|
||||
|
||||
json.GetString("type", buf, sizeof(buf));
|
||||
cache.iType = -1;
|
||||
|
||||
for (int i = 0; i < ZONETYPES_SIZE; i++)
|
||||
{
|
||||
if (StrEqual(buf, gS_ZoneTypes[i]))
|
||||
{
|
||||
cache.iType = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.iType == -1)
|
||||
{
|
||||
//PrintToServer("");
|
||||
continue;
|
||||
}
|
||||
|
||||
cache.iTrack = json.GetInt("track");
|
||||
//cache.iEntity
|
||||
cache.iDatabaseID = json.GetInt("id");
|
||||
if (json.HasKey("flags")) cache.iFlags = json.GetInt("flags");
|
||||
if (json.HasKey("data")) cache.iData = json.GetInt("data");
|
||||
|
||||
if (cache.iType == Zone_Stage)
|
||||
if (json.HasKey("index")) cache.iData = json.GetInt("index");
|
||||
|
||||
ReadVec("point_a", json, cache.fCorner1);
|
||||
ReadVec("point_b", json, cache.fCorner2);
|
||||
ReadVec("dest", json, cache.fDestination);
|
||||
|
||||
if (json.HasKey("form")) cache.iForm = json.GetInt("form");
|
||||
json.GetString("target", cache.sTarget, sizeof(cache.sTarget));
|
||||
//json.GetString("source", cache.sSource, sizeof(cache.sSource));
|
||||
cache.sSource = source;
|
||||
|
||||
gA_Zones.PushArray(cache);
|
||||
}
|
||||
|
||||
if (gB_YouCanLoadZonesNow)
|
||||
LoadCachedZones();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -24,16 +24,38 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You have to be {1}alive{2} to set your start position."
|
||||
}
|
||||
"SetStartNotInStartZone"
|
||||
{
|
||||
"#format" "{1:s},{2:s},{3:s},{4:s}"
|
||||
"en" "You {1}must{2} be in the {3}start zone{4} to use set start."
|
||||
}
|
||||
"DeleteSetStart"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Start position has been {1}deleted{2}."
|
||||
}
|
||||
// ---------- ZoneHook ---------- //
|
||||
"ZoneHook_Crosshair"
|
||||
{
|
||||
"en" "Entity under crosshair"
|
||||
}
|
||||
"ZoneHook_Tpto"
|
||||
{
|
||||
"en" "Teleport to (stops timer)"
|
||||
}
|
||||
"ZoneHook_Draw"
|
||||
{
|
||||
"en" "Draw beams around entity"
|
||||
}
|
||||
"ZoneHook_Zonetype"
|
||||
{
|
||||
"#format" "{1:s}"
|
||||
"en" "Zone type: {1}"
|
||||
}
|
||||
"ZoneHook_Hooktype"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Hook type: {1} ({2})"
|
||||
}
|
||||
"ZoneHook_Confirm"
|
||||
{
|
||||
"en" "Go to confirm"
|
||||
}
|
||||
// ---------- Commands ---------- //
|
||||
"StageCommandAlive"
|
||||
{
|
||||
@ -57,6 +79,11 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You {1}cannot{2} setup mapzones when you're dead."
|
||||
}
|
||||
"ZonesNotSQL"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You {1}cannot{2} add/edit/delete non-sql zones."
|
||||
}
|
||||
"ZoneCustomSpawnMenuTitle"
|
||||
{
|
||||
"en" "Add custom spawn for track:"
|
||||
@ -291,6 +318,15 @@
|
||||
{
|
||||
"en" "Edit a map zone"
|
||||
}
|
||||
"HookZone"
|
||||
{
|
||||
"en" "Hook a trigger, teleporter, or button."
|
||||
}
|
||||
"HookZone2"
|
||||
{
|
||||
"#format" "{1:s}"
|
||||
"en" "Hook {1}"
|
||||
}
|
||||
"ZoneEditTitle"
|
||||
{
|
||||
"en" "Choose a zone to edit:"
|
||||
@ -414,7 +450,7 @@
|
||||
"ZoneStageEnter"
|
||||
{
|
||||
"#format" "{1:s},{2:s},{3:d},{4:s},{5:s},{6:s}{7:s}"
|
||||
"en" "{1}You have reached stage {2}{3}{4} with a time of {5}{6}{7}."
|
||||
"en" "{1}Stage {2}{3}{4} @ {5}{6}{7}"
|
||||
}
|
||||
"Zone_Start"
|
||||
{
|
||||
@ -484,4 +520,4 @@
|
||||
{
|
||||
"en" "UNKNOWN ZONE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5
addons/stripper/maps/bhop_n0bs1_css.cfg
Normal file
5
addons/stripper/maps/bhop_n0bs1_css.cfg
Normal file
@ -0,0 +1,5 @@
|
||||
;; shit zone
|
||||
filter:
|
||||
{
|
||||
"targetname" "mod_zone_start"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user