All the credit for those particular code modifications go to Gwahir, I didn't write any of the clk functions.
Also, it's a good idea for debug, but is it useful for anything else?
EDIT: Useful in it's current state I mean.
I was thinking of new ways of passing data from the outside world into the game, primarily for use in digital screen image displaying. So far I have been using a CPU with a massive amount of code generated from a PHP script I wrote to get all the colors of the pixels in game allowing me to mcopy it to the screen's memory.
Although this worked great, it was fairly tedious and took ages to upload, compile, and execute the CPU.
So I figured, why not add a concommand input to the E2, to allow it to receive data through concommands. So I did just that.
Through my tests, I was able to send roughly 2000 commands a second and paint it correctly on the digital screens I had set up.
There could be many other uses for this, including being able to bind keys to interface with the E2.
I added a new concommand "wire_expression2_runcmd", and several functions for the E2.
If the expression was not executed by a concommand, cmdRan() will return "", and cmdArgs will return an empty array.runOnCmd(N) -- toggles whether or not the E2 should execute when the command is entered, by default it is off, and this whole module will not work without it enabled before hand.
cmdClk() -- Returns 1 if the E2 was executed by a command being run, 0 if not.
cmdRan() -- Returns a string, of the command entered (The first argument)
cmdArgs() -- Returns an array of strings returned by the command.
And the part you have all been waiting for...
Code:AddCSLuaFile('cmdinput.lua') //Original author: ZeikJT //Modified by Gwahir //Further Modified by Some Guy wire_exp2_RunOnCmd = {} local runByCmd = false local CmdRan = "" local CmdArgs = {} local function HasEnt(table, ent) if !ValidEntity(ent) then return false end local id = ent:EntIndex() for i,e in ipairs(wire_exp2_RunOnCmd) do if ValidEntity(e) && e:EntIndex() == id then return true end end return false end registerFunction("runOnCmd", "n", "", function(self, args) local op1 = args[2] local rv1 = op1[1](self, op1) if rv1 != 0 then if !HasEnt(wire_exp2_RunOnCmd, self.entity) then table.insert(wire_exp2_RunOnCmd,self.entity) end else for i,e in ipairs(wire_exp2_RunOnCmd) do if e == self.entity then table.remove(wire_exp2_RunOnCmd,i) break end end end end) registerFunction("cmdClk", "", "n", function(self, args) if runByCmd then return 1 else return 0 end end) registerFunction("cmdRan", "", "s", function(self, args) return CmdRan end) registerFunction("cmdArgs", "", "r", function(self, args) return CmdArgs end) registerCallback("destruct",function(self) if !ValidEntity(self.entity) then return end for i,e in ipairs(wire_exp2_RunOnCmd) do if e == self.entity then table.remove(wire_exp2_RunOnCmd,i) break end end end) function Exp2ReceiveCmd( ply, cmd, args ) runByCmd = true CmdRan = args[1] table.remove(args,1) CmdArgs = args local clean = false for i,e in ipairs(wire_exp2_RunOnCmd) do if ValidEntity(e) && e.Execute != nil && e.player == ply then e:Execute() else clean = true end end runByCmd = false CmdRan = "" CmdArgs = {} if clean then local indexOffset = 0 for i,e in ipairs(wire_exp2_RunOnCmd) do if e == nil || !e:IsValid() || e.Execute == nil then table.remove(wire_exp2_RunOnCmd, i - indexOffset) indexOffset = indexOffset + 1 break end end end end concommand.Add("wire_expression2_runcmd",Exp2ReceiveCmd)
To use a concommand, it is quite simple. Just do:
wire_expression2_runcmd <the command name> <args>...
For example:
wire_expression2_runcmd MyTest 13 47 56
cmdRan() will return "MyTest"
and cmdArgs() will return an array set up like so:
[1] = "13"
[2] = "47"
[3] = "56"
This is still limited by the max concommand length, which I believe is 255 characters.
Credits: ZiekJT & Gwahi, I based this off the chat functions they wrote.
If you have any questions, ideas, or suggestions, feel free to reply, or PM me.
All the credit for those particular code modifications go to Gwahir, I didn't write any of the clk functions.
Also, it's a good idea for debug, but is it useful for anything else?
EDIT: Useful in it's current state I mean.
Against stupidity the Gods themselves contend in vain.
-Friedrich Schiller
The flame puts me in the mood to "Do it!".
-Dart, Legend of Dragoon
I discussed something along the lines of this not too long ago, however, for it to be reasonable, the commands needs to be registered clientside so one can't spam the server with useless commands.
As far as use, I'd say it is limited, but it's one way for people to bind more keys for instance. But yeah, it's limited.
As I mentioned I was looking for a better method of transfering data from the outside world, into the game. I was doing this for a long time with the CPU, by making a massive db and then mcopying it to the screens memory.
Although it worked, it was tedious to set up, and took a long time to upload the CPU.
I wouldn't say that this is very limited, since you could use it for almost any outside input. This is more of an "Interface with the outside world" type of thing. I have already begun drawing images on the digital screen with it, and it has been much faster than using the CPU method, and I am sure it is also much easier on the server.
As for the commands being abuseable, I don't see how it would be more abuseable than any other command in the source engine. You would have to have an E2 that is enable to recieve a command for it to actually do anything major on the server. It could be used as a crude method of overclocking an E2, but the CPU has a far greater speed for that, since you are limited by how many commands you can send per tick. It is also currently limited to only the owner's expressions recieving the commands, to prevent other players from interfering.
I can't currently think of a whole lot that could be done with this currently, other than transfering data from the client to the expression or binding keys to control it. But I do feel it is one of those very specialized tools that allows you to do things you otherwise could not.
Well, that's what I would call limited :P
It has a pretty narrow purpose, transfering data as you say, that doesn't mean it's bad, just that it isn't likely that the majority of the E2-users would ever consider it.
I didn't actually look or read closely, I though it looked like it created functions, not that it only was a single command. But then of course, it's not a problem.
(Also, max command-length is less than 256, I think 256 is including the command name itself)
So what do I need to do to get this included? It could be very useful in the future, although most people will have no idea what to do with it, it still expands capabilities and I cannot think of a single way that it can be exploited beyond what can already be done in the source engine itself.
I could see having a bit of use out of this, it would be quite useful.
There are a few things that would need to be improved, but I can definately see this being of use and it being on the SVN.
1. E2s need to be registered per player, so they can be cleaned up on disconnect (destruct is only run when entities are removed)
2. Perhaps some kind of call-sign system, so you can use it as "..._runcmd MyE2 1 2 3", and that will send "1 2 3" to whatever E2s are registered as "MyE2" (and perhaps add a cmdClk(S) to test for only certain commands)
3. Make Your commands only be recognized by Your expressions
Or what do you all think?
(Check the GameTick-extension to get some of it for free)
#1. Will do
#2. It already Does that. cmdClk() only returns whether or not the E2 was run by a command or not. cmdRan() returns a string, of the first Argument, which is used as the "Command name" then cmdArgs() returns the 2nd and on args. So it I did: wire_expression2_runcmd MyE2 1 2 3, My E2 code would look like this:
#3. Does that as well.Code:if (first()) { runOnCmd(1) } if (cmdClk()) { if (cmdRan() == "MyE2") { Args = cmdArgs() print(Args:string(1)) print(Args:string(2)) print(Args:string(3)) } }
Code:if ValidEntity(e) && e.Execute != nil then if (e.player == ply) then //DO NOT RUN UNLESS IT IS YOUR EXPRESSION e:Execute() end else
I will fix #1 after I get breakfast.![]()
8 months late, but... Better now than never.
I lost track of this after this post due to other things going on at the time, but THIS thread reminded me of it, so I fixed it up and it matches all the above discussed conditions.
Code://Base code by Gwahir //Functions and functionality by Incompatible /********Vars********/ wire_exp2_RunOnCmd = {} local runByCmd = false local CmdRan = "" local CmdArgs = {} /********************/ /********Helper Functions********/ local function HasEnt(table, ent) if ValidEntity(ent) then for i,e in ipairs(wire_exp2_RunOnCmd) do if ValidEntity(e) && e == ent then return true end end end return false end /********Actual Functions********/ registerFunction("runOnCmd", "n", "", function(self, args) local op1 = args[2] local rv1 = op1[1](self, op1) if rv1 != 0 then if !HasEnt(wire_exp2_RunOnCmd, self.entity) then table.insert(wire_exp2_RunOnCmd,self.entity) end else for i,e in ipairs(wire_exp2_RunOnCmd) do if e == self.entity then table.remove(wire_exp2_RunOnCmd,i) break end end end end) registerFunction("cmdClk", "", "n", function(self, args) if runByCmd then return 1 else return 0 end end) registerFunction("cmdRan", "", "s", function(self, args) return CmdRan end) registerFunction("cmdArgs", "", "r", function(self, args) return CmdArgs end) /********Cleanup Functions********/ registerCallback("destruct",function(self) if !ValidEntity(self.entity) then return end for i,e in ipairs(wire_exp2_RunOnCmd) do if e == self.entity then table.remove(wire_exp2_RunOnCmd,i) break end end end) hook.Add( "EntityRemoved", "wire_expression2_concmd_playercleanup", function( ply ) if (ply:IsPlayer()) then local indexOffset = 0 for i,e in ipairs(wire_exp2_RunOnCmd) do if e.player == ply then table.remove(wire_exp2_RunOnCmd, i - indexOffset) indexOffset = indexOffset + 1 end end end end ) /********Backend Functionality********/ function Exp2ReceiveCmd( ply, cmd, args ) runByCmd = true CmdRan = args[1] or "" table.remove(args,1) CmdArgs = args or {} if (CmdRan != "" and CmdArgs != {}) then local clean = false for i,e in ipairs(wire_exp2_RunOnCmd) do if ValidEntity(e) && e.Execute != nil then if (e.player == ply) then e:Execute() end else clean = true end end if clean then local indexOffset = 0 for i,e in ipairs(wire_exp2_RunOnCmd) do if !ValidEntity(e) || e.Execute == nil then table.remove(wire_exp2_RunOnCmd, i - indexOffset) indexOffset = indexOffset + 1 break end end end end runByCmd = false CmdRan = "" CmdArgs = {} end concommand.Add("wire_expression2_runcmd",Exp2ReceiveCmd)
Bookmarks