Strange FindPlayer, Player.Cash issue

Rhytz

  • Newbie
  • Posts: 11
Strange FindPlayer, Player.Cash issue
« on April 14th, 2017, 02:09 PM »Last edited on April 14th, 2017, 07:23 PM
I'm actually having this issue on LU, but I was advised to ask here since we couldn't figure it out.

So I'm creating this minigame script, and at the end of each minigame, every participating player gets paid a certain amount of money depending on how well they played (0.8x of what the previous player got).

Edit, pastebin'd for better readabilty: https://pastebin.com/y0Rn3Fnm
Code: [Select]
function payoutPlayers(){
local topArray = [];
foreach(id, score in playerScores){
if(score > 0){
topArray.push({id = id, score = score});
}
}

topArray.sort(sortScores);
local _payout = currentMinigame.payout;
foreach(pos, scoreinfo in topArray){
local _player = FindPlayer(scoreinfo.id);
if(_player){
local realpos = pos + 1;
//_player.Cash += _payout;
BigMessage(_player, "You came " + realpos + " in the " + currentMinigame.name, 5000, 3);
_payout = abs(_payout * 0.8);
}
_player = null;
}
}

So this code works, until you uncomment the _player.Cash += _payout; line. Then only the first iteration will succeed, and it will error on the second one. For some reason when that line is uncommented, _player is set to the player ID(int), instead of a Player reference.

Here's testing with that line commented out, and some debug prints. All works fine:
Code: [Select]
SCRIPT: before if(_player): Theremin
SCRIPT: before _player.Cash: Theremin
SCRIPT: Cash: 18005 _player: Theremin(Player)pos: 1 payout: 15000(integer)
SCRIPT: before BigMessage: Theremin
SCRIPT: Cash: 18005 _player: Theremin(Player)pos: 1 payout: 15000(integer)
SCRIPT: before if(_player): Rhytz
SCRIPT: before _player.Cash: Rhytz
SCRIPT: Cash: 4054 _player: Rhytz(Player)pos: 2 payout: 12000(integer)
SCRIPT: before BigMessage: Rhytz
SCRIPT: Cash: 4054 _player: Rhytz(Player)pos: 2 payout: 12000(integer)
SCRIPT: [lu-minigames] Minigame ended

However, when I uncomment the _player.Cash += _payout; line, this is what I get:
Code: [Select]
SCRIPT: before if(_player): Theremin
SCRIPT: before _player.Cash: Theremin
SCRIPT: Cash: 18005 _player: Theremin(Player)pos: 1 payout: 15000(integer)
SCRIPT: before BigMessage: Theremin
SCRIPT: Cash: 33005 _player: Theremin(Player)pos: 1 payout: 15000(integer)
SCRIPT: before if(_player): 1
SCRIPT: before _player.Cash: 1

AN ERROR HAS OCCURED [the index 'Cash' does not exist]

CALLSTACK
*FUNCTION [payoutPlayers()] Scripts/lu-minigames/main_s.nut line [164]
*FUNCTION [stopMinigame()] Scripts/lu-minigames/main_s.nut line [141]

LOCALS
[playerScores] ARRAY
[currentMinigame] TABLE
[realpos] 2
[_player] 1
[@[email protected]] 2
[scoreinfo] TABLE
[pos] 1
[_payout] 12000
[topArray] ARRAY
[this] TABLE
[minigameState] "ended"
[eligiblePlayers] TABLE
[currentMinigame] TABLE
[this] TABLE

So can anyone tell if there is something wrong with my code? Or have a run into an unfortunate LU bug?

Hoping someone can help

KAKAN

  • Wiki Contributor
  • Posts: 3,343
Re: Strange FindPlayer, Player.Cash issue
« Reply #1, on April 14th, 2017, 04:42 PM »
Code: [Select]
AN ERROR HAS OCCURED [the index 'Cash' does not exist]

CALLSTACK
*FUNCTION [payoutPlayers()] Scripts/lu-minigames/main_s.nut line [164]
*FUNCTION [stopMinigame()] Scripts/lu-minigames/main_s.nut line [141]

LOCALS
[playerScores] ARRAY
[currentMinigame] TABLE
[realpos] 2
[_player] 1
[@[email protected]] 2
[scoreinfo] TABLE
[pos] 1
[_payout] 12000
[topArray] ARRAY
[this] TABLE
[minigameState] "ended"
[eligiblePlayers] TABLE
[currentMinigame] TABLE
[this] TABLE
See the LOCALS section.
_player is 1, it should be a instance instead.
So, try removing the _player = null; from your code and give it a try. I know this is a really stupid thing to do. But, you know, VCMP and LU( Squirrel too, sometimes ) give unexpected results :)
And, try this one as well, dunno for sure, but might do the trick :)
Code: [Select]
https://pastebin.com/uqQ1agtV
I've ran into similar problem and that solved the thing, still dunno how.
oh no

Rhytz

  • Newbie
  • Posts: 11
Re: Strange FindPlayer, Player.Cash issue
« Reply #2, on April 14th, 2017, 05:07 PM »Last edited on April 14th, 2017, 05:52 PM
I added _player = null; in an attempt to fix the issue, but it didn't help unfortunately. I think FindPlayer must be returning that 1, after _player.Cash is called in the previous iteration.

I have no clue where else that 1 could come from?

Again, the code works fine without the _player.Cash += _payout; line... Then the _player variable contains a valid Player instance in every iteration, and every player sees the BigMessage. With that line, only the first player gets to see the BigMessage, AND gets the money, but the loop errors and halts on the second iteration.

Edit: didnt see your pastebin fix, gonna test, ty!
Re: Strange FindPlayer, Player.Cash issue
« Reply #3, on April 14th, 2017, 07:19 PM »Last edited on April 14th, 2017, 07:22 PM
Unfortunately the problem persisted using that code, and whatever i tried. So I'm now resorting to a somewhat gross workaround, but it does the job.

Code: [Select]
NewTimer("delayedCash", realpos * 100, 1, _player, _payout);

function delayedCash(player, cash){
player.Cash += cash;
}

So here's the finished product:
Code: [Select]
function payoutPlayers(){
local topArray = [];
foreach(id, score in playerScores){
if(score > 0){
topArray.push({id = id, score = score});
}
}

topArray.sort(sortScores);
local _payout = currentMinigame.payout;
foreach(pos, scoreinfo in topArray){
local _player = FindPlayer(scoreinfo.id);
if(typeof(_player) != "Player") _player = FindPlayer( scoreinfo.id );

if(_player && typeof(_player) == "Player"){ 
local realpos = pos + 1;
//_player.Cash += _payout; //Why does this not work!!!!??!?!?
//Delay the payout, this does seem to work
NewTimer("delayedCash", realpos * 100, 1, _player, _payout);
BigMessage(_player, "You came " + realpos + " in the " + currentMinigame.name, 5000, 3);
_payout = abs(_payout * 0.8);
}else{
print("Error retrieving player for payout");
}
}
}

function delayedCash(player, cash){
player.Cash += cash;
}

If anyone has a more solid solution than what I did, I'm all ears  :)

kennedyarz

  • Sr. Member
  • Making American Great Again
  • Posts: 334
Re: Strange FindPlayer, Player.Cash issue
« Reply #4, on April 15th, 2017, 01:26 AM »
Quote from Rhytz on April 14th, 2017, 07:19 PM
if(typeof(_player) != "Player") _player = FindPlayer( scoreinfo.id );
      if(_player && typeof(_player) == "Player")      

Hi, I do not know anything about LU, but you could not deal with those capital letters?

EK.IceFlake

  • Hero Member
  • "We are the champions my fellahs" - Sufyan/VK.SuFy
  • Posts: 1,761
Re: Strange FindPlayer, Player.Cash issue
« Reply #5, on April 15th, 2017, 05:05 AM »
A much more solid workaround would be to keep an array of every online player with their instance:
Code: [Select]
players <- {};
Code: [Select]
function LUEventForPlayerJoin(player)
{
    players.rawset(player.ID, player);
}
Code: [Select]
function LUEventForPlayerLeave(player)
{
    players.rawdelete(player.ID);
}
Code: [Select]
function MegaFindPlayer(playerid)
{
    if (players.rawin(playerid)) return players[playerid];
    else return null;
}

KAKAN

  • Wiki Contributor
  • Posts: 3,343
Re: Strange FindPlayer, Player.Cash issue
« Reply #6, on April 15th, 2017, 08:34 AM »
Quote from Rhytz on April 14th, 2017, 07:19 PM
Unfortunately the problem persisted using that code, and whatever i tried. So I'm now resorting to a somewhat gross workaround, but it does the job.

Code: [Select]
NewTimer("delayedCash", realpos * 100, 1, _player, _payout);

function delayedCash(player, cash){
player.Cash += cash;
}

So here's the finished product:
Code: [Select]
function payoutPlayers(){
local topArray = [];
foreach(id, score in playerScores){
if(score > 0){
topArray.push({id = id, score = score});
}
}

topArray.sort(sortScores);
local _payout = currentMinigame.payout;
foreach(pos, scoreinfo in topArray){
local _player = FindPlayer(scoreinfo.id);
if(typeof(_player) != "Player") _player = FindPlayer( scoreinfo.id );

if(_player && typeof(_player) == "Player"){ 
local realpos = pos + 1;
//_player.Cash += _payout; //Why does this not work!!!!??!?!?
//Delay the payout, this does seem to work
NewTimer("delayedCash", realpos * 100, 1, _player, _payout);
BigMessage(_player, "You came " + realpos + " in the " + currentMinigame.name, 5000, 3);
_payout = abs(_payout * 0.8);
}else{
print("Error retrieving player for payout");
}
}
}

function delayedCash(player, cash){
player.Cash += cash;
}

If anyone has a more solid solution than what I did, I'm all ears  :)
an idea: Use findplayer again to set player's cash. Something like:
FindPlayer( whatever).Cash
It should work as we already know that the player exists haha
oh no

vito

  • Sr. Member
  • Posts: 405

KAKAN

  • Wiki Contributor
  • Posts: 3,343
oh no

Rhytz

  • Newbie
  • Posts: 11
Re: Strange FindPlayer, Player.Cash issue
« Reply #9, on April 15th, 2017, 11:47 AM »
Quote from EK.IceFlake on April 15th, 2017, 05:05 AM
A much more solid workaround would be to keep an array of every online player with their instance
Good stuff, woke up today with my mind all cleared up and a similar idea... Why am I not simply storing the player instance in the array, so I don't need FindPlayer(). Gonna try that, thanks!
Quote from kennedyarz on April 15th, 2017, 01:26 AM
Hi, I do not know anything about LU, but you could not deal with those capital letters?
typeof(_player) returns "Player"
Quote from KAKAN on April 15th, 2017, 10:17 AM
LU works with that. See the first code. That's the thing.
Yeah i prefixed the variables with an underscore just in case something else in the script was interfering with those variables (i use player and payout variables elsewhere)

Anyway thanks for the help guys, gonna poke around with it and see if I can create a better solution. Will report back in!

KAKAN

  • Wiki Contributor
  • Posts: 3,343
Re: Strange FindPlayer, Player.Cash issue
« Reply #10, on April 15th, 2017, 12:24 PM »Last edited on April 15th, 2017, 12:26 PM
Quote from Rhytz on April 15th, 2017, 11:47 AM
Anyway thanks for the help guys, gonna poke around with it and see if I can create a better solution. Will report back in!
um, you forgot this?
Quote from KAKAN on April 15th, 2017, 08:34 AM
an idea: Use findplayer again to set player's cash. Something like:
FindPlayer( whatever).Cash
It should work as we already know that the player exists haha
Here's the code:
Code: [Select]
function payoutPlayers(){
local topArray = [];
foreach(id, score in playerScores){
if(score > 0){
topArray.push({id = id, score = score});
}
}

topArray.sort(sortScores);
local _payout = currentMinigame.payout;
foreach(pos, scoreinfo in topArray){
local _player = FindPlayer(scoreinfo.id);
if(_player && typeof _player == "Player"){
local realpos = pos + 1;
FindPlayer(scoreinfo.id).Cash += _payout;
BigMessage(_player, "You came " + realpos + " in the " + currentMinigame.name, 5000, 3);
_payout = abs(_payout * 0.8);
}
else
print("Nope.");
}
}
oh no

Rhytz

  • Newbie
  • Posts: 11
Re: Strange FindPlayer, Player.Cash issue
« Reply #11, on April 15th, 2017, 01:02 PM »
Quote from KAKAN on April 15th, 2017, 12:24 PM
um, you forgot this?
I refactored the code so I wouldn't have to rely on FindPlayer and the player ID to get the player instance. Now when a player scores his first point, his player instance is added to the playerScores array. Now it all works fine, without the ugly timer, and without FindPlayer :)

Here's the final code:
Code: [Select]
function payoutPlayers(){
local topArray = [];
foreach(scoreinfo in playerScores){
if(scoreinfo){
topArray.push({player = scoreinfo.player, score = scoreinfo.score});
}
}

topArray.sort(sortScores);
local _payout = currentMinigame.payout;
foreach(pos, scoreinfo in topArray){
if(scoreinfo.player){ 
local realpos = GetNth(pos + 1);
scoreinfo.player.Cash += _payout;
BigMessage(scoreinfo.player, "You came " + realpos + " in " + currentMinigame.name, 5000, 3);
_payout = abs(_payout * 0.8);
}
}
}

Here's a little preview of the script in action:

EK.IceFlake

  • Hero Member
  • "We are the champions my fellahs" - Sufyan/VK.SuFy
  • Posts: 1,761

Rhytz

  • Newbie
  • Posts: 11
Re: Strange FindPlayer, Player.Cash issue
« Reply #13, on April 24th, 2017, 08:09 PM »
If by that you mean indent it properly... For some reason the [ code ] tag gets rid of my indentation. It still looks right in the preview though