Raised This Month: $ Target: $400
 0% 

[L4D2] Remove excess weapon_* on the ground


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
ilham92-cc-sakura
Senior Member
Join Date: Oct 2008
Location: /var/www/index.html
Old 07-08-2024 , 12:36   [L4D2] Remove excess weapon_* on the ground
Reply With Quote #1

As per title, some plugins spawn a lot of weapon time to time, so I plan to remove excess weapon_* but I didn't see weapon get removed, I not sure if my code is wrong

Code:
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>

#define MAX_WEAPONS 18 // Maximum allowed weapon entities
#define CHECK_INTERVAL 5.0 // Interval in seconds to check for weapon entities

Handle g_Timer = INVALID_HANDLE;

public Plugin myinfo =
{
	name = "[L4D2] Limit Weapons Ground",
	author = "Anime4000",
	description = "Limit weapons on the ground",
	version = "1.0.0",
	url = "https://steamcommunity.com/id/anime4000/"
}

public void OnPluginStart()
{
	// Start the timer if it's not already running
	if (g_Timer == INVALID_HANDLE)
	{
		g_Timer = CreateTimer(CHECK_INTERVAL, Timer_CheckWeapons, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
	}
}

public void OnMapStart()
{
	// Start the timer if it's not already running
	if (g_Timer == INVALID_HANDLE)
	{
		g_Timer = CreateTimer(CHECK_INTERVAL, Timer_CheckWeapons, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
	}
}

public Action Timer_CheckWeapons(Handle timer, any data)
{
	CheckAndManageWeapons();
	return Plugin_Continue;
}

public void CheckAndManageWeapons()
{
	// Array to store the entity indices of weapons
	int weaponEntities[MAX_WEAPONS + 1];
	int weaponCount = 0;

	// Iterate through all entities
	for (int entity = 1; entity <= GetMaxEntities(); entity++)
	{
		if (IsValidEntity(entity) && IsWeaponEntity(entity))
		{
			weaponEntities[weaponCount++] = entity;

			// If we have found more weapons than the maximum allowed, remove the extras
			if (weaponCount > MAX_WEAPONS)
			{
				PrintToConsoleAll("RemoveEntity Weapon %d (%d)", entity, weaponCount - 1);
				AcceptEntityInput(entity, "Kill", -1, -1, -1);
			}
		}
	}
}

public bool IsWeaponEntity(int entity)
{
	// Check if the entity is a valid weapon by checking the classname prefix
	char classname[64];
	GetEdictClassname(entity, classname, sizeof(classname));

	// Check if the classname starts with "weapon_"
	if (strncmp(classname, "weapon_", 7) == 0)
	{
		return true;
	}

	return false;
}
What is different between RemoveEntity(int); or AcceptEntityInput(int, "kill);
some said using AcceptEntityInput is better way, but I didn't see any weapons on the ground get removed
__________________

Last edited by ilham92-cc-sakura; 07-08-2024 at 12:37. Reason: identation
ilham92-cc-sakura is offline
Marttt
Veteran Member
Join Date: Jan 2019
Location: Brazil
Old 07-08-2024 , 20:57   Re: [L4D2] Remove excess weapon_* on the ground
Reply With Quote #2

18 weapons is a small value compared to the amount of weapon entities on the map
also you may have some crashes because you are not checking if the weapon has owner
it may lead to deleting equipped weapons as well
__________________
Marttt is offline
ilham92-cc-sakura
Senior Member
Join Date: Oct 2008
Location: /var/www/index.html
Old 07-09-2024 , 23:26   Re: [L4D2] Remove excess weapon_* on the ground
Reply With Quote #3

Quote:
Originally Posted by Marttt View Post
18 weapons is a small value compared to the amount of weapon entities on the map
also you may have some crashes because you are not checking if the weapon has owner
it may lead to deleting equipped weapons as well
I understand, this what I want because I have Points System (PS) plugins running, player could use PS instead.

the code seem not working even I set MAX_WEAPONS 1, reason to believe recent L4D2 update making it incompatible
__________________
ilham92-cc-sakura is offline
101
Senior Member
Join Date: Nov 2023
Old 07-16-2024 , 09:39   Re: [L4D2] Remove excess weapon_* on the ground
Reply With Quote #4

First of All :
* You have to check if weapon has an owner or not to avoid server crash [as you were told]
Spoiler

* You don't need to store weapons in array if you only want to restrict count , unless you plan to use them later so that would be logical , otherwise :
Spoiler


* You can do check once (only when round start) , so you don't need to create a repeated timer unless you have a custom plugin that spawns weapons continuously! .. BTW , you can restrict weapon by using another method (Allow weapon to be removed by chance using OnEntityCreated hook) :
Spoiler
101 is offline
Bacardi
Veteran Member
Join Date: Jan 2010
Location: mom's basement
Old 08-10-2024 , 12:43   Re: [L4D2] Remove excess weapon_* on the ground
Reply With Quote #5

In topic first post, it looks like classic mistake with timers.
You create repeated timer and stored on handle, problem is that you use also timer flag TIMER_FLAG_NO_MAPCHANGE.

Timer will stop and disappear on map load, but it will not clear the handle,
you have old address of that non exist timer.

For quick fix, you should remove all timer code from OnPluginStart().
Then remove all checks on OnMapStart(), just create timer straight on that handle.



Anyway, here random plugin example.
I used @101 idea also, using sdkhooks OnEntityCreated.
PHP Code:





#include <sdktools>
#include <sdkhooks>


enum struct WpInfo
{
    
int entref;
    
int timestamp;
}


Handle hTimer;
ArrayList listent;
bool IsRoundFreezeEnd true;

// Weapon m_iState
#define WEAPON_IS_ONTARGET            0x40 // weapon currently auto-aimed (hl2 legacy code ?)
#define WEAPON_NOT_CARRIED            0    // Weapon is on the ground
#define WEAPON_IS_CARRIED_BY_PLAYER        1    // This client is carrying this weapon.
#define WEAPON_IS_ACTIVE                2    // This client is carrying this weapon and it's the currently held weapon

const int threshold 18;

public 
void OnPluginStart()
{
    
HookEventEx("round_freeze_end"round_freeze_end);

    
listent = new ArrayList(sizeof(WpInfo));
}

public 
void OnMapStart()
{
    
IsRoundFreezeEnd true;

    
listent.Clear();
    
delete hTimer;
}

public 
void round_freeze_end(Event event, const char[] namebool dontBroadcast)
{
    
listent.Clear();
    
CreateTimer(1.0delay_TIMER_FLAG_NO_MAPCHANGE); // lets make sure, map own weapon entities are spawned
}

public 
Action delay(Handle timer)
{
    
IsRoundFreezeEnd false;
    
hTimer CreateTimer(2.0TimerCheck_TIMER_REPEAT);

    return 
Plugin_Continue;
}



public 
void OnEntityCreated(int entity, const char[] classname)
{
    if(
IsRoundFreezeEnd)
        return;

    if(
StrContains(classname"weapon_"false) == 0)
    {
        
SDKHook(entitySDKHook_SpawnPostSpawnPost);
    }
}

public 
void SpawnPost(int entity)
{
    if(!
HasEntProp(entityProp_Send"m_iState"))
        return;

    
WpInfo info;
    
info.entref EntIndexToEntRef(entity);
    
info.timestamp GetTime();
    
    
listent.PushArray(infosizeof(WpInfo));
}

public 
Action TimerCheck(Handle timer)
{
    if(
hTimer == null || hTimer != timer)
        return 
Plugin_Stop;


    
int listentsize listent.Length;

    
// Treshold when start remove weapons
    
if(listentsize <= threshold)
        return 
Plugin_Continue;

    
WpInfo info;
    
int time GetTime();
    
int ent;



    for(
int x 0listentsize threshold && listentsizex++)
    {
        
listent.GetArray(xinfosizeof(WpInfo));

        
        
ent EntRefToEntIndex(info.entref);

        if(
ent == -1)
        {
            
listent.Erase(x);
            
x--, listentsize--;

            continue;
        }

        if(
GetEntProp(entProp_Send"m_iState") == WEAPON_NOT_CARRIED)
        {
            if( (
time info.timestamp) <= 60 )    // new weapon stay on ground about 60 seconds when not pickup
                
continue;

            
AcceptEntityInput(ent"Kill");
            
listent.Erase(x);
            
x--, listentsize--;

        }
        else
        {
            
// refresh timestamp
            
info.timestamp time;
            
listent.SetArray(xinfosizeof(WpInfo));
        }
    }


/*
    char classname[64];
    int ent = -1;

    while((ent = FindEntityByClassname(ent, "weapon_*")) != -1)
    {
        if(!HasEntProp(ent, Prop_Send, "m_iState")
        || GetEntProp(ent, Prop_Send, "m_iState") != WEAPON_NOT_CARRIED)
            continue;


        // Do code here
        
        GetEntityClassname(ent, classname, sizeof(classname));
        PrintToServer("%i ent %s", ent, classname);
    }
*/


    
return Plugin_Continue;

Plugin save weapon entities, what are created after round_freeze_end event, into arraylist.
These weapons in arraylist get removed only, when those exceed over 18 limit.
These new weapons have 60 seconds timelimit when on ground and not picked.
When new weapon is picked up again from ground, time get reset.





- For extra, there is code snippet how you can loop all weapons on map what are not carried.
__________________
Do not Private Message @me
Bacardi is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 01:24.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode