Odd SE problem - need help ! [solved]

The place to discuss scripting and game modifications for X³: Reunion.

Moderators: Moderators for English X Forum, Scripting / Modding Moderators

Post Reply
User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Odd SE problem - need help ! [solved]

Post by euclid » Fri, 17. Nov 06, 17:53

After a script call with return variable $c and parameters $a and $b, the value of parameter $b has changed.

How is this possible?


Cheers Euclid

Edit: solved - please scroll down. E.
Last edited by euclid on Sat, 18. Nov 06, 02:24, edited 1 time in total.

Cycrow
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 22227
Joined: Sun, 14. Nov 04, 23:26
x4

Post by Cycrow » Fri, 17. Nov 06, 18:47

you cant pass value by reference in scripts.

but there are 2 ways you can do it, add the values to the array and pass the array, the arrays should be passed by reference.

the other way is to use global or local varibles

Code: Select all

set global varible 'b' value = 1
$c = call script 'script' a = $a
$b = global varible 'b'

User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Post by euclid » Fri, 17. Nov 06, 18:57

I'm not sure what you mean.

Code: Select all

008   $h = $b
009   write to player logbook $b
010   write to player logbook $h
011 @ $c = [THIS] -> call script 'divide' :  integer or floating point array=$a   integer or floating point array=$b
012   write to player logbook $b
013   write to player logbook $h
The return variable $c has the correct value so the script call works. However the values of $h and $b have changed; not $a though.

IMHO the value of the parameters $a and $b should not be altered by the script call.

Or am I wrong?

Cheers Euclid

Cycrow
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 22227
Joined: Sun, 14. Nov 04, 23:26
x4

Post by Cycrow » Fri, 17. Nov 06, 19:11

what values to you get before and after the call for $b and $h ?

User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Post by euclid » Fri, 17. Nov 06, 19:21

Before $b=$h=ARRAY(1,11,0) and after the call $b=$h=ARRAY(1,909090909,1)

The curious thing is that the value 909090909 is calculated in 'divide' as part of 1/11 = 0.090909090.... but why (and how) does this value get in $b$, and more strangely why is it in $h after the call?


Cheers Euclid

User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Post by euclid » Fri, 17. Nov 06, 20:47

It is utterly strange. The script 'divide' (part of my floating point math lib) seems to cause a change of the value of the second parameter.

The simple test script

Code: Select all

001   $x = 39
002   $y = 11
003 @ $a = [THIS] -> call script 'int2float' :  integer=$y
004   $mes = 'x= %s and y= %s before divide call'
005   write to player logbook: printf: fmt=$mes, $x, $a, null, null, null
006 @ $z = [THIS] -> call script 'divide' :  integer or floating point array=$x   integer or floating point array=$a
007   $mes = 'After divide call: x= %s , y= %s and z= %s'
008   write to player logbook: printf: fmt=$mes, $x, $a, $z, null, null
009   return null
run on null gives log entries in chronological order:
>>
x=39 and y=ARRAY(1,11,0) before divide call

After divide call: x=39, y=ARRAY(1,909090909,0) and z=ARRAY(1,354545453,-8)
<<

Clearly the script call has changed the script parameter y from (1,11,0) to (1,909090909,1). Strange thing is that the number at $y[1]$ is computed in by the script 'divide' as part of 1/11 = 909090909E-10.


Only the second parameter causes trouble and only if it is an array.


Very odd !!


Cheers Euclid

Cycrow
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 22227
Joined: Sun, 14. Nov 04, 23:26
x4

Post by Cycrow » Fri, 17. Nov 06, 21:04

Well, arrays are passed by reference, so if you change the array in the calling script, it will change in the parent.

im guessing your doing something with the array in the divide script ?

could you post ur divide script

User avatar
Stevio
Posts: 2271
Joined: Sat, 4. Jun 05, 10:36
x3tc

Post by Stevio » Fri, 17. Nov 06, 21:08

looking throught the int2float

the lines 004 and 005 are confusing...

Code: Select all

001   $a =  array alloc: size=3
002   $s = 1
003   if $num < 0
004    $s = - 1
005    $num = - $num
006   end
...
i think you are trying to suggest negative numbers... {$s = (negative) -1)
which you cannot do with the 'subtract (-)' command


is this correct?

Cycrow
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 22227
Joined: Sun, 14. Nov 04, 23:26
x4

Post by Cycrow » Fri, 17. Nov 06, 21:13

no, thats fine, it jsut assumes that your doing 0 - something if you do that

so that will set the value to -1

i just prefer using 0 - $value, but essentially they are the same

User avatar
Stevio
Posts: 2271
Joined: Sat, 4. Jun 05, 10:36
x3tc

Post by Stevio » Fri, 17. Nov 06, 21:15

oh yeah, silly me :oops: :P :lol:

User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Post by euclid » Fri, 17. Nov 06, 21:17

Cycrow wrote:Well, arrays are passed by reference, so if you change the array in the calling script, it will change in the parent.....
Uhm, so just to get that right:

Say, I have an array $y in the main script. If this main script calles a subscript where also the name $y is used and the value gets changed there, then the value is also changed in the main script?


Cheers Euclid

Cycrow
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 22227
Joined: Sun, 14. Nov 04, 23:26
x4

Post by Cycrow » Fri, 17. Nov 06, 21:22

what i ment, is if you passs the array to the subscript and change the array in the subscript, it will change in the calling script as well.

simply using the same varible names shouldn't cause the change.

thats y it would help to see the divide script, to c if theres anything there that might be changing the value

User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Post by euclid » Fri, 17. Nov 06, 21:32

Originally I've used $q in the divide script but to trace the bug I've changed that to:

Code: Select all

Arguments
1: p , Var/Number , 'integer or floating point array' 
2: q , Var/Number , ' integer or floating point array' 
Source Text

001   $s =  size of array $p
002   $pp = $p
003   skip if $s > 1
004 @  $pp = [THIS] -> call script 'int2float' :  integer=$p
005   $s =  size of array $q
006   $qq = $q
007   skip if $s > 1
008 @  $qq = [THIS] -> call script 'int2float' :  integer=$q
009   * gcd first
010   $s = $pp[1]
011   $t = $qq[1]
012 @ $g = [THIS] -> call script 'gcd' :  first number=$s  second number=$t  output as array=[TRUE]
013   $pp[1] = $g[1]
014   $qq[1] = $g[2]
015   * gcd ends
016   $s = $qq[1]
017 @ $bb = [THIS] -> call script 'invert' :  integer=$s
018   $qq[1] = $bb[1]
019   $s = $bb[2]
020   $t = $qq[2]
021   $t = $s - $t
022   $qq[2] = $t
023 @ $bb = [THIS] -> call script 'prod' :  number 1=$pp  number 2=$qq
024   return $bb
Still the same.


Cheers Euclid

User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Post by euclid » Sat, 18. Nov 06, 02:23

Cycrow wrote:Well, arrays are passed by reference, so if you change the array in the calling script, it will change in the parent.....
Sorry for being so slow (was chasing this bug through the night) but it took a chat with AalaarDB (big thanks) to set my head straight.


'arrays are passed by reference......strings and numbers by their value.'


Everbody kept saying that and didn't get it. But now it makes sense to me and maybe the following prevent some from chasing this 'bug' (more a feature?) like I did :

Passing can be done in various ways for example $A=$B is passing $B to $A.
Also script calls pass their parameters to the called script. For example this..

@ $c = [THIS] -> call script 'prod' : number 1=$a number 2=$b

...script call has 2 parameters $a and $b which are passed to the called script's arguments (inputs). The called script returns the result $c.

And, of course you can use these parameters within the script (arguments). In fact you do use these because you would not expect that changes made in the subscript are passed back to the parameters of the called subscript.

Why would $a or $b have changed after the script call above?

If the passed objects are strings or numbers then the above script call will not change $a and $b. But this is not so for arrays.

While for strings & numbers $A=$B copies $B to A$ for arrays only a reference (to the parameter in the calling script) is forwarded from $B to $A. So any changes made in $A will be back referenced via $B to the source array (in the above case the parameters $a and $b of the called script).

In fact, one could return the result $c without the '$return$c' in the called script by

@ [THIS] -> call script 'prod' : number 1=$a number 2=$b

and pass in 'prod' the result to $a.


But in some case (*sigh*) one likes to keep $a and $b so how to prevent that 'overwriting by reference'?

In the subscript the inputs (arguments) containing the reference have to be cloned first

$n = size of array $a
$n = n - 1
$ca = clone array $a: index 0 ...$n
....
....

and then the clones $ca,.. are used rather than the reference carrier $a and $b.



So, thanks again for your input :thumb_up: (back to work.......)


Cheers Euclid

Cycrow
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 22227
Joined: Sun, 14. Nov 04, 23:26
x4

Post by Cycrow » Sat, 18. Nov 06, 03:11

yeah i can c where you made the mistake.

i guess it helps to understand how pointers work in C/C++

its all about memory addresses, ur simply changing whats in a set memory space.

the main difference with scripting and C, is that certain values are always like pointers, but in C you can choose if they are value or pointers

jlehtone
Posts: 21809
Joined: Sat, 23. Apr 05, 21:42
x4

Post by jlehtone » Sat, 18. Nov 06, 07:48

Yes, 'by value' means 'make a copy', while 'by reference' is like 'this name refers to that variable'. By reference avoids the copy and is thus more efficient way to pass arguments. But then, like in this case, one may need an additional temporary variable.

References can lead to 'aliasing'. A wonderful way to shoot oneself into foot.

Try passing the same array as both arguments to your unfixed 'divide'. By now you should be able to deduce what will happen. Fortran has never even allowed that. C99 standard added argument qualifiers to prevent it.

I guess the SE lacks 'const reference'.

User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Post by euclid » Tue, 21. Nov 06, 16:55

I wonder what happens if an array is passed to a global variable.

If the global variable just containes the reference it would make little sense because it can be called (get global variable) at any time later by any other script and hence the original array is gone.

Cheers Euclid

Cycrow
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 22227
Joined: Sun, 14. Nov 04, 23:26
x4

Post by Cycrow » Tue, 21. Nov 06, 17:56

the global varible also holds the reference of to the array.

so you can assign it to a varible and have another script use the array without it having to be passed in the first place.

also, any changes to the array are saved.

if you do something like

Script 1:

Code: Select all

$array = alloc array: size = 2
set global varible 'mu.array' balue = $array
= call script 'script 2'
$size = size of array $array
then another complety seperate scripts can also access the array.

Script 2:

Code: Select all

$array = get global varible 'my.array'
append $value to array $array
you will find that the size from the first script is 3 after the call script.

remember the global varibles only store the reference, if you set the varible to something else, it wont effect the array, only the references thats stored in the global varible

User avatar
euclid
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 13293
Joined: Sun, 15. Feb 04, 20:12
x4

Post by euclid » Tue, 21. Nov 06, 20:10

Thanks Cycrow,

It's about Gnasirator's MK3 optimization.

Code: Select all

001   * Init
002   $gained.total.delta = 0
003   $gained.total.delta.perHour = 0
004   $gained.total.perHour = 0
005   $timestamp = get global variable: name='plugin.autotrade.timestamp'
006   $timestamp.now = playing time
007   skip if $timestamp
008    $timestamp = $timestamp.now
009   $Stats = get global variable: name='plugin.autotrade.stats'
010   $PageID = get global variable: name='autotrade.PageID'
011   $log = null
012   
013   * Spielerschiffe finden und UniTrader filtern
014   $traders =  get ship array: of race Player class/type=null
015   $size.traders =  size of array $traders
016   
017   while $size.traders
018   *= wait randomly from 1 to 3 ms
019    dec $size.traders = 
020    $test.ship = $traders[$size.traders]
021    $exp = $test.ship -> get local variable: name='experience'
022    $mk3 = $test.ship -> get amount of ware Handelssoftware Mk3 in cargo bay
023    skip if $mk3 AND $exp
024     remove element from array $traders at index $size.traders
025   end
026   
027   if  size of array $traders
028    $size.traders =  size of array $traders
029    $data =  array alloc: size=2
030    $stats.new =  array alloc: size=$size.traders
031    $i = 0
032    
033    while $i < $size.traders
034 @   = wait randomly from 50 to 150 ms
035     $test.ship = $traders[$i]
036     $trader.new.gained = $test.ship -> get local variable: name='Gain'
037     $data[0] = $test.ship
038     $data[1] = $trader.new.gained
039     $stats.new[$i] = $data
040     inc $i = 
041    end
042    
043   * Array stats.new enthaelt nun alle aktuellen MK3 Haendler und deren Gained
044    
045   * Beinhaltet den gesamten verdienst seit beginn jeglicher unitrader
046    $gained.total = 0
047   * stats.new jetzt schon speichern, da es nun veraendert wird.
048    gosub refresh
049   * Erste Ausfuhrung der Statistikfunktion
050    if $Stats != null
051     $size.stats.new =  size of array $stats.new
052   * Alten und neuen Array vergleichen, ob noch dieselben Schiffe vorhanden sind
053     
054     while $size.stats.new
055 @    = wait randomly from 50 to 150 ms
056      dec $size.stats.new = 
057      $test.ship = $stats.new[$size.stats.new][0]
058      $tempgained = $test.ship -> get local variable: name='Gain'
059      $gained.total = $gained.total + $tempgained
060      
061   * returns -1 if not found
062   *$index.in.oldstats =  get index of $test.ship in array $Stats offset=-1 + 1
063      $size.stats.old =  size of array $Stats
064      $index.in.oldstats = -1
065      while $size.stats.old AND $index.in.oldstats < 0
066       dec $size.stats.old = 
067 @     = wait randomly from 50 to 150 ms
068       $test.ship.old = $Stats[$size.stats.old][0]
069       skip if not $test.ship.old AND $test.ship.old == $test.ship
070        $index.in.oldstats = $size.stats.old
071      end
072      
073      if $index.in.oldstats >= 0
074       $trader.old.gained = $Stats[$index.in.oldstats][1]
075       $test.ship.old = $Stats[$index.in.oldstats][0]
076       $trader.new.gained = $stats.new[$size.stats.new][1]
077       $trader.new.gained = $trader.new.gained - $trader.old.gained
078       $stats.new[$size.stats.new][1] = $trader.new.gained
079      end
080     end
081    end
082    
083   * Zwischenstand:
084   * Alle in Stats enthaltenen Schiffe sind auch in stats.new
085   * Gained neu = Gained neu - Gained alt
086   * Neue Schiffe sind in stats.new aber nicht in Stats
087    
088   calculate:
089   * Time
090    $time.diff = $timestamp.now - $timestamp
091    $time.diff.secs = $time.diff mod 60
092    $time.diff.min = ( $time.diff mod 3600 ) / 60
093    $time.diff.hour = $time.diff / 3600
094    $timestamp.sec = $timestamp.now mod 60
095    $timestamp.min = ( $timestamp.now mod 3600 ) / 60
096    $timestamp.hour = $timestamp.now / 3600
097   * Beinhalten den Gesamtverdienst seit letzter Statistikabfrage
098    $gained.total.delta = 0
099    
100    $size.stats.new =  size of array $stats.new
101    $i = 0
102    while $i < $size.stats.new
103     $tempgained = $stats.new[$i][1]
104     $gained.total.delta = $gained.total.delta + $tempgained
105     inc $i = 
106    end
107    $gained.total.delta.perHour = $gained.total.delta / $time.diff * 3600
108    skip if $gained.total.delta.perHour
109     $gained.total.delta.perHour = 0
110    $gained.total.perHour = $gained.total / $timestamp.now * 3600
111   end
112   * end if traders
113   
114   endit:
115   gosub output
116   return null
117   
118   output:
119   if $timestamp > 0
120    $log = sprintf: pageid=$PageID textid=300, $time.diff.hour, $time.diff.min, $time.diff.secs, null, null
121   else
122    $log = sprintf: pageid=$PageID textid=301, null, null, null, null, null
123   end
124   $dummy = sprintf: pageid=$PageID textid=303, $timestamp.hour, $timestamp.min, $timestamp.sec, null, null
125   $log = $log + $dummy
126   $dummy = sprintf: pageid=$PageID textid=302, $gained.total, $gained.total.delta, $gained.total.perHour, $gained.total.delta.perHour, null
127   $log = $log + $dummy
128   write to player logbook $log
129   endsub
130   return null
131   
132   breakpoint:
133   [THIS] -> set destination to [PLAYERSHIP]
134 @ = wait 10000 ms
135   $data = $stats.new[0]
136   $data = $Stats[0]
137   endsub
138   return null
139   
140   refresh:
141   set global variable: name='plugin.autotrade.timestamp' value=$timestamp.now
142   gosub breakpoint
143   set global variable: name='plugin.autotrade.stats' value=$stats.new
144   endsub
145   return null
146   
147   failure:
148   write to player logbook 'Statistikfehler'
149   return null
The array $Stats (global variable plugin.autotrade.stats) is read correctly only once. Second read (get global variable) it contains zeros.

I wonder if this could be due to an overwrite by reference?

Cheers Euclid

Post Reply

Return to “X³: Reunion - Scripts and Modding”