Page 1 of 1

CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 12:12 pm
by toneddu2000
I noticed that if I write in ssqc

Code: Select all

void PlayerPostThink()
{	
	if (self.button0){
		FireWeapon();
	}
}
and if I keep pressing mouse button, weapon keeps firing, according to remaining ammo and firing pause time, of course.
Just a side note not so important: FireWeapon() communicates perfectly with csqc via SendEntity / SendFlags.

Instead, if I trigger the mouse pressing event directly in csqc with

Code: Select all

float CSQC_InputEvent(float evtype, float scanx, float chary, float devid)
{
	switch(evtype)
	{
		case IE_KEYDOWN:
			if(scanx == K_MOUSE1){
				sendevent("FireWeapon", "");//call Cmd_FireWeapon in ss/main/ssclient.c
				return TRUE;
			}
		return FALSE;
	}
	return FALSE;
}
then, in ssclient.c

Code: Select all

//triggered by CSQC_InputEvent in cs/main/csmain.c
void Cmd_FireWeapon()
{
	FireWeapon();
}
Weapon fires once but, keeping the mouse button, doesn't help to continue firing. You need to release the mouse button and press it again to fire another round. In this case, a machinegun behaviour couldn't be replicated.
There's method in CSQC_InputEvent to keep executing an event as long a key is pressed?

Thanks guys, as always

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 1:40 pm
by Spike
mouse do not auto-repeat.
keyboard buttons auto-repeat at an operating-system-defined rate, or not at all if the engine disabled autorepeat for some reason. auto-repeat repeats at the same rate as in the console or in notepad. key bindings will not fire from auto-repeated keys, which is one of many reasons why you should still use the engine's key binding system instead of enforcing your own vision of keys on people.
do not depend upon keyboard auto-repeat for anything other than text entry - failure to stick to this rule means that people can just go into their windows/etc keyboard settings and just crank up their key repeat rate to make things super spammy.

it could be replicated if you implement a timer in your own code. either in the csqc, or in the ssqc. preferably the ssqc, which will help smooth intervals between firing - just as the vanilla ssqc does with button0.

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 3:03 pm
by toneddu2000
which is one of many reasons why you should still use the engine's key binding system instead of enforcing your own vision of keys on people.
:?:
When did I enforce something to someone? :D
I'm just saying that, in my very honest opinion, it seems uneffective to me to use ssqc for things (like weapons and client inputs) that are intimately related to client side programming. A modern approach could be, for example, to add movetype to csqc (a great absence, imo) and directly controlling weapons with csqc and send to server ONLY the data other clients need to know (position / orientation / mesh / sounds of weapons, firing effects, etc.).
Why should I create all the weapon code in ssqc? What client cares about how much ammo do I have? Or how my weapon fire rate is configured? He / she only needs to know which weapon and when I'll use, so he / she can avoid my rockets! :D
it could be replicated if you implement a timer in your own code. either in the csqc, or in the ssqc. preferably the ssqc, which will help smooth intervals between firing - just as the vanilla ssqc does with button0.
I didn't create any timer in ssqc. The code I used it's the one I posted. Are you saying the engine created for me some sort of timer for input event?
Thanks Spike

PS:
preferably the ssqc
So, what CSQC_InputEvent needs for?

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 3:42 pm
by Spike
toneddu2000 wrote:When did I enforce something to someone? :D
it was a generic 'you'.
toneddu2000 wrote:I'm just saying that, in my very honest opinion, it seems uneffective to me to use ssqc for things (like weapons and client inputs) that are intimately related to client side programming. A modern approach could be, for example, to add movetype to csqc (a great absence, imo) and directly controlling weapons with csqc and send to server ONLY the data other clients need to know (position / orientation / mesh / sounds of weapons, firing effects, etc.).
Why should I create all the weapon code in ssqc? What client cares about how much ammo do I have? Or how my weapon fire rate is configured? He / she only needs to know which weapon and when I'll use, so he / she can avoid my rockets! :D
You don't have control over clientside stuff, it is trivial to edit the engine to spam weapon events even without editing csqc. that is a _massive_ loophole for cheats.
additionally, sendevent is a reliable function. reliables require the previous reliable to have been acked before the next can be sent. this causes some massive latency issues. you do NOT want to have to update the position 10 times a second in your csqc, send that to ssqc over reliables with the aforementioned latency issues, then rebroadcast that to all the csqc modules. you're just getting a double-whammy on latency. its not feasable.
instead, send your event to ssqc using the input_frame stuff, have the ssqc respond to that based upon timings, and have all csqc modules updating the position. the server is the only authoritive entity, the only one that can really be trusted to not cheat.
I didn't create any timer in ssqc. The code I used it's the one I posted. Are you saying the engine created for me some sort of timer for input event?
self.attack_finished is a timer.
or did you never write any ssqc weapons code?
So, what CSQC_InputEvent needs for?
menus, stuff where you really do need the raw events, stuff where you really do want to cancel those raw events to prevent the engine from acting on them.
You could implement your own input logic using csqc_inputevent and csqc_input_frame in combination with each other, but if you're making an fps then its overkill when the built-in fallbacks generate decent default csqc_input_frame input_* values already.

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 5:43 pm
by toneddu2000
You don't have control over clientside stuff, it is trivial to edit the engine to spam weapon events even without editing csqc. that is a _massive_ loophole for cheats.
ok. Didn't know that.
additionally, sendevent is a reliable function. reliables require the previous reliable to have been acked before the next can be sent. this causes some massive latency issues. you do NOT want to have to update the position 10 times a second in your csqc, send that to ssqc over reliables with the aforementioned latency issues, then rebroadcast that to all the csqc modules. you're just getting a double-whammy on latency. its not feasable.
Didn't know that either. No, of course I don't want that
instead, send your event to ssqc using the input_frame stuff, have the ssqc respond to that based upon timings, and have all csqc modules updating the position. the server is the only authoritive entity, the only one that can really be trusted to not cheat.
CSQC_Input_Frame, huh? Well, never heard of it till now! :D I'll try something on the net but on csqctest (my bible) it's unused. On Shpuld's Mobster Massacre there's some code. I'll dig it up, thanks.
Is this function a "csqc alter ego" of PlayerPostThink()?
self.attack_finished is a timer.
or did you never write any ssqc weapons code?
No, no.. we didn't understand each others! :D I meant ... a timer for input, not for weapons!
Infact if, instead of weapon function I replaced ssqc code with

Code: Select all

void PlayerPostThink()
{	
	if (self.button0){
		bprint("A\n");
	}	
}
It will print AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA as long I press mouse button.
On csqc it will print A. Stop. So it's not something related to my code but instead something related to how "button released" is managed in ssqc and csqc
menus, stuff where you really do need the raw events, stuff where you really do want to cancel those raw events to prevent the engine from acting on them.
whoa, really small breadcrumbs. Well this definately breaks my dreams with csqc. :D
I guess I'll do what everyone does: all the big part in ssqc, aided by small bits in csqc

Thanks Spike, vital as always your help

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 6:36 pm
by Spike
attack_finished _IS_ a timer for input.
after it triggers, another input is accepted. how is that not input related? :P

people use ssqc for things because its the authoritive version of the game state. you can have lots of different instances of the game running in lots of 100% independant csqc modules, sure... but that's really not a multiplayer game. that's just a load of different people all playing the same game independantly.
there's not really any reason you can't reduce weapon impacts to that of a single timer (per attack), but do do so you would have to decide in advance whether and when it was going to hit or latency will just destroy everything. of course, in such a case, hits would likely need to be able to home in on the receiving client and stuff. I don't think that sort of thing would have a good feel to it though. such things are good in mmo-style games though, where latency and bandwidth use can spike when things get crowded.

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 10:53 pm
by gnounc
Firstly:
toneddu2000 wrote: I guess I'll do what everyone does: all the big part in ssqc, aided by small bits in csqc
Spike wrote: people use ssqc for things because its the authoritive version of the game state.
Thats the main thing I think people should take away from this thread. it's pretty important.




ignoring the what/why of what you're doing,

csqc_input_event is called by the engine whenever there is an input event (whenever someone hits a keyboard key or touches the mouse). so it isnt called every frame.

You mentioned playerpostthink and shoving a test print in there printing every frame. If thats the behavior you want in csqc, you need to find a function that similarly is called every frame.

Ive been doing things like that at the very bottom of CSQC_UpdateView();

Shove any code in there that you want run every frame.

I'm not saying thats the right way to do what you are trying to do, I'll let you be the judge of that.
Good luck.

PS: bear this in mind..
Spike wrote:attack_finished _IS_ a timer for input.
You'll need a similar mechanism BECAUSE your function will be called every frame.

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 11:17 pm
by toneddu2000
no guys, you did not understand the bprint example. It wasn't my intent to print something every frame. My intent was to understand why same action has different reactions on ssqc AND csqc.
I think the big problem about csqc is that there's no manual about how to use it. For ssqc there's a bare manual and lots of tutorial, but for csqc you have to look what other guys did before you and try to comprehend what they wrote.
Regarding CSQC_InputEvent my position is pretty clear: it's imo the right function to call if you want to trigger an action based on player input. Simple. My question was elementary: why ssqc function remains "listening" as long as button is pressed and csqc one doesn't? I didn't say I want a function that runs every frame and stuff! :D I just pointed out I noticed this difference.
Ive been doing things like that at the very bottom of CSQC_UpdateView();
Shove any code in there that you want run every frame.
Yeah, I try to use UpdateView to...update the view! :D
So, update the player view, differentiate first person from third person view, differentiate local player from other players and so on.
For example, skeleton stuff imo shouldn't go down there because there's predraw function for it.
You'll need a similar mechanism BECAUSE your function will be called every frame.
Ok, so maybe what I did it's not the right thing to do it. Things like this should be triggered by an event, not spammed. Most of all because I'm trying to use FTEQW for a truly multiplayer game

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 11:35 pm
by gnounc
toneddu2000 wrote:why ssqc function remains "listening" as long as button is pressed and csqc one doesn't?
because the ssqc function you mentioned is called every frame. (listening always)
and the csqc one you mentioned (csqc_input_event) is only called when a button is pressed or released (or the mouse is moved)
which is the kind of thing usually found in engine code, and not in qc. its been made available to csqc.

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sat Dec 27, 2014 11:42 pm
by toneddu2000
ah ok thanks gnounc, understood now. I guess that, if I want to replicate this kind of behaviour I'd do a check through InputFrame to control if button is released or it's still pressed, but always triggered by CSQC_InputEvent. I don't know if it's bandwith-killer but I'll do some tests
Thanks again

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sun Dec 28, 2014 12:59 am
by gnounc
What I did, was set a flag when the left mouse button is held, (in csqc_input_event, if event is keydown, if key is mouse1)
and unset that flag when the left mouse button is released.

THEN in a function that is called every frame, like at the bottom of CSQC_UpdateView(), check that flag, and check the time since it was last pressed.

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sun Dec 28, 2014 2:12 am
by Spike

Code: Select all

float mouseisheld;
float mouseretrigger;
float(float evtype, float a_scan, float b_uni) CSQC_InputEvent =
{
  switch(evtype)
  {
    case IE_KEYDOWN:
    case IE_KEYUP:
    if (a_scan == K_MOUSE1)
    {
      mouseisheld = (evtype == IE_KEYDOWN);
      return mouseisheld;
    }
    break;
  }
  return FALSE;
};

void() CSQC_UpdateView =
{
  if (mouseisheld && mouseretrigger < time)
  {
    print("they pressed mouse1, and we stopped the key binding from working\n")
    mouseretrigger = time + 1;
  }
};
the above will re-fire only once every second, of course. note that that's in terms of _server_ time instead of client time. if you want to use the client's local clock (instead of the server's, which can jump a little due to latency), use the cltime global as your clock instead of the time global.



the csqc_input_frame function is called just before each input journal entry is generated. the various input_* globals will be pre-initialised to what the engine thinks should be in that input frame, but you can overwrite them. for instance, the following code will swap over +attack and +jump. because why not:
void() CSQC_Input_Frame =
{
if ((input_buttons & 3) == 2)
input_buttons = 1 | (input_buttons & ~3);
else if ((input_buttons & 3) == 1)
input_buttons = 2 | (input_buttons & ~3);
};

now, the input journal's frames will be generated with bit values 1(+attack) and 2(jump) swapped. the server will see these swapped values instead of the original ones, etc.
yeah, button1 is weird. +use was never implemented and the raw network representation omits it completely, hence why 1 and 2 instead of 1 and 4.
you can override impulse, angles, movement, and stuff this way too. just grep through fteextensions.qc for the input_* globals to see what exists and the names of them.
I recently tweaked the engine to also include prydon cursor fields in this way (this was something shpuld craved for in his twitch stream, iirc), which can give a few other interesting input fields that can be repurposed for other stuff without having to use lots of custom events.

Re: CSQC_InputEvent - event pressed not loopable?

Posted: Sun Dec 28, 2014 2:38 pm
by toneddu2000
gnounc wrote:What I did, was set a flag when the left mouse button is held, (in csqc_input_event, if event is keydown, if key is mouse1)
and unset that flag when the left mouse button is released.

THEN in a function that is called every frame, like at the bottom of CSQC_UpdateView(), check that flag, and check the time since it was last pressed.
thanks gnounc for the tip

Thanks a lot Spike for the code. I'll test it immediately! I honestly try to avoid as much as possible functions that run every frame (preferring triggered events) but, if it's impossible to do it in another way, ok.
Spike wrote:you can override impulse, angles, movement, and stuff this way too. just grep through fteextensions.qc for the input_* globals to see what exists and the names of them.

Code: Select all

#ifdef CSQC
float input_timelength;
vector input_angles;
vector input_movevalues;
float input_buttons;
float input_impulse;
#endif
Spike wrote:I recently tweaked the engine to also include prydon cursor fields in this way (this was something shpuld craved for in his twitch stream, iirc), which can give a few other interesting input fields that can be repurposed for other stuff without having to use lots of custom events.
:shock: