GameMonkey Script

GameMonkey Script Forums
It is currently Tue Oct 23, 2018 5:13 pm

All times are UTC




Post new topic Reply to topic  [ 22 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Fri Feb 08, 2008 10:34 am 
Offline

Joined: Wed Jan 16, 2008 10:26 pm
Posts: 23
Hey there,

It's proberly done before, and I think there's a more efficient way of doing this, but here's my version.

Including in game monkey, example:

Code:
include("path\to\includefile");


Binded function:

Code:
int gmIncludeFile( gmMachine *a_machine, const char * a_filename )
{

   std::ifstream file((const char *)a_filename);

   g_syscall(G_PRINT, QMM_VARARGS( "[GMS Mod] Include, Trying to load '%s'\n",a_filename));

   if (!file){
      g_syscall(G_PRINT, QMM_VARARGS( "[GMS Mod] Include, Error, Could not open '%s'\n",a_filename));
      return GM_EXCEPTION;
   }
   
   std::string fileString = std::string(std::istreambuf_iterator<char>(file),
   std::istreambuf_iterator<char>());
   file.close();

   a_machine->GetLog().Reset();
   int num_errors;
   if (num_errors = a_machine->ExecuteString(fileString.c_str()) > 0)
   {
      g_syscall(G_PRINT,QMM_VARARGS("\n[GMS Mod] Include, Compile failed for '%s'\n\n",a_filename));
      g_syscall(G_PRINT,"------------------------------------------------------------\n");

      bool first = true;

      while ( const char* error=a_machine->GetLog().GetEntry( first ) )
            {
         g_syscall(G_PRINT,QMM_VARARGS ( "%s\n", error ));
      }

      g_syscall(G_PRINT,"------------------------------------------------------------\n");
      g_syscall(G_PRINT,"[GMS Mod] Include, end of compile debugging\n\n");
       }else{
      g_syscall(G_PRINT,QMM_VARARGS("[GMS Mod] scriptfile '%s' successfully included\n",a_filename));
   }
}


Of course the g_syscall(G_PRINT,""); functions should be replaced by a print function used in the engine you are using.


Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 15, 2008 12:15 am 
Offline

Joined: Fri Nov 24, 2006 9:50 am
Posts: 165
is "include" the right term? It doesn't run the code inline to the current thread does it?


Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 15, 2008 9:52 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 707
HiVision wrote:
is "include" the right term? It doesn't run the code inline to the current thread does it?
The function will not behave like a preprocessor #include. It will behave the same way system.DoFile() currently does. It will run the included code in its own thread, requiring appropriate use of 'global' or other accessors. Note that the \binds\gmSystemLib is not portable as it contains some Windows platform code. Nothing prevents you from running your source through an external preprocessor, as at least one studio I know does. There just isn't one built in, which I personally consider unfortunate, not because I like preprocessors, quite the contrary, but they are a feature that can be useful for things like efficiently stripping debug code from a release build, or building differnt SKUs, and don't have to be used if you don't want to.


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 28, 2009 12:41 pm 
Offline

Joined: Tue Apr 28, 2009 12:32 pm
Posts: 4
if you wanna do a quickndirty include 'preprocessor' style try :

GMscript 'test.gm'
Code:
#include "somefile.gm"
#include "someotherscript.gm"

// do stuff

C++
Code:
#include <string>
#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

string loadScript( const char *filename ){
  vector< string > files;
  std::ifstream file( filename ) ;
  std::string line;
  std::string script;
  std::string buf;
  // search for '#include "somefile"' in file, if found try including
  while( std::getline( file, line ) ){
    string needle = "#include \"";
    if( needle.compare( line.substr(0, needle.size()) ) == 0 ){
      std::ifstream include( line.substr( needle.size(), line.find("\"")-1 ).c_str() );
      while( include.is_open() && std::getline( include, buf ) )
        script.append( buf );
    }else script.append( line );
  }
  file.close();
  return script;
}

int main(){
  string script = loadScript("test.gm");
  gm.ExecuteScript( script ); // you'll get the idea
}

This way, before the gm machine executes the code, you search and combine all code first...and then the code will be run in one gmthread.
There will be a lot disadvantages concerning this technique, but if you use gamemonkey script for basic stuff this is no prob.


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 28, 2009 12:53 pm 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 707
Welcome to the forum sqz, thanks for contributing :)


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 28, 2009 12:54 pm 
Offline

Joined: Sat Apr 25, 2009 1:40 am
Posts: 66
^ If the file you're including has an include, it won't process it.

Code:
#include <string>
#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

string loadScript( const char *filename ){
  std::ifstream file( filename ) ;
  std::string line;

  // search for '#include "somefile"' in file, if found try including
  while( std::getline( file, line ) ){
    string needle = "#include \"";
    if( needle.compare( line.substr(0, needle.size()) ) == 0 ){
      line.append(loadScript(line.substr( needle.size(), line.find("\"")-1 ).c_str()));
    }else script.append( line );
  }
  file.close();
  return script;
}

int main(){
  string script = loadScript("test.gm");
  gm.ExecuteScript( script ); // you'll get the idea
}


that should


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 28, 2009 1:42 pm 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 707
Thanks 39ster, and a welcome to you also :)


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 28, 2009 1:56 pm 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
That's a nice simple example. Good work guys, I like it.

We could probably upgrade it to implement a simple const style define:

Code:
#define SUCCESS 1
#define FAILED 0


if (result == SUCCESS)
{
 ...
}


Although I'd probably do something with the naming - I've been pondering consts for a while now


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 28, 2009 2:53 pm 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
39ster wrote:
^ If the file you're including has an include, it won't process it.


We'd need to put in a fix to stop an infinite loop.

if you go:

Code:
// a.gm
#include "b.gm"

// b.gm
#include "a.gm"


It'd loop forever.

Additionally, remember to test against self includes.

Code:
// a.gm
#include "a.gm"


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 28, 2009 4:42 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
I really don't see the point of include in a scripting language. Unlike C/C++, the definition of variables or types are not necessary to use them, and I'd rather share system wide functionality accessors from within a named global table or reference to a global user object. What significant gain is there to be had for #include functionality? You are implementing an automated bloat mechanism, and because the included script is copy and pasted within the current script, it will be compiled within an unnamed function like the rest of the script, where it is hidden from other scripts, and all scripts that include that file get a copy of it. In fact, if 5 scripts include a.gm, then you have 5 copies of whatever variables and functions that a.gm defines sitting in memory. That's mega bloat, and for what?

General preprocessor functionality would be useful to do stripping of debug code and such, but that sort of thing isn't necessarily a language specific problem. It's more of a text parsing problem that we can do ourselves prior to compiling and running a script.


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 28, 2009 11:44 pm 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 707
DrEvil-OB wrote:
...General preprocessor functionality would be useful to do stripping of debug code and such, but that sort of thing isn't necessarily a language specific problem. It's more of a text parsing problem that we can do ourselves prior to compiling and running a script.

That is my mind-set also.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 19, 2009 6:05 pm 
Offline

Joined: Sun Jul 29, 2007 11:52 am
Posts: 33
Location: Canberra, Australia
I'm actually planning on making a change to GM at the moment like this. Basically either write a class to wrap round and provide virtuals for overloading new/delete/malloc/free calls cleanly, and also an import, similar to Python's. Been working with Python quite a bit recently, but integrating it in a game neatly is certainly a pain in the a**. Just need to find a way to get code to be executed, and work inside it's own table, so I can assign back. Something along the lines of:

myLib = import( "myLib" );


Top
 Profile  
Reply with quote  
PostPosted: Tue May 19, 2009 6:35 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
Yea that would be useful. Think that's how lua modules work also. I'm not entirely sure how to best do that in GM. Every time you run a script it gets wrapped in an unnamed function and executed. I guess the tricky part is how do we force all variable/function/etc declarations to effectively become members of a table that we provide as the 'this' ? If you mandated the user declare variables with the member declaration it could be done pretty easily.

Code:
//mymodule.gm
.Name = "MyModule";
//or
this.Name = "MyModule";
//or
member Name = "MyModule";

this.ModuleFunction = function() { ... }

SomeLocalVar = 10; // this wouldnt set up a module member because it isn't scoped to the 'this'



Code:
//test.gm
mymodule = import("mymodule");
mymodule.ModuleFunction();

print(mymodule.SomeLocalVar); // does not exist


I'm not sure this is a big deal, because GM doesn't default to global scope like lua, so you'd have to use some sort of keyword anyways, so it's probably not a big inconvenience that the module would have to be explicit about declaring stuff as a member of the module.

All this is do-able right now, you can just allocate a table, set it as the 'this' to the call to execute mymodule.gm, and you should end up with a table that has all the module information. Hide a reference to this table in some global table like _MODULES["mymodule"] = tbl; Then you can just bind an import function to check that table and return that table if it exists, otherwise execute the script and save the reference to the _MODULES table. I believe that's how lua does it in a nutshell.


Top
 Profile  
Reply with quote  
PostPosted: Wed May 20, 2009 9:40 pm 
Offline

Joined: Sun Jul 29, 2007 11:52 am
Posts: 33
Location: Canberra, Australia
You just summed up pretty much how I plan to do it. I don't mind having a nice "NOTE: 'globals' to the module must be 'members'" note, as effectively they're not global - they are module members. I would quite like to add a module type to GM to handle this...but even in Python, it boils down to just really being a dict with bloat, so why add the extra bits in and not just keep it the way it was? You can fake classes with a table in GM, and I actually really like that - it's very pure. Another thing I'd like to add is a way to unload a module nicely (Assigning null to _MODULES["X"] ought to do it) - refs may still exist for objects in the module, but that is something the scripter/programmer needs to be aware of and work with.

Speaking of modifications, DrEvil, I've made a few changes to gmscriptex which you might want to roll into your version. I've dug through and replaced all references to STL with typedef'd equivalents, reason being I provide STL with my own allocator to track and keep it away from the main heap (should I wish to) and replaced all new and deletes with GM_NEW, GM_NEW_ARRAY and GM_DELETE, still working on a getting and GM_DELETE_ARRAY to actually function properly instead of just wrapping to delete[] (can't find a placement delete the way I'd like to implement it in C++), but it will allow for simpler overloading of memory allocation, as I'd quite like to do a decent job of it - basically have a simple allocator class which you give to GM to use.


Top
 Profile  
Reply with quote  
PostPosted: Thu May 21, 2009 1:51 am 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
certainly, I'm always open to improvements to gm_ex.

I'm not sure module unloading is a very useful feature, for the reasons you mentioned and having leftover references laying around, which would still function as the full module, and further calls to import("mymodule") would just load the script again. Not sure what you expect to gain with module unloading support. I suppose if GM had support for weak references you could store weak references in the global table so that if all the users of your module let go of their references the module could be GC'd away until something needed it again, but that would be about as far as I would take it I think, and even this isn't trivial considering GMs lack of weak references. I haven't sat down to think hard about whether weak references could be emulated some how, though it is certainly a feature I'd love to see.

You could 'clear' the table instead of just _MODULES[name]=null but then you are basically causing any user of the module after that to either have to check for the presence of every variable or function they want to call or the scripts will exception since the rug will have been pulled out from under them so to speak. Not a very useful proposition IMO.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 22 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group