Wip markdown files

This commit is contained in:
relt-1
2023-09-26 21:11:14 +02:00
parent dc28e5c841
commit d6e6d92377
12 changed files with 154 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
# QScript Rundown Page 1
QScript is like onions. It has layers.
1. Game
2. QScript
3. Interfaces
4. Languages
The top layer is the game itself. That's where you talk with QScript to add modules, functions, classes, objects, etc.
QScript is the second layer, it talks with the language interfaces about what files to load, what functions to call, etc.
Interfaces actually talk with the scripting languages themselves. But to QScript, each one behaves the same way. There **cannot** be any language specific functionalities that are related to QScript and not the lanugage itself.
[Next ->][QScriptRundown2]

View File

@@ -0,0 +1,12 @@
# QScript Rundown Page 2
If you want to add a feature to QScript, you first have to decide what layer it should lie in. If you want to add a new entity to QScript, you just modify the top-level game layer. If you want to add a new scripting functionality, you might want to modify QScript and the interfaces, but if you want to add something to a scripting language, you must modify its source code directly.
An example of modifying a scripting language is what had to be done with Squirrel.
Squirrel does not support inheriting from userdata, so what had to be done is to modify the source code of it to make it possible.
Same thing with changing the class after it has been created. I have added a _finish metamethod which gets called when the class is finished defining its methods. Its return value is what the class will be set to at the end.
The fact that you can inherit from a userdata, and then get another userdata instance should not be possible in regular Squirrel. This is an example of modifying the scripting language to fit our needs.
[<- Prev][QScriptRundown1.md] | [Next ->][QScriptRundown3.md]

View File

@@ -0,0 +1,114 @@
# QScript Rundown Page 3
Lets talk about `QObject`s.
A full `QObject` structure looks like this:
```cpp
struct QObject
{
struct QClass* cls;
union QValue vars[];
};
```
The structure is pretty complex.
Lets try to understand it piece by piece.
A `QObject` contains a pointer to a `QClass`. The `QClass` pointer is shared by `QObject`s which use the same class.
The QObject also contains a list of [QValues][QValue] which are the individual unique variables of the QObject.
---
```cpp
struct QClass
{
const char* name;
int vars_count;
struct QVar* vars;
int methods_count;
struct QFunction* methods;
int sigs_count;
struct QInterface** sigs;
};
```
Let's go one level deeper and this is where we start to branch out. We will tackle `QVar* vars` first.
---
```cpp
struct QVar
{
enum QType type;
const char* name;
int size;
bool is_private;
union QValue defaultval;
};
```
`QVar` is basically a definition of a variable in a class. It stores the name, type, default value, etc. The `size` is used to determine the initial size of the string if the `type` is a `QType_String`
A `QClass` will store a pointer to a list of these, along with the amount. They are in fact, used as a reference to the `QValue vars[]` which are a 1:1 representation of the `QVar* vars*` in the class. In other words, an index in the `QVar* vars*` array in the `QClass` corresponds to the value in `QValue vars[]` in the QObject.
---
```cpp
enum QFunctionType
{
QFunction_Native,
QFunction_Scripting,
QFunction_Module,
QFunction_Void,
};
struct QFunction
{
int always_zero;
enum QFunctionType type;
union
{
QCFunc func_native;
QCallback* func_scripting;
QModuleFunction* func_module;
void* func_void;
};
};
```
`QFunction` is more of a wrapper around multiple types of functions. The each slot in the union has a corresponding `QFunctionType`. But what you might notice is the `always_zero` variable. Why is it there?
There is this quirk with scripting languages where they will write their entire scripting base libraries in their own C api, and then pass these base library functions as a normal pointer to the language. Which basically means that they will treat every C function as a regular function pointer and not a struct. Function pointers have a very special tendency to not be 0 (DUH).
We can take advantage of that by first checking if the `QFunction` `always_zero` is 0, and if its not, we just CALL the QFunction pointer directly. But if it is 0, we can be 99.9% sure that it is actually a `QFunction` struct and we can treat it as such.
---
```cpp
typedef struct
{
int count;
enum QType* types;
} QParams;
typedef struct
{
int count;
const char** names;
struct QParams* args;
} QInterface;
```
A `QInterface` is a list of function declarations. Not definitions. A `QInterface` only stores the name, and arguments of each function. The actual implementation is up to the `QClass`.
When a `QClass` inherits from another `QClass`, it creates a new `QInterface` the parent `QInterface` **pointers** get copied into the interface array before the new one. Not the `QInterface`s themselves. This saves on memory.
We plan on adding actual interface functionality to the scripting languages, showing off to functional scripting language developers what modern OOP languages can do.
---
[<- Prev][QScriptRundown2.md] | [Next ->][QScriptRundown4.md]

View File

@@ -0,0 +1,12 @@
# QScript Rundown Page 4
By the nature of QScript, it has been designed to be a appframework interface. It means that anything in the game can use it.
If you want to use QScript in your own dll, first you have to connect to it.
Use the `CreateInterfaceFn` function with the `QSCRIPT_INTERFACE_VERSION` parameter which will return a (IQScript*).
$_SMALL Remember to check for null values! _$
```cpp
qscript = (IQScript*)appSystemFactory(QSCRIPT_INTERFACE_VERSION, NULL)
```
(appSystemFactory is a `CreateInterfaceFn` you get in the `Init` or `Connect` function of a DLL class)