BVM Questions

Blitz3D Forums/Blitz3D Programming/BVM Questions

JoshK(Posted 2004) [#1]
Okay, I want to add BVM into the engine, properly. If this works, the author gets another license sale.

I am using one script per entity. I want to load a script with an UpdateEntity() function, and pass the function the four-byte entity data structure to update that entity.

file$="monster.script"
module=BVM_LoadModule(file)
If module=BVM_INVALID_MODULE RuntimeError "Error loading script "+Quote(file)+"."
context=BVM_CreateContext()
functionpointer=BVM_FindEntryPoint(context,module,"UpdateEntity")
BVM_SelectContext(context)
BVM_SelectEntryPoint(functionpointer)
BVM_Invoke_Blitz3D()


Questions:

-How do I pass a variable to the UpdateEntity() function? (The entity!)

-Can I have more than one function called "UpdateEntity" in the same context, or do I have to call each entity's update routine a different name?

-Is there any inherit overhead in calling a function? Should I call one UpdateMonsters() function, or is it okay to call each UpdateMonster() function individually?


WendellM(Posted 2004) [#2]
I'm only (very recently) familiar enough with BVM (though I like it) to mention that you'll need to pop the stack to prevent possible stack overflow, since every Invoke returns a value (this isn't really clear in the docs): http://koriolis.free.fr/forum/viewtopic.php?t=57

As for multiple UpdateEntities per context, you might find http://koriolis.free.fr/forum/viewtopic.php?t=55 helpful.

Man, I feel that I've only yet scratched the surface ( http://koriolis.free.fr/forum/viewtopic.php?t=49 ), but I love what the potential of BVM seems to be!


Jeroen(Posted 2004) [#3]
WendellM says it: you have to "pop".
Yes, BVM is cool and therefore I implemented it in Wobbles.


poopla(Posted 2004) [#4]
FunctionPoint would be the entrypoint(like main() in a standard C program). You would "Push" the entity that UpdateEntity() needs, then call it(if I recall correctly).

I never used BVM like that, I coded all the actual game entities and structure in script itself. I was using it on top of alot of systems, like physics, effects, and general management. So all game code went in scripts, the more processor intensive code went in hardcode.


Koriolis(Posted 2004) [#5]
How do I pass a variable to the UpdateEntity() function? (The entity!)
I have to admit this explanation really lacks in the "basics" part of the docs (it's explained in the tutorial though). The recent questions I was asked gave me good hints about what needs improvments in the docs, and it *will* be improved.

Passing parameters is done by pushing them on the context stack. For that use BVM_PushInt,BVM_PushFloat and BVM_PushString.
By example say your function is:
Function SomeFunc$(param1%, param2#)
...
End Function

All you have to do in your main program is to push the parameters, invoke the function, then pop the return value.
BVM_PushInt(20) ; the value for param1 (it's an integer, so use BVM_PushInt)
BVM_PushFloat(1.23) ; the value for param2 (it's a float, so use BVM_PushFloat)
BVM_SelectEntryPoint(hEP_SomeFunc)
BVM_Invoke_MYCOMMANDSET()
returnValue$ = BVM_PopString() ; the return value (it's a string, so use BVM_PopString). 
    ; If we don't need the return value than we just do "BVM_PopString()" and don't 
    ; store the result anywhere (but popping it would *still* be required).


Can I have more than one function called "UpdateEntity" in the same context, or do I have to call each entity's update routine a different name?
Each script is a separate program, and thus the names you use in one script doesn't interfer in the other ones. Using the same function name in different scripts is actually a common and good usage, if you're planning to use one script per entity.
So you can have each script have its very own "UpdateEntity" function, no problem at all.

Is there any inherit overhead in calling a function? Should I call one UpdateMonsters() function, or is it okay to call each UpdateMonster() function individually?
I don't think you can find any significant speed difference between both solutions, so choose the one that best fits your needs.


JoshK(Posted 2004) [#6]
If I have a script function that does not return a value, do I need to pop anything? Can I just do this:

BVM_PushInt(entity); entity structure to update
BVM_SelectEntryPoint(pointer): update function pointer
BVM_Invoke_Blitz3D();update the entity

It seems that the stack might be getting screwed up. After about 30 seconds, it says the entity does not exist when I try to position it, yet the debugline I added in the script, just before that command, lists the same entity it has been running the whole time.


Koriolis(Posted 2004) [#7]
No, as stated in the thread WendellM pointed you at, you *always* have to pop something.

To restate what I've said in this thread:
There must always be a pop after BVM_Invoke_<CMDSET>
Most important, a function for which you declared no return value actually returns an int (like in plain blitz), so in this case you have to put BVM_PopInt() after the invokation.
Note: this also stands for the main program, which is nothing else than a function taking no parameters and returning an integer).

The fact that any function actually returns a value is really a blitz thing, it's not a specificity of BVM:
In blitz you can do
: 
Function Func1() 
    ; I have not declared the return type, but it's an integer by default 
    ; Here's the proof: I return the string "7 little dwarfs", 
    ; it will get automatically converted to an integer (-> 7) 
    Return "7 little dwarfs" 
End Function 
Function Func2() 
    ; I have not declared the return type, but it's an integer by default 
    ; In addition I'm returning nothing (will return the default value, 0 
End Function 
Print Func1() 
Print Func2()

Try this in Blitz, this will print 7 and 0. As you see Func1 and Func2 *do* return a value.

If you fail to pop the return value you will eventually face a stack overflow. Because the default return type is integer, you have to do a BVM_PopInt() after the invokation. And as you really don't need any return value, just pop it and don't store the value anywhere.
Simply put, add
BVM_PopInt()
and that's all.

In BVM 2 the stack overflow error will get properly reported rather than causing a bug.


JoshK(Posted 2004) [#8]
Sick, it works!


Hotcakes(Posted 2004) [#9]
That's great. Days worth of conversation and Halo gets it all within a few hours. =]


Rimmsy(Posted 2004) [#10]
BVM is the bomb!


JaviCervera(Posted 2004) [#11]
BVM is the best scripting engine I have seen in ages :)


JoshK(Posted 2004) [#12]
Okay, I almost have it all tested, but I am running into a bad problem.

I call an entity update function every loop for several minutes, and it works fine. Then it just stops being able to select the entry pointer. What causes this? How can I bug test it?


Sweenie(Posted 2004) [#13]
For starters I would count the nr of updates that is made before it stops to see if it's always the same or if it's random.


Rimmsy(Posted 2004) [#14]
Are you sure you're calling BVM_PopInt() or whichever data type the function at your selected entry point is returning?

I've found the only way to test it is to use large quantities of debuglogs in my scripts.

updatePoint=BVM_FindEntryPoint(script_context,module_handle,"updateworld")
debuglog "updateWorld entry point: "+updatePoint


Rimmsy(Posted 2004) [#15]
Generally I create one global context at the beginning of my game, then map all my loaded modules to that. I'm therefore never calling selectContext ever again.


JoshK(Posted 2004) [#16]
Me too. I said SelectEntryPoint.

I have verified that the entrypointer is the same value that is initially loaded, and that it is succesffully called for about five minutes, and then it just keeps failing after a certain point. I only use one context for all scripts.


JoshK(Posted 2004) [#17]
I tested to see when it failed, by incrementing a variable each time the script is called. I ran it three times, and it failed on the 17,582th, 16,904th, and 17,868th loops. :|


Koriolis(Posted 2004) [#18]
I call an entity update function every loop for several minutes, and it works fine. Then it just stops being able to select the entry pointer. What causes this
Most probably the 10 minutes timeout of the trial version. This time limit is the only limitation of the trial version, everything else being exactly as in the full version, so that you can properly test all you that want.
After that limit is reached some key functions of BVM are locked.
So if it works all fine for 10 minutes and suddenly stops, then it's all normal.

I should certainly have put a messagebox or something to make it obvious.


JoshK(Posted 2004) [#19]
ARGHHHHH!!! I suspected this, but no one said that there was a time limit, and I didn't see anything in the docs about it.

Oh well, problem solved. Now that I know the system works, I am off to get my credit card.

Thanks for the help with this.


You might check out PayPal for orders. They take the same fee, but you can withdraw your money instantly. ShareIt would not accept my hotmail address, and it failed the first time I tried my gamecreators address, then worked thr 2nd time. :|


Koriolis(Posted 2004) [#20]
and I didn't see anything in the docs about it
True. It's said in the little readme at the end of the installation though. But I now believe noone actually reads these readmes, so a message box after the timeout is probably a good idea.


Hotcakes(Posted 2004) [#21]
If it's any concellation, I read it, K =] But I bought it before I actually used it so it didn't matter =]

BTW, that patched dll you sent me, would that be likely to have been a patched demo or patched proper dll? Maybe I should revert back to the old one and test it...


Koriolis(Posted 2004) [#22]
would that be likely to have been a patched demo
Shouldn't be, I compiled it with the options set up for the full version. I'll check that anyway, and let you know otherwise.

[EDIT]Checked, it's ok[/EDIT]


Hotcakes(Posted 2004) [#23]
Then, shoot. I have no idea what's going wrong now...