Simple and extravagant prediction demos for useItems

This commit is contained in:
Christopher Dawalt 2021-09-28 06:51:21 -04:00
parent d8b003e23c
commit f72f98c46e
11 changed files with 373 additions and 60 deletions

View File

@ -42,32 +42,16 @@ ClientGame_ConsoleCommand(void)
//pSeatLocal->m_bFireModeFreshPress = TRUE;
break;
#if USE_ITEMS_PREDICTION_TEST == 0
//case "useitems"
// TS_playerUseItems();
// break;
case "+useitems":
pl = (player)pSeat->m_ePlayer;
if( !(pl.gflags & GF_UNUSED3)){
TS_playerUseItems();
}
pl.gflags |= GF_UNUSED3;
Input_useItems_press();
break;
case "-useitems":
pl = (player)pSeat->m_ePlayer;
pl.gflags &= ~GF_UNUSED3;
Input_useItems_release();
break;
#else
case "+useitems":
//TS_playerUseItems();
//pSeatLocal->m_bUseItemsFreshPress = TRUE;
pSeatLocal->m_bUseItems = TRUE;
break;
case "-useitems":
pSeatLocal->m_bUseItems = FALSE;
break;
#endif
case "usepowerup":
TS_playerUsePowerup();
break;

View File

@ -206,6 +206,13 @@ ClientGame_EventParse(float fHeader)
case EVENT_TS::USEITEMS_CHANGE_CALLBACK:{
pl.clientUseItemsCallback();
}break;
#if OTHER_PREDICTION_TEST == 1
case EVENT_TS::CUSTOM_PREDICTION_CALLBACK:{
Custom_Prediction_Server_Callback(pl);
}break;
#endif
case EVENT_TS::TEST:{
//printfline("EVENT_TS::TEST HAPPENED");
//clearscene();

View File

@ -1,11 +1,7 @@
// SHARED CONFIG SETTING - set this consistently between client/server progs!
// If 0, nothing special.
// If 1, Makes some changes to enable prediction for useitems.
// Spams the turn-on click noise though.
// Doubt this is worth further support as I don't know how to support this for
// more than one extra feature, the INPUT_BUTTON# list is exhausted after this.
#define USE_ITEMS_PREDICTION_TEST 0
// See server copy for notes
#define OTHER_PREDICTION_TEST 2
///////////////////////////////////////////////////////////////////////////////

View File

@ -365,6 +365,8 @@ TS_View_DrawSpecialEffects_Weapon(
vector* recentLaserHitPosVar
)
{
const float drawAlpha = 1.0;
const vector lasColor = [1.0, 0, 0];
@ -473,6 +475,17 @@ TS_View_DrawSpecialEffects_Weapon(
void
TS_View_DrawExtraEffects(player pl, int thirdperson)
{
if(pl.inventoryEquippedIndex > -1){
weapondynamic_t dynaRef2 = pl.ary_myWeapons[pl.inventoryEquippedIndex];
//printfline("---TS_View_DrawSpecialEffects_Weapon--- %d", (float)((dynaRef2.iBitsUpgrade_on & BITS_WEAPONOPT_FLASHLIGHT) != 0));
//dynaRef2.iBitsUpgrade_on = 0;
}
//int thirdperson = (autocvar_cl_thirdperson == TRUE || this.entnum != player_localentnum);
//base_player pp = (base_player)this;

View File

@ -2,10 +2,15 @@
// SHARED CONFIG SETTING - set this consistently between client/server progs!
// If 0, nothing special.
// If 1, Makes some changes to enable prediction for useitems.
// Spams the turn-on click noise though.
// Doubt this is worth further support as I don't know how to support this for
// more than one extra feature, the INPUT_BUTTON# list is exhausted after this.
#define USE_ITEMS_PREDICTION_TEST 0
// See all mentions of this throughout the codebase for the places it changes.
// Mainly it adds a chunk that immitates FTE prediction at the end of
// ts/src/shared/input.qc, as a demonstration more than anything. This is likely
// overkill. This also stops sending the weapon's "iBitsUpgrade_on" in normal
// player.qc script and does so along custom inputframe updates in input.qc.
// If 2, use "input_impulse" instead. Well gee, look at that.
// Also comes with a separate check for playing the click noise as the
// 'input_sequence==clientcommandframe' check does not work like the custom version.
#define OTHER_PREDICTION_TEST 2
///////////////////////////////////////////////////////////////////////////////

View File

@ -100,3 +100,23 @@ void Weapons_Draw(void);
void Weapons_Holster(void);
#if OTHER_PREDICTION_TEST == 1
#ifdef CLIENT
// test
void Custom_Prediction_Server_Callback(player pl);
void Custom_Predict_EntityUpdate(player pl);
void Custom_Predict_PlayerPreFrame(player pl);
void Custom_Predict_PlayerPostFrame(player pl);
var float custom_input_sequence = 0;
var float custom_clientcommandframe = 0;
var float custom_servercommandframe = 0;
#else
var float custom_servercommandframe = 0;
void Custom_EvaluateEntity(player pl);
#endif
#elif OTHER_PREDICTION_TEST == 2
//var BOOL isFreshInput = FALSE;
#endif//OTHER_PREDICTION_TEST

View File

@ -623,8 +623,7 @@ TS_playerUseItems(void){
return;
}
#if USE_ITEMS_PREDICTION_TEST == 0
#if OTHER_PREDICTION_TEST == 0
#ifdef CLIENT
sendevent("TS_playerUseItems", "");
@ -639,8 +638,6 @@ TS_playerUseItems(void){
// always do this then
_TS_playerUseItems();
#endif
}
@ -723,7 +720,21 @@ _TS_playerUseItems(void){
// Let's be a clientside sound only.
#ifdef CLIENT
#if OTHER_PREDICTION_TEST == 1
// enforce a check that this is the first inputframe, not repeats, to avoid sound spam
if(custom_input_sequence==custom_clientcommandframe){
#elif OTHER_PREDICTION_TEST == 2
//if(input_sequence==clientcommandframe){
//if(isFreshInput){
if(0){ // never do it here, elsewhere instead
#else
// nothing special
if(1){
#endif
localsound("weapons/switch.wav", CHAN_AUTO, 1.0f);
}
#endif

View File

@ -15,6 +15,9 @@ enum EVENT_TS{
SOUNDPITCHED,
SOUNDPITCHED_CHANNEL,
USEITEMS_CHANGE_CALLBACK,
CUSTOM_PREDICTION_CALLBACK,
TEST,
};

View File

@ -15,13 +15,32 @@
*/
void processInputs(void);
#ifdef CLIENT
void PreSpawn_Input(void);
// externs
void HUD_DrawWeaponSelect_Trigger(void);
BOOL TS_HUD_CloseWeaponSelect(BOOL);
#endif
#if OTHER_PREDICTION_TEST == 1
float custom_input_buttons;
float ary_custom_input_buttons[512];
BOOL ary_custom_input_sentYet[512];
void Custom_Game_Input(void);
#endif
// WARNING! This is only called by PMove_Run, which is only called
// for spawned players. This is not called for players in spectator,
// so if script to check for clicking while in spectator with no menu
@ -333,27 +352,15 @@ Game_Input(void)
}
*/
#if USE_ITEMS_PREDICTION_TEST == 1
//INPUT_BUTTON2 reserved for jump...
//INPUT_BUTTON6
//INPUT_BUTTON7 (used for sneaking currently)
if(input_buttons & INPUT_BUTTON6){
//printfline("IM here what");
if( !(pl.gflags & GF_UNUSED3)){
TS_playerUseItems();
}
pl.gflags |= GF_UNUSED3;
}else{
pl.gflags &= ~GF_UNUSED3;
#if OTHER_PREDICTION_TEST == 2
if(input_impulse == 115){
TS_playerUseItems();
}
// great. So that won't even work.
//isFreshInput = FALSE;
#endif
}//Game_Input
@ -415,6 +422,8 @@ void processInputs(void){
#ifdef CLIENT
// called when not ingame for sending a spawn request.
@ -455,8 +464,55 @@ void PreSpawn_Input(void){
void HUD_DrawWeaponSelect_Trigger(void);
BOOL TS_HUD_CloseWeaponSelect(BOOL);
#ifdef CLIENT
// redirects from cmd.qc to be less of a mess over there.
void Input_useItems_press(void){
player pl = (player)pSeat->m_ePlayer;
#if OTHER_PREDICTION_TEST == 0
if( !(pl.gflags & GF_UNUSED3)){
TS_playerUseItems();
}
pl.gflags |= GF_UNUSED3;
#elif OTHER_PREDICTION_TEST == 1
pSeatLocal->m_bUseItems = TRUE;
#elif OTHER_PREDICTION_TEST == 2
pSeatLocal->m_bUseItems = TRUE;
//TAGGG - play the click only this once
if( !(pl.gflags & GF_UNUSED3)){
localsound("weapons/switch.wav", CHAN_AUTO, 1.0f);
}
pl.gflags |= GF_UNUSED3;
#endif
}//Input_useItems_press
void Input_useItems_release(void){
player pl = (player)pSeat->m_ePlayer;
#if OTHER_PREDICTION_TEST == 0
pl.gflags &= ~GF_UNUSED3;
#elif OTHER_PREDICTION_TEST == 1
pSeatLocal->m_bUseItems = FALSE;
#elif OTHER_PREDICTION_TEST == 2
pSeatLocal->m_bUseItems = FALSE;
pl.gflags &= ~GF_UNUSED3;
#endif
}//Input_useItems_release
#endif
// Not yet called by Nuclide! A series of notes for now
// (move to clientside files then)
@ -479,9 +535,11 @@ void ClientGame_Input_Frame(void){
// affecting other inputs like crouch is unnecessary, that causes the player to
// uncrouch if changing weapons while crouched.
player pl = (player)pSeat->m_ePlayer;
if(pl == NULL)return; // ???
if(pl.iState != PLAYER_STATE::SPAWNED && pSeatLocal->m_flUI_Display != UI_SCREEN::NONE){
// If buying, don't allow any movement inputs.
// The above is a similar check as "g_vguiWidgetCount > 0", but the buymenu does not
@ -512,23 +570,216 @@ void ClientGame_Input_Frame(void){
if (pSeatLocal->m_iInputSpeed == TRUE) {
input_buttons |= INPUT_BUTTON7;
//self.flags |= FL_SNEAK;
}else{
//self.flags &= ~FL_SNEAK;
}
//printfline("input_buttons: %d", (INPUT_BUTTON7 & input_buttons) );
#if USE_ITEMS_PREDICTION_TEST == 1
// NOTE - GF_UNUSED3 is being used for playing the toggle-switch sound in
//
#if OTHER_PREDICTION_TEST == 2
// using GF_UNUSED4 instead of GF_UNUSED3 because that one is
// being used to play the click-noise on toggling instead.
// Yes, really.
if(pSeatLocal->m_bUseItems){
//pSeatLocal->m_bUseItems = FALSE;
input_buttons |= INPUT_BUTTON6;
if( !(pl.gflags & GF_UNUSED4)){
input_impulse = 115;
//isFreshInput = TRUE;
}
pl.gflags |= GF_UNUSED4;
}else{
pl.gflags &= ~GF_UNUSED4;
}
#endif
}// ClientGame_InputFrame
#endif // CLIENT
//TAGGG - most of the alternate prediction demo.
// Replicates what's seen in Nuclide's src/predict.qc to make
// the toggle-options feature predicted without involving FTE's
// input_buttons.
//////////////////////////////////////////////////////////////////////////////////
#if OTHER_PREDICTION_TEST == 1
// Shared
void Custom_Game_Input(void){
player pl = (player)self;
if(custom_input_buttons == TRUE){
if( !(pl.gflags & GF_UNUSED3)){
//printfline("---CLICK---");
TS_playerUseItems();
}
pl.gflags |= GF_UNUSED3;
}else{
pl.gflags &= ~GF_UNUSED3;
}
}//Custom_Game_Input
#ifdef CLIENT
void Custom_ClientGame_Input_Frame(void){
if(pSeatLocal->m_bUseItems){
//pSeatLocal->m_bUseItems = FALSE;
//input_buttons |= INPUT_BUTTON6;
ary_custom_input_buttons[custom_clientcommandframe % 512] = TRUE;
}
if(!ary_custom_input_sentYet[custom_clientcommandframe % 512]){
sendevent("GSVRCC", "ff", custom_clientcommandframe, ary_custom_input_buttons[custom_clientcommandframe % 512]);
ary_custom_input_sentYet[custom_clientcommandframe % 512] = TRUE;
}
//printfline("CURRENT CLIENTCOMMAND FRAME: %d", custom_clientcommandframe);
// And refresh the entry in the queue somewhere before this point, so that
// loop-arounds don't cause issues from running into leftover/out-of-date
// memory being set but not being worth paying attention to.
float subtr = custom_clientcommandframe - 256;
if(subtr < 0){subtr += 512;}
float modulo = subtr % 512;
ary_custom_input_buttons[modulo] = 0;
ary_custom_input_sentYet[modulo] = FALSE;
}
void Custom_Predict_EntityUpdate(player pl){
if (pl.entnum == player_localentnum) {
/* run the player physics from the last approved servercommandframe to the current one */
for (int i = pl.custom_sequence+1; i <= custom_servercommandframe; i++) {
/* ...maybe the input state is too old? */
//if (!getinputstate(i)) {
// break;
//}
custom_input_sequence = i;
//pl.Physics_Run();
custom_input_buttons = ary_custom_input_buttons[custom_input_sequence % 512];
Custom_Game_Input();
}
}
pl.custom_sequence = custom_servercommandframe;
}
void Custom_Predict_PlayerPreFrame(player pl){
//printfline("---PREFRAME---");
for (int i = pl.custom_sequence + 1; i <= custom_clientcommandframe; i++) {
//float flSuccess = getinputstate(i);
//if (flSuccess == FALSE) {
// continue;
//}
if (i==custom_clientcommandframe){
//CSQC_Input_Frame();
Custom_ClientGame_Input_Frame();
}
/* don't do partial frames, aka incomplete input packets */
//if (input_timelength == 0) {
// break;
//}
/* this global is for our shared random number seed */
custom_input_sequence = i;
/* run our custom physics */
//pl.Physics_Run();
custom_input_buttons = ary_custom_input_buttons[custom_input_sequence % 512];
Custom_Game_Input();
}
custom_clientcommandframe++;
}
void Custom_Predict_PlayerPostFrame(player pl){
//printfline("---ROLLBACK---");
}
// called by server
void Custom_Prediction_Server_Callback(player pl){
float received_servercommandframe = readfloat();
custom_servercommandframe = received_servercommandframe;
if(pl != NULL){
Custom_Predict_EntityUpdate(pl);
}
if(pl != NULL){
int EXTRA = readint();
if(EXTRA > -1){
pl.ary_myWeapons[pl.inventoryEquippedIndex].iBitsUpgrade_on = EXTRA;
//pl.ary_myWeapons[pl.inventoryEquippedIndex].iBitsUpgrade_on_net = pl.ary_myWeapons[pl.inventoryEquippedIndex].iBitsUpgrade_on;
}
}
}
#endif
#else
// SERVER
// short for GameServer_RunClientCommand.
void
CSEv_GSVRCC_ff(float arg_scf, float arg_ibc){
//TS_playerUseItems();
custom_servercommandframe = arg_scf;
custom_input_buttons = arg_ibc;
Custom_Game_Input();
// send a message back!
player pl = (player)self;
WriteByte( MSG_MULTICAST, SVC_CGAMEPACKET );
WriteByte( MSG_MULTICAST, EVENT_TS::CUSTOM_PREDICTION_CALLBACK );
WriteFloat( MSG_MULTICAST, custom_servercommandframe );
if(pl.inventoryEquippedIndex > -1){
WriteInt( MSG_MULTICAST, pl.ary_myWeapons[pl.inventoryEquippedIndex].iBitsUpgrade_on );
}else{
WriteInt( MSG_MULTICAST, -1 );
}
msg_entity = pl;
multicast( [0,0,0], MULTICAST_ONE );
}
void Custom_EvaluateEntity(player pl){
// SAVE_STATE
//if(pl.inventoryEquippedIndex > -1){
// pl.ary_myWeapons[pl.inventoryEquippedIndex].iBitsUpgrade_on_net = pl.ary_myWeapons[pl.inventoryEquippedIndex].iBitsUpgrade_on;
//}
}
#endif// CLIENT vs. SERVER
#endif// OTHER_PREDICTION_TEST
//////////////////////////////////////////////////////////////////////////////////

View File

@ -44,6 +44,10 @@ enum PLAYER_STATE{
class player:base_player
{
#ifdef CLIENT
int custom_sequence;
#endif
// On death, the player cannot change the camera to fake-specator until at least 1 second
// has passed.
// On death, set this to 2.5. If it is less than 1.5,

View File

@ -69,6 +69,8 @@ player::ReceiveEntity(float new, float fl)
{
/* the generic client attributes */
base_player::ReceiveEntity(new, fl);
/* animation */
if (fl & PLAYER_TOPFRAME) {
@ -324,7 +326,9 @@ void player::ReceiveEntity_ary_myWeapons(int i){
//ary_myWeapons[i].iSlots = readbyte();
ary_myWeapons[i].iClipLeft = readbyte();
ary_myWeapons[i].iClipAkimboLeft = readbyte();
#if OTHER_PREDICTION_TEST != 1
ary_myWeapons[i].iBitsUpgrade_on = readbyte();
#endif
int newFir = readbyte();
@ -471,6 +475,12 @@ player::PredictPreFrame(void)
// reach the Nuclide logic looking at it in time to be applied.
// No need here now I think?
//this.viewzoom = this.flZoomCurrent;
#if OTHER_PREDICTION_TEST == 1
Custom_Predict_PlayerPreFrame(this);
#endif
}
/*
@ -485,7 +495,6 @@ player::PredictPostFrame(void)
{
//printfline("---PREDICT POST FRAME");
/*
#ifdef CLIENT
if(iState == PLAYER_STATE::SPAWNED){
@ -603,8 +612,13 @@ player::PredictPostFrame(void)
ROLL_BACK_ARY(ary_ammoTotal, i);
}
#if OTHER_PREDICTION_TEST == 1
Custom_Predict_PlayerPostFrame(this);
#endif
}
#else
void
player::EvaluateEntity(void)
@ -830,6 +844,11 @@ player::EvaluateEntity(void)
}
}
#if OTHER_PREDICTION_TEST == 1
Custom_EvaluateEntity(this);
#endif
}
/*
@ -1011,8 +1030,6 @@ player::SendEntity(entity ePEnt, float fChanged)
// no need to send again until this flag is set freshly.
this.completeInventorySend = FALSE;
return (1);
}
@ -1025,7 +1042,9 @@ void player::SendEntity_ary_myWeapons(int i){
//WriteByte(MSG_ENTITY, ary_myWeapons[i].iSlots );
WriteByte(MSG_ENTITY, ary_myWeapons[i].iClipLeft );
WriteByte(MSG_ENTITY, ary_myWeapons[i].iClipAkimboLeft );
#if OTHER_PREDICTION_TEST != 1
WriteByte(MSG_ENTITY, ary_myWeapons[i].iBitsUpgrade_on );
#endif
WriteByte(MSG_ENTITY, ary_myWeapons[i].iFireMode );
WriteByte(MSG_ENTITY, ary_myWeapons[i].iFireModeAkimbo );
WriteByte(MSG_ENTITY, ary_myWeapons[i].iIronSight );