GameScript - Scripting for Blitz3D

Blitz3D Forums/Blitz3D Programming/GameScript - Scripting for Blitz3D

John J.(Posted 2007) [#1]
Note: This is one of several libraries that have been sitting on my hard drive for about a year not being used (since I have moved on to my own C++ game engine [using Ogre]). I have decided to release a few of these libraries since can be very useful to many of you, I'm sure.


Download GameScript Here

GameScript SDK provides you with the power to compile and execute embedded script programs within your BlitzBasic application. Embedded scripts can be used as plug-ins, modable content, and much more. GameScript supports multi threading scripts, which allows you to run more than one script at the same time in your application.

GameScript scripts are normally filed as “.gs” files and will be automatically compiled when necessary. When distributing your application, you can hide your script source code by simply deleting the “.gs” files, leaving the remaining compiled GameScript executables (.gsx). The “.gsx” files will exist for each “.gs” file after they have been run once (which automatically calls the GameScript compiler) or have been compiled manually with the GameScript compiler. This is extremely handy also if you have developed a plug-in for an application that utilizes GameScript, and you would like to protect your source code.

GameScript has very few limitations and is a full-featured programming language, including features such as custom data types, standard flow control, and an optimizing compiler. Some of the features GameScript includes are:

• Easy to use structured programmer-friendly BlitzMax-style language syntax
• Easy-to-use programmer interface
• Custom data types
• Functions with recursion support
• Local, Global, Constant, and Static variables
• A fast compiler
• Ultra-fast multi-threading virtual machine
• Protect your scripts – Since GameScript natively runs only GameScript executables (.gsx), there's no need for your script source code (.gs) to be included with your final distribution
• Automatic compile management – GameScript source code (.gs) is compiled to GameScript executable (.gsx) only when changes have been made.

Note: Funtion overloading, which might be mentioned in the manual, does not currently exist in this version of GameScript.


Ricky Smith(Posted 2007) [#2]
Very cool - thanks !!


lo-tekk(Posted 2007) [#3]
This sounds exciting, thank you !


Beaker(Posted 2007) [#4]
Where is the manual?


slenkar(Posted 2007) [#5]
would this help with making an RPG? how?


John J.(Posted 2007) [#6]
Where is the manual?

Oops sorry! I uploaded the wrong file. Try the link again.

would this help with making an RPG? how?

Definitely. You could use it to write quests, AI, etc. Anything that you don't want to directly hard-code into your EXE (like mission events in a tank game, for example), you can put in a script. This way you can easily update and expand on your game (mods and expansion packs would be nearly impossible without some sort of scripting language).


(tu) sinu(Posted 2007) [#7]
I already have bvm, however looking at this won't hurt, big thanks for releasing it.

Scripting is important, like john said, if you don't want to hardcode quests, ai etc use scripting, then if you want to make so that you get 1 coin everytime you enter a room, simply do it through a script.
For something that simple you really don't want to be hardcoding.


jfk EO-11110(Posted 2007) [#8]
Just downloaded. I still wonder how this is inserted in bitz, and how the "compiled" (I assume it's not native code, isit?) scripts are interacting with blitz variables and entities etc.

Sounds very good so far.


John J.(Posted 2007) [#9]
I still wonder how this is inserted in bitz, and how the "compiled" (I assume it's not native code, isit?)

It's not native - it compiles to a custom pcode format. The pcodes are read by the virtual machine and executed (the VM actually can run scripts at 1/3 of Blitz's speed, which is surprising considering that it is a VM).

The only way to interface the script to your code is through functions which you add to the scripting language through "GameScript Functions.bb"

P.S. While your program can't call GameScript functions, it can run GameScripts whenever you want. And since GameScripts are pseudo-threaded, you can easily construct a event-based script system that executes certain scripts when events trigger.


Leto(Posted 2007) [#10]
Sounds really cool, thanks John.


Danny(Posted 2007) [#11]
Thanks for sharing John!

d.


_33(Posted 2007) [#12]
Hello John,

This is a great service you just did there by posting this small language/script engine + compiler. But I have a question regarding compiled code. I looked at the source and compiled code and noticed that the compiled code is about twice as large as the source code in filesize. Any reason?

Cheers.


John J.(Posted 2007) [#13]
I looked at the source and compiled code and noticed that the compiled code is about twice as large as the source code in filesize. Any reason?

I just used an inefficient storage method. If I remember correctly (I made this about 2 years ago ;) ), opcodes are stored as "[numofparams] [opcode] [param1] [param2] [etc.]", which isn't efficient storage-wise, but is easy to implement in Blitz3D.

I made a similar scripting language for an embedded system later and compiled codes were less than half the source size (and that's without assembly optimization), so it's definitely possible to improve (if you really think it's worth the time - scripts are definitely not going to be the major concern for HD usage)

Edit: BTW, here's a sample script that I used to run a training mission in BattleTanks 3 (it's really simple - it doesn't even use most of GameScript's features like functions and data-types):

Of course this only works with BattleTanks 3 (since there are game-specific funtions) - I'm just demonstrating how scripts can be used not only as event-triggered, but as a parallel pseudo-thread that manages the game.


slenkar(Posted 2007) [#14]
delay in the script doesnt actually delay the game right?

lets see if I understand:

tank_exists is a blitz function that returns 1 or 0
so the script is capable of executing blitz functions and recieving the results.


so for an rpg, I could write conversations and their threads,
Im already using XML which functions almost like a scripting language and has a great tree-structure for conversations.
Branching conversation trees wouldnt be that easy to write and maintain with a scripting language but it could be used to add enemy AI


_33(Posted 2007) [#15]
Chunkations, the script doesn't call a B3D function, IMHO, it calls a pre coded command name that launches a B3D coded function from John's game.

John J.: I'm not saying I'll concentrate my efforts on shrinking that filesize, it was a curiosity that I tought interesting and was just wondering the whereabouts of it. Needless to say this is a really great help to have available a scripting language as powerful as this at hand. I'll have to study the docs to understand how to implement this as a command line interpreter and how it would work as an AI scripting system. It will be long days ahead.

Cheers.


John J.(Posted 2007) [#16]
delay in the script doesnt actually delay the game right?

lets see if I understand:

tank_exists is a blitz function that returns 1 or 0
so the script is capable of executing blitz functions and recieving the results.

Yeah, delay doesn't actually the game of course - the scripts are threaded so they are running parallel to the game.

Like _33 said, it doesn't directly call a Blitz3D function (it can't since Blitz3D doesn't support function pointers or polymorphism). You have to add your function in GameScript_Functions.bb properly so that the compiler/VM can access it (it's pretty simple, just follow the example of the other functions).


JaviCervera(Posted 2007) [#17]
Really nice project :) Might become a cool scripting engine maintained by the community. I'll play a bit with it.

The license seems to be the zlib, isn't it?


John J.(Posted 2007) [#18]
The license seems to be the zlib, isn't it?

Yeah.

Might become a cool scripting engine maintained by the community.

Good idea. If the zlib license gets in the way here, I can change it (if so, let me know).


_33(Posted 2007) [#19]
When I looked into having a way to parse many commands on the same line, I sumbled on this semi-colon rule that I found odd. Apparently semi-colon only terminates lines, and doesn not permit to pile commands one after the next. I'll have to figure a way around this.


John J.(Posted 2007) [#20]
Apparently semi-colon only terminates lines

That's strange - maybe the documentation is incorrect. If you look in the script example I posted above, there are some "piled" commands in there, so it should be working.


_33(Posted 2007) [#21]
Actually, it's my bad John! semi-colon does make you pile up commands, but with a FOR statement, it doesn't want.

For i = 1 To 30;prime = NextPrime(prime);Print prime;Next

In the case of a FOR statement terminating with a semi-colon, we get the following error:

ERROR: Expected line-end or semicolon(line #10)

EDIT: After more tests, I found out that the real problem seems to be that it doesn't like to have the FOR statement and the NEXT statement on the same line.

So, this works:
For i = 1 To 30;prime = NextPrime(prime);Print prime;
Next


John J.(Posted 2007) [#22]
Ok, the problem's fixed now :) It actually had nothing to do with "For" but in fact stand-alone functions (like Print) were to blame - the compiler was reading ahead one token too far and therefore skipped right over the Next statement since it was on the same line.


_33(Posted 2007) [#23]
LOL! I was definately looking at the wrong place. It is now fixed on my end, neat! Thanks again John! OK here's something I found. It's concerning a misplaced FOREVER statement.

Case TOKEN_UNTIL, TOKEN_FOREVER
GSC_AddError("Keyword is out of place (there are no open "+Chr(34)+"Repeat"+Chr(34)+" statements)")
GSC_NextToken()
Return

... I just added TOKEN_FOREVER in there so it is taken in account.

Now one last obscure thing about this script language that I found:
For i = 2 To current - 1
If (current Mod i) = 0 Then ; Found = False ; Exit
EndIf
Next
........ This works fine, but:
For i = 2 To current - 1
If (current Mod i) = 0 Then Found = False ; Exit
EndIf
Next
......... This doesn't generate any errors and will generate very different results. It seems to be doing the Exit all the time, but maybe I'm mistaken.


YellBellzDotCom(Posted 2007) [#24]
All I got to say is wow, this is going to help out in a lot of areas. Trully appreciated!!


JaviCervera(Posted 2007) [#25]
Good idea. If the zlib license gets in the way here, I can change it (if so, let me know).
No problem. Zlib license is perfect. In three weeks I'll finish my exams, and play a bit with this. Porting the VM to C might be a good idea (you can still use it in Blitz3D/Plus through a dll, and you might use that dll in any language).


John J.(Posted 2007) [#26]
Now one last obscure thing about this script language that I found:

Ok, that's fixed now too. The whole single-line If..Then parser was wrong - it assumed that a single line If..Then statement is "If condition then statement1 [else statement2]", and didn't consider that there might be multiple statements. The reason your first example worked is because that ";" terminator made it think that it was a multi-line statement (fixed now also), and the EndIf closed it properly. The bottom example didn't work because the ";" was missing so it thought it was a single-line If statement and it couldn't handle multiple commands in a single-line If statement.

Anyway, now you can do things like this:
For i = 2 To current - 1
  If (current Mod i) = 0 Then Found = False; Exit
  If (current Mod i) = 0 Then ;Found = False; Exit;
  If (current Mod i) = 0 Then
    Found = False; Exit
  EndIf
  If x Then a; b; c; d; e Else f; g; h; i; j
Next


Porting the VM to C might be a good idea (you can still use it in Blitz3D/Plus through a dll, and you might use that dll in any language).

Yeah, that might work pretty well. And considering that it runs at 1/3 of Blitz3D's speed now, I wonder how fast it would be in C/C++ :) But is Blitz3D capable of callback functions through DLLs?


_33(Posted 2007) [#27]
John J., I assure you , if I knew what I was doing, I would fix this right away! But it was getting in the complex zone and I'm not yet very good with parsers and tokenizers, so I prfered to leave this to the experts. None the less, terrific work as usual of your behalf mr Judnich!

Now I've looked somewhat about how to add the possibility to feed commands in other ways than a file in this tool, and came to the conclusion, that I would have to make a function that is similar to the file handling one, but using a bank. How do you think that would go? Is there any thing particular I should know? What I would do is let the compiler make a temp file as the executable gets created and run that.

Cheers.


John J.(Posted 2007) [#28]
Now I've looked somewhat about how to add the possibility to feed commands in other ways than a file in this tool, and came to the conclusion, that I would have to make a function that is similar to the file handling one, but using a bank. How do you think that would go? Is there any thing particular I should know? What I would do is let the compiler make a temp file as the executable gets created and run that.

You could change it to read from a bank, but it would be a lot easier to just create a temporary file, and delete it after calling GSV_ThreadLoad(). The compiler and virtual machine is kind-of hard-coded into using files, and it would take a while to change that.


_33(Posted 2007) [#29]
Reason for me asking is mostly because I want to pass my Console user input through the GSV so the user or me or beta tester or whoever could prompt it for any needs. But I do not necessarely want them to see the source file. Still, I will try to see how that could go. I've seen 2 major functions that would need to be duplicated for BANK usage, and possibly a flag that would indicate if the source is from a file or a bank.

But as you say, it's a lot of work. possibly for little gain.


John J.(Posted 2007) [#30]
Reason for me asking is mostly because I want to pass my Console user input through the GSV so the user or me or beta tester or whoever could prompt it for any needs.

The only problem I could think of in this case is that scripted functions are local to their own file/source. You could easily make a temporary file system that feeds console input into the script engine, but then you'd only have access to Blitz functions (the ones you add to "GameScript Functions.bb"). You could work around this, though, by adding all your scripted functions after each console input, but will lead to increased compile times (although the compiler is reasonably fast).


John J.(Posted 2007) [#31]
Update: The latest version includes a compiler bug fix where some functions were not properly parsed.


_33(Posted 2007) [#32]
Hmmm, thanks!


OJay(Posted 2007) [#33]
yeah, thanks john!

im currently evaluating to integrate it within a small editor to make the GUI handling completely via scripts.

works pretty good so far, but im seeing an issue coming at the horizon: making an editor with scripts leads to a lot of functions and therefore to one very large script file. how complicated would it be to make an include command, which includes the source directly into the main script before the compiler starts? is it possible at all?

would be a nice feature allowing for larger projects, wouldnt it?

cheers :)


Matty(Posted 2007) [#34]
Didn't see this first time round (2 weeks ago). Looks good and seems fairly easy. I bought bvm a while ago but couldn't get my head around it. This seems much easier.


John J.(Posted 2007) [#35]
Update: The latest version includes a compiler bug fix where function parameters were not working properly.


Naughty Alien(Posted 2007) [#36]
..interesting..


Koriolis(Posted 2007) [#37]
I bought bvm a while ago but couldn't get my head around it. This seems much easier.
I must say I'm very surprised to hear that Matty. One of the main goals of bvm is to achieve an easy integration into the host application, in particular by removing the need of writing glue code to allow scripts to call your very own functions. Though the latest version improved a lot, this part was already pretty good in BVM 1 and I have only heard good feedbacks about it.

I am very interested in knowing what seemed complicated to you in bvm, it might only be a documentation issue. You would do me a favour by maybe helping me to make bvm better.

If you're interesting in helping, I suggest you come to the new BriskVM forum. Thanks.


Matty(Posted 2007) [#38]
Sorry Koriolis - I just found it a little difficult to understand, I probably didn't give it the time required to learn it though. After looking at Johns and trying it out a little it seemed much simpler. However my time spent in front of the Pc has diminished greatly in recent months so while I'd normally be happy to help you make bvm better I am not at my PC often enough at the moment. Thanks.


OJay(Posted 2008) [#39]
hi there.

the following code fails to execute and quits with a "object does not exist":
Type Vehicle
	Field Speed:Float
EndType

Local Car:Vehicle
Car = New Vehicle 'Create a new instance of Vehicle and store it's pointer in Car
Car.Speed = GetSpeed(Car) + 10

Function GetSpeed:Float(v:Vehicle)
	Return v.Speed  <----- that line causes the problem!
EndFunction

i think there's a typo in GameScriptVM.bb at line 1019: "var\Thread = Thread" should be "obj\Thread = Thread".

because blitz quits on accessing type fields EVERY SINGLE TIME exactly on that line!

ok. but fixing that one doesnt solve the whole thing. now the script executes, but fails on compiling with the message: "Unknown instruction code (14)! Possible corrupted GSX executable.". the log-file says this:

_______07 Jan 2008, 19:04:46 - example1.gsx:_________________
Runtime error at instruction #14:
...
mov eax, 0
pop ecx
add ecx, eax
mov ecx, [var]
[var], ecx <-- Unknown instruction code (0)! Possible corrupted GSX executable.
jmp _Label22
_Label-1
pop [var]
...




credit for this bugreport goes to the original author: http://www.blitzbasic.com/Community/posts.php?topic=74972 :)


hopefully someone sees a solution for this, since it makes using custom types (almost ^_^ ) impossible with gamescript!

cheers


John J.(Posted 2008) [#40]
Thanks for posting. Actually, someone recently contacted me, reporting exactly the same problem, which he later fixed on his own. I uploaded the fix, so try redownloading and see if it fixes the problem (sorry I didn't upload earlier).

Again, the credit for this fix goes to another blitz user (I don't know his blitzbasic username, unfortunately), not me. He also ported GameScript to BlitzMax, which I'm sure would be useful to a lot of people (though I won't release it without his permission since it is his port).


OJay(Posted 2008) [#41]
awesome, thanks! i'll try it, when i get home.


c32bit(Posted 2008) [#42]
I just tested and confirmed the fix works.
Thanks to all of you for helping out on this one. It is very much appreciated.


OJay(Posted 2008) [#43]
yepp, works here too :)

unfortunately, i found another glitch :/

i cant get the following code to compile:
Type Vehicle
	Field Speed:Float
EndType

Local Car:Vehicle
Car = New Vehicle 'Create a new instance of Vehicle and store it's pointer in Car

SetSpeed(car, 10)
print GetSpeed(car)


Function SetSpeed(v:Vehicle, s:Float )
	if v = null then Return
	v.Speed = s
EndFunction

Function GetSpeed:Float(v:Vehicle)
	If v = null then Return
	Return v.Speed
EndFunction


it constantly gives me "cannot return from non-function. use 'end' instead. (line #14)". and line #19..

so you can't use conditional returns in functions it seems or do i am overseeing something here?


john: maybe you could give me the email of that mysterious user, so i could contact him directly? :) possibly he knows a solution...


Nack(Posted 2008) [#44]
Sorry to revive. But seems appropriate to write in the same thread than start a new one.

I realize, if the script get too big, it will fail to run. I changed the max instruction constant in the VM file and it run fine. But not sure what side effect that might have cause (still a script novice). Any ideas?


Warner(Posted 2008) [#45]
@OJay .. it's not really a glitch. If statements are compiled as separate routines, which means you can't use Return from inside an IF statement.
Try changing it to:

If v <> null Then
Return v.speed
EndIf


OJay(Posted 2008) [#46]
nope, sorry. this is even worse ;)
ERROR: Cannot return from non-function. Use "End" instead(line #21)
ERROR: Expected equals symbol followed by assignment(line #21)
ERROR: Keyword is out of place (all functions are already closed)(line #23)
ERROR: Expected "Else" or "EndIf"(line #23)
ERROR: Expected "EndFunction"(line #387)

i also tried to replace the if's with select's or while's and other hacky statements, with no success...you just cannot return from a function conditionally. so its a limitation of the language.


anyway...i think gamescript is nice to begin with scripting and write small and fast scripts and experiment with it and all. but for anything more serious one should search for alternatives...


Warner(Posted 2008) [#47]
This should be better:

local speed:Float
If v <> null Then
speed = v.speed
Else
speed = 0
EndIf

Return speed


OJay(Posted 2008) [#48]
yes this works, but isnt a real solution either...since you have to go through the whole function () and cant break out prematurely.


BLaBZ(Posted 2009) [#49]
wow, i don't consider myself a very well versed programmer, but after 30 min of reading the manual, all i can say is, awesome, this is so brilliant


_Skully(Posted 2009) [#50]
This is great... I've always wanted to have a look at the internals of a scripting system... thanks!


AJ00200(Posted 2009) [#51]
How do you include this in a .bb file?


GIB3D(Posted 2009) [#52]
Edit: Nevermind :P

Can this be "easily" changed to use a Blitz3D syntax instead because I'm not too familiar with BlitzMax syntax?


Kippykip(Posted 2014) [#53]
I know this is old, but it's gold
Reuploaded it: https://drive.google.com/file/d/0B5PbaEZg8neXdkZxdndDSTM3Ujg/edit?usp=sharing


Yue(Posted 2016) [#54]
Power Full. o.O
@Kippykip Thanks you. :)