Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

SecondLife scripting vs WoW scripting

Rhysling Greenacre
Registered User
Join date: 15 Nov 2003
Posts: 132
11-21-2005 17:17
what kind of scripting do you prefer? i'll elaborate.

in secondlife scripting you have states.

state MoveToPosition
{
//...
goto state MovingToPosition;
}

state MovingToPosition
{
//...
goto state AtPosition;
}

state AtPosition
{
//...
}

In WoW you don't have states, so you'd register a callback to an update function that fires each tick:

RegisterEvent("OnUpdate";);
var state = "move_to_position";
function update()
{
if state == "move_to_position"
//...
if state == "moving"
//...
if state == "at position"
//...
}
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
11-21-2005 21:57
You could essentially emulate WoW style states in LSL very easily.

CODE

string gState;

myFunction() {
if (gState == "move_to_position") {

} else if (gState == "moving") {

} else if (gState == "at position") {

}
}

default {
touch_start(integer tn) {
gState = "move_to_position";
myFunction();
}
}

Of course, Im probably vastly oversimplifying.
I actually prefer LSL's model to WoW's (from what you describe it as) because there seems to be more compile time checking - in WoW there's no telling whether you accidentally misspell one of the state's names in your conditional statements without meticulously checking each one. It really depends upon how you organize your code though.
==Chris
Rhysling Greenacre
Registered User
Join date: 15 Nov 2003
Posts: 132
11-22-2005 09:48
Actually the reason I asked is because I'm making a 2D game engine with a Lua scripting interface. I'm thinking of having a setState("state";) function that would exit the current function and start running the state() function. Lua is just so gosh darned cool! You can even do microthreads (greenthreads) in it! :D
Jarod Godel
Utilitarian
Join date: 6 Nov 2003
Posts: 729
11-22-2005 10:33
What can you script in WoW? I've never played WoW, but macros and keybinds in CoH/CoV fascinate me -- if you do it right, Mastermind'ing can almost be a state-based system.
_____________________
"All designers in SL need to be aware of the fact that there are now quite simple methods of complete texture theft in SL that are impossible to stop..." - Cristiano Midnight

Ad aspera per intelligentem prohibitus.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
11-22-2005 11:56
The way LSL handles states and events is pretty cool.
  1. Global Event Mask
  2. Active State
  3. State Table
    1. State A Lookup Table Address
      1. State A Event Mask

    2. State B Lookup Table Address
      1. State B Event Mask


  4. State A Event Lookup Table
  5. State B Event Lookup Table


Basicly when an event is generated a 64bit flag identifies the event which is then compaired with the global mask; then it is compaired against the active state mask; finaly it counts the number of active bits in the mask before (and included) the events flag. Then it calls the event handler (like you would a function) at the address indicated by the counter (though the actual calling isn't handled in the script; this part, thank god, has been built into the VM). It's a nice tight format that could really do with a optimizing compiler.

If anyone is interested i'll post the actual file formating (but not the bytecode info).
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Lindsey Dassin
Fallen Angel
Join date: 14 Sep 2005
Posts: 33
11-22-2005 16:13
From: Strife Onizuka
The way LSL handles states and events is pretty cool.
If anyone is interested i'll post the actual file formating (but not the bytecode info).


Yes, yes please, affirmative, and for the love of god, yes! =)
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
11-22-2005 18:41
I used SciTe to make this, and i used the lsl file type, the "{" and "}" i use to collapse sections for quicker access to data i want.

This research was done with some permision from LL (they never told me to stop and we dialoged about my research). I am not at liberty to discuss my research techniques. I'm not posting the rest of these notes because really they aren't all that useful.

In the proccess of my research I "discovered"
1. LSL scripts are compiled by the client and their memory space is allocated and uploaded by the client.
2. LSL Bytecode is almost 1 to 1 with the LSLText, meaning if you were motivated you could write a decompiler. All that is lost by compiling are comments, white space, names, and += -= *= %= /= all are expanded.
3. Publishing research had the potential to lead to alot of trouble so does discussing research techniques.

CODE

Writen by Strife Onizuka

byte code

header:
0x0000 <0x00-0x03> <0x04-0x07> <0x18-0x1B> <0x0C-0x0F>
0x0010 <0x10-0x13> <Address of <Global Vars Values> start> <Allocate Variables after here> <0x1C-0x1F>
0x0020 <0x20-0x23> <0x24-0x27> <0x28-0x2B> <0x2C-0x2F>
0x0030 <0x30-0x33> <0x34-0x37> <Address of <Global Vars>> <Address of <Global Func>>
0x0040 <0x40-0x43> <0x44-0x47> <Address of <NoS>> <0x4C-0x4F>
0x0050 <0x50-0x53> 0x00000000 0x00000000
0x0060 <CEM> <Global Func> <Global Vars> <State Data> <spacer> <Global Vars Values> 0x40

<0x00-0x03> = 0x00004000 script memory size?
<0x04-0x07> = 0x00000000 ?
<0x18-0x1B> = 0x00000200 lsl version? asset type?
<0x0C-0x0F> = 0x00003FFF script memory size? memory mask? overflow point?
<0x10-0x13> = 0x00003FFF script memory size? memory mask? overflow point?.
<0x14-0x17> = 0x0000???? <Address of <Global Vars Values> start>
<0x18-0x1B> = 0x0000???? <Allocate Variables after here>
<0x1C-0x1F> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x20-0x23> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x24-0x27> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x28-0x2B> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x2C-0x2F> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x30-0x33> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x34-0x37> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x38-0x3B> = 0x0000???? <Address of <Global Vars>>
<0x3C-0x3F> = 0x0000???? <Address of <Global Func>>
<0x40-0x43> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x44-0x47> = 0x00000000 handler retired from active compiler, non null address activates it.
<0x48-0x4B> = 0x0000???? <Address of <NoS>>
<0x4C-0x4F> = 0x00000000 unused handler
<0x50-0x54> = 0x00000001 local address of <CEM>?, number of threads?, some offset? number of <CEM>`s?,


<spacer> = <0x0000> (2 bytes)
<CEM> = Combined Event Mask (all the Event Masks OR`ed together) (8 bytes)
{<State Data>
Format:<NoS><LoS><SC>
<NoS> = Number of States (4 bytes)
{<LoS> = List of States (12 bytes * <NoS>)
<AofSB> = Address of <SB> (4 bytes), they start at <Address of <NoS>>
<EM> = Event Mask (8 bytes) see "Event Mask Code Table"
format: (<AofSB><EM>)*<NoS>
}
{<SC>
format: (<SoD Address>0x00((<EA><EMR>)*BEiEM)(<bytecode>*BEiEM))*<NoS>
<SoD Address> = Start of Data Address, 0x00000005, this address is relative to it self.
BEiEM = Bits enabled in <EM>
<EA> = Event Address (4 bytes)
{<EMR> = Event Memory Requirements (4 bytes)
rotation 0x10 bytes
vector 0x0C bytes
list 0x04 bytes
key 0x04 bytes
string 0x04 bytes
float 0x04 bytes
integer 0x04 bytes
}
}
}

{<Globals Vars>
<NoV> = Number of variables, no idea if there is an actual number for this in the code.
format: (<Local Address of <data>> <type> 0x00 <data>) * <NoV>
{<type>
void 0x0
integer 0x1 <data> = value (4 bytes)
float 0x2 <data> = value (4 bytes)
list 0x7 <data> = <<Global Vars Values> Local Address>, address of the value , (4 bytes)
rotation 0x6 <data> = value (16 bytes)
vector 0x5 <data> = value (12 bytes)
key 0x4 <data> = <<Global Vars Values> Local Address>, address of the value , (4 bytes)
string 0x3 <data> = <<Global Vars Values> Local Address>, address of the value , (4 bytes)

}
}

{<Globals Func>
<NoF> = Number of Functions
<AoF> = Address of Function
format:<NoF>(<AoF>*<NoF>)(<Byte Code>*<NoF>)
}

{<Global Vars Values>
first byte of <Global Vars Values> is byte 0x01
(<NoB><Type><0x00><Value>)*NoG)
<NoB> = Number of Bytes
{<Type>
{void 0x00}//not supported but don't know?
{integer 0x01}//NoB == 0x04
{float 0x02}//NoB == 0x04
{string 0x03}//NoB == Length of String + 1 (for the NULL)
{key 0x04}//NoB == Length of String + 1 (for the NULL)
{vector 0x05}//NoB == 0xC
{rotation 0x06}//NoB == 0x10
{list 0x07
<Value> = <NoV>(<Address of a Global Variable>*<NoV>)
<NoV> = Number of Values, 1 byte
<Address of a Global Variable> is local to <Global Vars Values>
}
}
}

{"Type Table" //Variable types and memory requirements, with declare codes for functions & events
function
rotation 0x05 16 bytes
vector 0x04 12 bytes
list 0x03 4 bytes
key 0x02 4 bytes
string 0x02 4 bytes
float 0x01 4 bytes
integer 0x01 4 bytes

//floats and integers are stored the same way as are strings and keys.
//in the code there is no way to tell the difference between the two.
//why global functions use different codes is beyond me since the compiler dictates how a variable interacts.
}

{"Event Mask Code Table"
0x00000000 0x00000001 state_entry()
0x00000000 0x00000002 state_exit()
0x00000000 0x00000004 touch_start(integer a)
0x00000000 0x00000008 touch(integer a)
0x00000000 0x00000010 touch_end(integer a)
0x00000000 0x00000020 collision_start(integer a)
0x00000000 0x00000040 collision(integer a)
0x00000000 0x00000080 collision_end(integer a)
0x00000000 0x00000100 land_collision_start(vector a)
0x00000000 0x00000200 land_collision(vector a)
0x00000000 0x00000400 land_collision_end(vector a)
0x00000000 0x00000800 timer()
0x00000000 0x00001000 listen(integer a, string b, key c, string d)
0x00000000 0x00002000 on_rez(integer a)
0x00000000 0x00004000 sensor(integer a)
0x00000000 0x00008000 no_sensor()
0x00000000 0x00010000 control(key a, integer b, integer c)
0x00000000 0x00020000 money(key a, string b)
0x00000000 0x00040000 email(string a, string b, string c, string d, integer e)
0x00000000 0x00080000 at_target(integer a, vector b, vector c)
0x00000000 0x00100000 not_at_target()
0x00000000 0x00200000 at_rot_target(integer a, rotation b, rotation c)
0x00000000 0x00400000 not_at_rot_target()
0x00000000 0x00800000 run_time_permissions(integer a)
0x00000000 0x01000000 changed(integer a)
0x00000000 0x02000000 attach(key a)
0x00000000 0x04000000 dataserver(key a, string b)
0x00000000 0x08000000 link_message(integer a, integer b, string c, key d)
0x00000000 0x10000000 moving_start()
0x00000000 0x20000000 moving_end()
0x00000000 0x40000000 object_rez(key a)
0x00000000 0x80000000 remote_data(integer a, key b, key c, string d, integer e, string f)
}


{<Byte Code>
format: <address of <code>><pamater <type> list><code>
events set the value of <return and pamaters> = 0x00 and <address of <code>> = 0x00000005
<return and pamaters> format:<pamater list>
{<pamater list>
format: (<type>0x00)*NoP(0x00<type = void>)
NoP = number of paramaters, we don`t actualy get this number
}
{<type> = (variable types)
<type> == 0x07 (list)
<type> == 0x06 (rotation)
<type> == 0x05 (vector)
<type> == 0x04 (key)
<type> == 0x03 (string)
<type> == 0x02 (float)
<type> == 0x01 (integer)
<type> == 0x00 (void)
}
<code> = many <byte> combinations.
}
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Lindsey Dassin
Fallen Angel
Join date: 14 Sep 2005
Posts: 33
11-23-2005 16:44
Thank you Strife -- that actually answers more than a few questions i had about how LSL works.

It's disappointing to hear that LSL bytecode basically corresponds 1 to 1 with LSL scripts. From what you said it sounds like there are no stack operations for function calls, no indirect addressing of any kind ( a HUGE loss -_-; ), and no branching instructions underlying flow control... correct?

I'm sorry if those questions have bleedingly obvious answers. It's just that i absolutely adored Intel 8088 assembly in high school: The speed and power was far above any compiler i had encountered. Well, okay, that and i'd like to get absolutely everything that i can out of LSL. =)
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
11-23-2005 19:18
From: Lindsey Dassin
Thank you Strife -- that actually answers more than a few questions i had about how LSL works.

It's disappointing to hear that LSL bytecode basically corresponds 1 to 1 with LSL scripts. From what you said it sounds like there are no stack operations for function calls, no indirect addressing of any kind ( a HUGE loss -_-; ), and no branching instructions underlying flow control... correct?

I'm sorry if those questions have bleedingly obvious answers. It's just that i absolutely adored Intel 8088 assembly in high school: The speed and power was far above any compiler i had encountered. Well, okay, that and i'd like to get absolutely everything that i can out of LSL. =)


Local variables are stored in the stack, and as code is executed more values are pushed on to the end of the stack and poped off the end. If LL wanted to implement a swap function that would trade two values between variables all they would need to do it would be:
  1. push the first variable
  2. push the second variable
  3. pop and store into the first
  4. pop and store into the second


exampe a++ works by:
  1. push a
  2. push a
  3. push 1
  4. pop two values and add them, push the result into the stack
  5. pop value from the stack (into the great bit bucket in the sky)
  6. which leave the original value of a at the top of the stack, ready to be used.


exampe ++a works by:
  1. push a
  2. push 1
  3. pop two values and add them, push the result into the stack
  4. which leave the modivied value of a at the top of the stack, ready to be used.


When a function is called the base stack pointer is changed, the result is actualy at a negative stack value, and the paramaters values are pushed into the new stack.

But beyond string and list pointers LSL does not support pointers. The way the byte code is arranged pointers are impossible (except with lists and strings which wouldn't work well or the way you wanted).
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Lindsey Dassin
Fallen Angel
Join date: 14 Sep 2005
Posts: 33
11-24-2005 10:23
So LSL scripts do have an underlying assembly! Yes! It's a stack-based assembly, but still assembly. <3

Strife, thank you so much -- you're wonderful! It looks like i'll have to get in touch with LL and do some research of my own! ( so's i don't constantly pester you ;) )

On a side note, having taught computer science courses before, i think i understand why there aren't any pointers. I've helped a lot of students write a lot of programs, which don't usually crash until you introduce pointers. ...then they don't stop crashing!