1. This forum is ARCHIVED! Visit the new Cloud Sixteen forums, codename Eden, at https://eden.cloudsixteen.com. These forums will remain archived for a few months before being closed down, so try to encourage plugin developers to begin moving their content across to the new forums.
Dismiss Notice
Hi Guest, you need a Steam account to register and post on these forums. Login with Steam at the top of the forums to get started!
Dismiss Notice
Hi Guest, do you want to buy HL2RP or another Clockwork schema? Visit the Cloud Sixteen Store to get started!

[RELEASE] PropertyCommand Library/Hack

Discussion in 'Development' started by Spencer, Dec 30, 2012.

  1. Spencer

    Spencer Spencer Sharkey

    This simple library file simply modifies a few features within the standard Clockwork command library to allow the addition of registering commands on the property menu. Its labeled as a hack because it replaces the standard Clockwork.command:New(name) method so it can edit the metatable manually, so lets hope that doesn't change in the near future. There was no real other way around this. (The property menu is the combobox-like menu that appears when you right click on entities while holding down the context-menu key) Paste this file into a shared library file (ex: schema\libraries\sh_propertycommand.lua)

    Code:
    local Clockwork = Clockwork;
    
    CMDFILTER_PLAYER = function(player, entity) return (entity:IsPlayer()) end
    CMDFILTER_PROP = function(player, entity) return (entity:GetClass() == "prop_physics") end
    
    --[[ Set the __index meta function of the class. --]]
    local CLASS_TABLE = {__index = CLASS_TABLE};
    
    -- A function to register a new command.
    function CLASS_TABLE:Register()
    	return Clockwork.command:Register(self, self.name);
    end;
    
    function CLASS_TABLE:RegisterProperty(Filter)
    	return Clockwork.command:RegisterProperty(self, self.name, Filter);
    end;
    
    -- A function to get a new command.
    function Clockwork.command:New(name)
    	local object = Clockwork.kernel:NewMetaTable(CLASS_TABLE);
    		object.name = name or "Unknown";
    	return object;
    end;
    
    -- A function to register a new command for properties.
    function Clockwork.command:RegisterProperty(data, name, Filter)
    	local realName = string.gsub(name, "%s", "");
    	local uniqueID = string.lower(realName);
    	
    	if (!self.stored[uniqueID]) then
    		self.stored[uniqueID] = data;
    		self.stored[uniqueID].name = realName;
    		self.stored[uniqueID].text = data.text or "<none>";
    		self.stored[uniqueID].flags = data.flags or 0;
    		self.stored[uniqueID].access = data.access or "b";
    		self.stored[uniqueID].arguments = data.arguments or 0;
    		if (CLIENT) then
    			self:AddHelp(self.stored[uniqueID]);
    		end;
    	end;
    
    	self.stored[uniqueID].pOrder = data.pOrder or 0;
    	self.stored[uniqueID].pIcon = data.pIcon or nil;
    	self.stored[uniqueID].pLabel = data.pLabel or data.name;
    	self.stored[uniqueID].pFilter = Filter
    
    	local commandTable = self.stored[uniqueID];
    
    	properties.Add(uniqueID, {
    		MenuLabel	=	commandTable.pLabel,
    		Order		=	commandTable.pOrder,
    		MenuIcon	=	commandTable.pIcon,
    		Filter		=	function(self, ent, ply) 
    							if (!Clockwork.player:HasFlags(ply, commandTable.access)) then return false end
    							if (!IsValid(ent)) then return false end
    							if (!commandTable.pFilter(ply, ent)) then return false end
    							return true 
    						end,
    						
    		Action		=	function( self, ent )
    							self:MsgStart()
    								net.WriteEntity( ent )
    							self:MsgEnd()
    						end,
    						
    		Receive		=	function( self, length, player )
    							local ent = net.ReadEntity()
    							if (Clockwork.plugin:Call("PlayerCanUseCommand", player, commandTable, ent)) then
    								if (Clockwork.player:HasFlags(player, commandTable.access)) then
    									if (commandTable.OnRun) then
    										local bSuccess, value = pcall(commandTable.OnRun, commandTable, player, ent);
    
    										if (!bSuccess) then
    											ErrorNoHalt("[Clockwork] The "..commandTable.name.." (PROPERTY USE) command has failed to run.\n");
    											ErrorNoHalt(value.."\n");
    										elseif (Clockwork.player:GetDeathCode(player, true)) then
    											Clockwork.player:UseDeathCode(player, commandTable.name, ent);
    										end;
    										
    										if (bSuccess) then
    											Clockwork.kernel:PrintLog(LOGTYPE_GENERIC, player:Name().." (PROPERTY USE) has used '"..commandTable.name.."'");
    											return value;
    										end;
    									end;
    								end
    							end
    						end
    	});
    
    	return commandTable
    end;
    


    We use this library to add a few simple admin commands to the context-menu, but it can really be used with any entity and any command. You can register it to already existing commands, too. The only difference is when someone uses it using the property method, an extra argument will be sent to the commands OnRun function containing the entity object.

    [​IMG]

    Here's an example of a command that kills a player when you select the option in the menu. This command also has compatibility with typing /plykill <Name> as well!

    Code:
    local Clockwork = Clockwork;
    
    local COMMAND = Clockwork.command:New("PlyKill");
    COMMAND.tip = "Kill a player.";
    COMMAND.text = "<string Name>";
    COMMAND.flags = CMD_DEFAULT;
    COMMAND.access = "o";
    
    -- Called when the command has been run.
    function COMMAND:OnRun(player, arguments, entity)
    	
    	local target = entity or Clockwork.player:FindByID(arguments[1])
    
    	if (target:Alive()) then
    		target:Kill()
    		Clockwork.player:NotifyAll(player:Name().."has killed " ..target:Name()..".");
    	else
    		Clockwork.player:Notify(target, "The target is already dead.");
    	end
    	
    end;
    
    COMMAND.pLabel = "Kill Player"
    COMMAND.pIcon = "icon16/bomb.png"
    
    COMMAND:RegisterProperty(CMDFILTER_PLAYER);
    
    As you can see, there's a few simple things added. Firstly the entity argument passed to the command's OnRun method, as well as a few properties.

    COMMAND.pLabel is basically the "fancy name" that'll appear on the menu itself, if you don't define this it'll just default to the command name, but it's suggested you add one.

    COMMAND.pIcon [OPTIONAL] is a path to the icon that'll appear next to the label on the menu. This is an optional field.

    COMMAND.pOrder [OPTIONAL] is an integer order of where it should appear on the menu. This is optional too, otherwise it'll just place it above the last one that's been registered. The higher the number, the more towards-the-bottom the menuitem will be.

    Lastly, you'll want to call COMMAND:RegisterProperty(Filter) to register it as a Property command. The function argument is required, and it's the client-side filter function so the properties module knows what entity to display this menu item on. The Filter argument should be a function. I've provided two global convenience functions to check for players, and props. They look like this

    Code:
    CMDFILTER_PLAYER = function(player, entity) return (entity:IsPlayer()) end
    CMDFILTER_PROP = function(player, entity) return (entity:GetClass() == "prop_physics") end
    
    Say you wanted it to only appear on items, you could easily call your register method like so:

    Code:
    COMMAND:RegisterProperty(function(player, entity)
           return (entity:GetClass() == "cw_item")
    end);
    
    I hope this is useful to someone! Enjoy!
     
  2. Mannulus

    Mannulus I hate everyone equally. Clockwork Customer

    Are we to copy each section of that code and put it into a single .lua file or...? Hate to sound stupid xD
     
  3. Spencer

    Spencer Spencer Sharkey

    Read the post.

    If you don't know what you're doing this probably isn't for you.
     
  4. Razor

    Razor Guest

    Spencer don't be so harsh :C
     
  5. Spencer

    Spencer Spencer Sharkey

    How was that harsh, it's true.
     
  6. Datzy

    Datzy Guest

    Awesome, I think this'll be greatly useful.
     
  7. jamiecross

    jamiecross HTML and VB coder

    YES! I can be lazy thanks Spencer.
     

Previous Readers (Total: 0)