Maybe I can ask about the principle of SourcePawn for native function implementation ?
No community like AlliedModders for a coder who likes squirrels is very unfortunately.
I really enjoy using squirrel write the script of L4D2, I also use sourcepawn write plugins , although squirrel not as good as sourcepawn in many places, but this does not mean that squirrel is not good, just sometimes not so strong like sourcepawn.
But now I have an urgent problem to solve:
In L4D2's "include" folder, I find a file named "halflife.inc" and there are some print functions in this file such as:
Code:
/**
* Prints a message to a specific client in the center of the screen.
*
* @param client Client index.
* @param format Formatting rules.
* @param ... Variable number of format parameters.
* @error If the client is not connected an error will be thrown.
*/
native void PrintCenterText(int client, const char[] format, any ...);
/**
* Prints a message to a specific client with a hint box.
*
* @param client Client index.
* @param format Formatting rules.
* @param ... Variable number of format parameters.
* @error If the client is not connected an error will be thrown.
*/
native void PrintHintText(int client, const char[] format, any ...);
It adds a native tag in front of the return value type but I'm not really sure I understand the meaning of the tag, so I want to ask what the tag's effect.
And, I also want to know the underlying implementation principle of this function.
I browsed https://wiki.alliedmods.net/Creating_Natives_(SourceMod_Scripting).
But, I don't think I really understand it.
And I searched all the .inc files to find something about regarding implementation of these two functions but nothing I found.
I want to implement them using squirrel, but I don't know how to do it.
Functions are first class values like integer or strings and can be stored in table slots, local variables, arrays and passed as function parameters. Functions can be implemented in Squirrel or in a native language with calling conventions compatible with ANSI C.
Maybe someone can explain the meaning of the above sentence, it is hard for me to understand it.
Although I don't understand this sentence, I think squirrels can also implement native functions, but I can't.
Squirrel can display HUD on the screen, so there must be no problem in displaying the text, but now the problem is that displaying HUD is for all players, and I hope to find a way to display different information for each specific survivor.
If the community doesn't allow discussion about other languages, the administrator can delete this post directly, but I really hope to find a way to make squirrels work like sourcepawn.
I'm glossing over a bit to keep things simple and I'm not too familiar with Squirrel, but I'll try to explain it.
Declaring a SourcePawn function as native means the plugin must use externally-provided code that isn't written in SourcePawn itself; it calls into code provided by SourceMod (which can in turn be engine functions, functions provided by extensions, or functions exposed by other plugins, which is what your link refers to -- it allows plugins to provide functions for other plugins to use).
Both require machine "native" code (in particular C++ for SourcePawn VM, C for the Squirrel VM) to register new functions into their respective virtual machines (SourcePawn and Squirrel, respectively). You can't expose functions written in Squrrel to SourcePawn, or the other way around.
I'm glossing over a bit to keep things simple and I'm not too familiar with Squirrel, but I'll try to explain it.
Declaring a SourcePawn function as native means the plugin must use externally-provided code that isn't written in SourcePawn itself; it calls into code provided by SourceMod (which can in turn be engine functions, functions provided by extensions, or functions exposed by other plugins, which is what your link refers to -- it allows plugins to provide functions for other plugins to use).
Both require machine "native" code (in particular C++ for SourcePawn VM, C for the Squirrel VM) to register new functions into their respective virtual machines (SourcePawn and Squirrel, respectively). You can't expose functions written in Squrrel to SourcePawn, or the other way around.
Thank you very much for your reply.
Maybe I haven't fully understood squirrels. Although I have written a lot of scripts and used them to implement many functions of sourcepawn, my usage of squirrels is still superficial.
Maybe my ability is not enough. Although I have read squirrels' documents carefully, I still don't understand a lot. For example, you replied about the usage of squirrels' registration functions.I have seen them many times before, I am still full of doubts.
I don't understand the implementation of the PrintCenterText on GitHud you replied to. Sorry about that.
What I want to do is "just" complete these functions through scripts. If you want to get the return value through scripts and then use the plugin output, why not using the plugin directly to complete it. Nevertheless, thank you for your help.
Declaring a SourcePawn function as native means the plugin must use externally-provided code that isn't written in SourcePawn itself;
So would this be incorrect usage of the "native" keyword?
This example is from a plugin & include file, but there's no compiled c++ code
l4d2stats.inc
Spoiler
PHP Code:
#if defined __l4d2_stat_tracker_inc__
#endinput
#endif
#define __l4d2_stat_tracker_inc__
enum
{
STAT_CLIENT = 0, // Client ID that these stats apply to
STAT_SI_TOTAL, // Total SI kills
STAT_SI_RATE, // SI kills per minute for this survivor
STAT_SI_PERCENTAGE, // Percentage of total SI killed
STAT_SI_BOOMER, // Number of boomers killed
STAT_SI_SMOKER, // Number of smokers killed
STAT_SI_HUNTER, // Number of hunters killed
STAT_SI_JOCKEY, // Number of jockies killed
STAT_SI_CHARGER, // Number of chargers killed
STAT_SI_SPITTER, // Number of spitters killed
STAT_COMMON_TOTAL, // Number of common killed
STAT_COMMON_RATE, // Common kills per minute for this survivor
STAT_COMMON_PERCENTAGE, // Percentage of total common killed
STAT_TANK_DAMAGE, // Amount of tank damage done
STAT_TANK_PERCENTAGE, // Percentage of tank damage
STAT_ACC_PERCENTAGE, // Survivors accuracy
STAT_ACC_SHOTS_FIRED, // Total number of shots fired
STAT_ACC_SHOTS_LANDED, // Total number of shots landed
STAT_ACC_HEADSHOT_PERCENTAGE, // Headshot percentage
STAT_ACC_HEADSHOT_COUNTS, // Total headshots landed
STAT_ACC_SI_HEADSHOT_PERCENTAGE, // Percentage of shots that landed on an SI that were headshots
STAT_ACC_SI_HEADSHOT_COUNT, // Total number of headshots on SI
STAT_ACC_SI_SHOTS_LANDED, // Total number of shots landed on SI
STAT_FF_TAKEN, // Friendly fire damage taken
STAT_FF_GIVEN, // Friendly fire damage given
STAT_MAX_STATS
}
enum
{
STAT_TEAM_TOTALSI, // Total number of SI killed
STAT_TEAM_SI_RATE, // Total SI kills per minute
STAT_TEAM_BOOMER, // Number of boomers killed
STAT_TEAM_SMOKER, // Number of smokers killed
STAT_TEAM_HUNTER, // Number of hunters killed
STAT_TEAM_JOCKEY, // Number of jockies killed
STAT_TEAM_CHARGER, // Number of chargers killed
STAT_TEAM_SPITTER, // Number of spitters killed
STAT_TEAM_COMMON, // Number of common killed
STAT_TEAM_COMMON_RATE, // Total number of common killed per minute
STAT_TEAM_TANK, // Number of tanks killed
STAT_TEAM_TANK_RATE, // Total number of tanks killed per minute
STAT_TEAM_TANK_DAMAGE, // Total damage done to tanks
STAT_TEAM_MAX_STATS
}
/**
* Retrieves the survival stats for a specific steam ID. Returns the data in an array of length STAT_MAX_STATS.
* The array will only contain a single entry (index '0') that contains all the data for the client.
*
* Example:
* Handle hStats = L4D2Stat_GetClientStats(sSteamID);
* if (hStats != INVALID_HANDLE && GetArraySize(hStats) > 0)
* {
* int siTotal = GetArrayCell(hStats, 0, STAT_SI_TOTAL);
* ...
* CloseHandle(hStats);
* }
* @param steamID Steam ID of the client that you want to retrieve stats for
* @returns Handle containing an array of length STAT_MAX_STATS with all the various stats for the client
*/
native Handle L4D2Stat_GetClientStats(const char[] steamID);
/**
* Retrieves the survival stats for all the current survivor clients in the game. Returns an array of length
* STAT_MAX_STATS that contains an entry for each survivor.
*
* @returns Handle containing an array of length STAT_MAX_STATS with all the survival stats for each survivor
*/
native Handle L4D2Stat_GetAllSurvivorStats();
/**
* Retrieves the overall survival stats for the team. Returns the data in an array of length STAT_TEAM_MAX_STATS.
* The array will only contain a single entry (index '0') that contains all the data for the team.
*
* Example:
* Handle hTeamStats = L4D2Stat_GetTeamStats();
* if (hTeamStats != INVALID_HANDLE && GetArraySize(hTeamStats) > 0)
* {
* int siTotal = GetArrayCell(hTeamStats, 0, STAT_TEAM_TOTALSI);
* ...
* CloseHandle(hTeamStats);
* }
*
* @returns Handle containing an array of length STAT_TEAM_MAX_STATS with all the various stats for the team
*/
native Handle L4D2Stat_GetTeamStats();
public Native_GetClientStats(Handle:plugin, numParams)
{
decl String:sSteamID[64];
GetNativeString(1, sSteamID, sizeof(sSteamID));
new Handle:hTarget = CreateArray(STAT_MAX_STATS);
for (new i = 0; i < MaxClients; i++)
{
if (IS_VALID_SURVIVOR(i))
{
decl String:sID[64];
SteamWorks_GetClientSteamID(i, sID, sizeof(sID));
if (StrEqual(sID, sSteamID))
{
GetClientStats(hTarget, i);
return _:hTarget;
}
}
}
return _:INVALID_HANDLE;
}
public Native_GetFullStats(Handle:plugin, numParams)
{
new Handle:hTarget = CreateArray(STAT_MAX_STATS);
for (new i = 0; i < MAXPLAYERS; i++)
{
if (IS_VALID_SURVIVOR(i))
{
GetClientStats(hTarget, i);
}
}
return _:hTarget;
}
public Native_GetTeamStats(Handle:plugin, numParams)
{
new Handle:hTarget = CreateArray(STAT_TEAM_MAX_STATS);
new Float:fSIRate = GetRatePerMinute(g_iTotalSI);
new Float:fCommonRate = GetRatePerMinute(g_iCommonTotal);
new Float:fTankRate = GetRatePerMinute(g_iTankTotal);
I guess I was in over my head trying to get to the point that you can't just register a native in Squirrel and use it like you would any other function in SourceMod without various hoops that may or may not be written yet.
Quote:
Originally Posted by NiceT
I don't understand the implementation of the PrintCenterText on GitHud you replied to. Sorry about that.
The function is implemented and registered with C++; that's why you couldn't find anything written in SourcePawn about the underlying implementation as you mentioned in the first post.
Quote:
Originally Posted by Silvers
You can: [L4D2 / CSGO / ANY] Execute Vscript Get Return
You're using the game engine as a bridge for the functionality. Of course you'll require some sort of bridge in any case (the VScript Functions extension is another existing method), but it's far from direct interop between the two VMs.
Quote:
Originally Posted by dustinandband
So would this be incorrect usage of the "native" keyword?
SourceMod exposes the ability to register plugin functions as natives (this isn't necessarily a feature provided by other applications that embed the SourcePawn VM, if any). The plugin that knows about the native (whatever includes l4d2stats.inc) has no idea what implements the native. All it knows is that it's not within its own plugin, and so SM has to handle it.
I believe the native specifier started from Pawn and predates the ability to register natives through other SourcePawn plugins. SourceMod's native registration means it's closer to an extern, though again, that's a very simplified way of putting it.
You're using the game engine as a bridge for the functionality. Of course you'll require some sort of bridge in any case (the VScript Functions extension is another existing method), but it's far from direct interop between the two VMs.
Maybe I didn't express the meaning clearly before. what I want is to implement the function of sourcepawn through vscript, not vscript through sourcepawn. but, thanks everyone.
I was just pointing out something, not an answer to your question.
I still don't understand what you're trying to do. Why don't you write in SourcePawn? If you really need to call some VScript functions you can do for example:
PHP Code:
// Credit to Timocop on VScript function
static int iScriptLogic = INVALID_ENT_REFERENCE;
if(iScriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(iScriptLogic))
{
iScriptLogic = EntIndexToEntRef(CreateEntityByName("logic_script"));
if(iScriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(iScriptLogic))
LogError("Could not create 'logic_script");