C#:
using Oxide.Core;
using static ConsoleSystem;
namespace Oxide.Plugins {
[Info("LimitFPS Hooks Demo", "turner#7777", "1.0.0")]
[Description("Demo on how to use the hooks that LimitFPS provides & use its API")]
public class LimitFPSHooksDemo : RustPlugin {
/// <summary>
/// Called when a player gets crashed (the command is called, not if their game is closed)
/// </summary>
/// <param name="command_initiatior">the player who ran the command or null if it was run from the server console</param>
/// <param name="target">The player that is being crashed</param>
/// <returns>Return non-null to cancel the crash (NOTE: The initator will still see a message that says it will crash the user, even if you prevent it from this hook, this is true for all hooks)</returns>
object OnPlayerCrashed(BasePlayer command_initiatior, BasePlayer target) {
string initiator;
if (command_initiatior == null) initiator = "Console";
else initiator = command_initiatior.displayName;
Puts($"{initiator} crashed player {target.displayName}");
return null;
// allow the crash
}
/// <summary>
/// Called when a player is being FPS queried (this does not give the FPS & Performance data, this is just the initial request). NOTE: This might get called and never get a OnFPSQueryFinished or OnFPSQueryTimeout hook call because of network latency and the client will send only 1 request at a time, so you should implement a timeout
/// </summary>
/// <param name="command_initiatior">the player who ran the command or null if it was run from the server console</param>
/// <param name="target">The player that is queried for their FPS</param>
/// <param name="request_id">The request ID of the query, use it to cross-check/sync your requests across multiple hook calls</param>
/// <returns>Return non-null to cancel the query</returns>
object OnFPSQueryStart(BasePlayer command_initiatior, BasePlayer target, int request_id) {
string initiator;
if (command_initiatior == null) initiator = "Console";
else initiator = command_initiatior.displayName;
Puts($"{initiator} performance queried player {target.displayName} with request id: {request_id}");
return null;
// allow the query
}
/// <summary>
/// Called when a performance query has timed out (the client did not respond within 10 seconds)
/// </summary>
/// <param name="command_initiatior">the player who ran the command or null if it was run from the server console</param>
/// <param name="target">The player that is queried for their FPS</param>
/// <param name="request_id">The request ID of the query, use it to cross-check/sync your requests across multiple hook calls</param>
void OnFPSQueryTimeout(BasePlayer command_initiatior, BasePlayer target, int request_id) {
string initiator;
if (command_initiatior == null) initiator = "Console";
else initiator = command_initiatior.displayName;
Puts($"The performance query that {initiator} did on {target.displayName} timed out! The request id was: {request_id}");
}
/// <summary>
/// Called when a performance query succeeded and the client returned a performance report
/// </summary>
/// <param name="command_initiatior">the player who ran the command or null if it was run from the server console</param>
/// <param name="target">The player that is queried for their FPS</param>
/// <param name="report">The performance report, it contains the FPS, Memory usage & other useful stuff</param>
void OnFPSQueryFinished(BasePlayer command_initiatior, BasePlayer target, ClientPerformanceReport report) {
string initiator;
if (command_initiatior == null) initiator = "Console";
else initiator = command_initiatior.displayName;
Puts($"The performance query that {initiator} did on {target.displayName} was successful! The request id was: {report.request_id}. Their FPS: {report.fps}");
}
/// <summary>
/// Called when a player is being FPS limited (when the command was sent, they are still with normal FPS)
/// </summary>
/// <param name="command_initiatior">the player who ran the command or null if it was run from the server console</param>
/// <param name="target">The player that is being FPS limited</param>
/// <param name="targetFps">The FPS that the player will be set at. The player's FPS can be lower & an attempt to increase it might be made to match it with the targetFps</param>
/// <returns></returns>
object OnLimitFPSStart(BasePlayer command_initiatior, BasePlayer target, float targetFps) {
string initiator;
if (command_initiatior == null) initiator = "Console";
else initiator = command_initiatior.displayName;
if (targetFps == 0f) {
Puts($"{initiator} removed the limiiter of {target.displayName}");
}
else {
Puts($"{initiator} initiated an FPS limit of player {target.displayName} with target FPS of: {targetFps}");
}
return null;
// allow the limitting
}
/// <summary>
/// Called every X seconds (config based number) and it will query the player's FPS and do some math to make it closer to the target
/// </summary>
/// <param name="command_initiatior">the player who ran the command or null if it was run from the server console</param>
/// <param name="target">The player that is being FPS limited</param>
/// <param name="targetFps">The FPS that the player will be set at. The player's FPS can be lower & an attempt to increase it might be made to match it with the targetFps</param>
/// <param name="report">The performance report for the current tick, it contains the FPS, Memory usage & other useful stuff</param>
/// <returns>Return non-null to cancel the current tick (NOTE: This will not cancel the fps limiter, only suppress the current tick, if you want to cancel it either suppress it every tick or call the API for canceling)</returns>
object OnLimitFPSTick(BasePlayer command_initiatior, BasePlayer target, float targetFps, ClientPerformanceReport report) {
string initiator;
if (command_initiatior == null) initiator = "Console";
else initiator = command_initiatior.displayName;
Puts($"The limiter by {initiator} for {target.displayName} with target FPS of {targetFps} just ticked! Their current fps is {report.fps}");
return null;
// allow the tick
}
[ChatCommand("test_crash")]
void cmd1(BasePlayer player, string command, string[] args) {
ulong target_to_crash = ulong.Parse(args[0]);
// the steamid of the player
string response = (string)Interface.Oxide.CallHook("API_CrashCommand", target_to_crash);
// the returned value is the string that a player/console running the command will get
player.ChatMessage(response);
}
[ChatCommand("test_playerfps")]
void cmd2(BasePlayer player, string command, string[] args) {
ulong target_to_query = ulong.Parse(args[0]);
// the steamid of the player
/* IMPORTANT:
Because when you query performance data its done over the network
the api will return a request id as a string
you should parse it as int and check for the response in
OnFPSQueryFinished and OnFPSQueryTimeout hooks and match against this request id
*/
string response = (string)Interface.Oxide.CallHook("API_PlayerFPSCommand", target_to_query);
// the returned value is the string that a player/console running the command will get
player.ChatMessage(response);
}
[ChatCommand("test_limitfps")]
void cmd3(BasePlayer player, string command, string[] args) {
ulong target_to_query = ulong.Parse(args[0]);
// the steamid of the player
float target_fps = ulong.Parse(args[1]);
// the limiter will try to stay near this number for their FPS. Set to 0 to remove the FPS limit
// NOTE: to disable the limit (make their FPS be normal again) set the target fps to 0
string response = (string)Interface.Oxide.CallHook("API_LimitFPSCommand", target_to_query, target_fps);
// the returned value is the string that a player/console running the command will get
player.ChatMessage(response);
}
}
}