WIP: port alien swarm and extend engine for asw

This commit is contained in:
nillerusr
2023-10-03 20:02:58 +03:00
parent 7d3c0d8b5a
commit 8322130890
617 changed files with 161164 additions and 220 deletions
@@ -0,0 +1,473 @@
#include <windows.h>
#include <mmsystem.h> // multimedia timer (may need winmm.lib)
#include "App.h"
#include "ScriptSys.h"
#include "GameObj.h"
#include "ScriptObj.h"
#include "gmCall.h"
#include "InputKBWin32.h"
App* App::s_instancePtr = NULL;
App::App()
{
s_instancePtr = this;
}
App::~App()
{
s_instancePtr = NULL;
}
bool App::Init()
{
InputKBWin32::Get().Init();
// Init console
InitConsole();
// Init script system for game objects
ScriptSys::Init();
// Register app bindings
RegisterScriptBindings();
// Init timer
m_deltaTime = 0;
m_lastTime = timeGetTime();
// Compile and run script
ScriptSys::Get()->ExecuteFile("TestGameObj.gm");
//TEST REMOVE
// ClearScreen();
// SetColor(COLOR_YELLOW, COLOR_RED);
// SetCursor(10,10);
// Print("Hello");
// PrintAt(10,10,"Hello");
return true;
}
void App::Destroy()
{
ScriptSys::Destroy();
}
bool App::Update()
{
int curTime = timeGetTime();
m_deltaTime = curTime - m_lastTime;
m_lastTime = curTime;
// Update input
InputKBWin32::Get().Update();
// Execute some script
ScriptSys::Get()->Execute(m_deltaTime);
if(InputKBWin32::Get().IsKeyPressed('A'))
{
TestA();
}
else if(InputKBWin32::Get().IsKeyPressed('B'))
{
TestB();
}
else if(InputKBWin32::Get().IsKeyPressed('C'))
{
TestC();
}
if(InputKBWin32::Get().IsKeyPressed(VK_ESCAPE))
{
return false;
}
return true;
}
void App::InitConsole()
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
m_console = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(m_console, &csbi);
DWORD dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
m_screenSizeX = csbi.dwSize.X;
m_screenSizeY = csbi.dwSize.Y;
}
void App::TestA()
{
// Test create a game object and set member in script
GameObj* newObj = new GameObj;
printf("new GameObj = %x\n", newObj);
printf("GameObj.m_scriptObj = %x\n", newObj->GetScriptObj());
newObj->GetScriptObj()->SetMemberString("m_name", "MangoBoy");
newObj->GetScriptObj()->ExecuteGlobalFunctionOnThis("WhatsMyName");
delete newObj;
gmCall call;
if(call.BeginGlobalFunction(ScriptSys::Get()->GetMachine(), "RunGlobalObject"))
{
call.End();
}
}
void App::TestB()
{
// Test call script function that keeps running for a bit
gmCall call;
if(call.BeginGlobalFunction(ScriptSys::Get()->GetMachine(), "ThreadYieldTest"))
{
call.End();
}
}
void App::TestC()
{
// Quick test of collect garbage and cpp owned objects
GameObj* newObj = new GameObj;
printf("new GameObj = %x\n", newObj);
printf("GameObj.m_scriptObj = %x\n", newObj->GetScriptObj());
newObj->GetScriptObj()->SetMemberString("m_name", "PotatoHead");
//newObj->GetScriptObj()->ExecuteGlobalFunctionOnThis("WhatsMyName");
ScriptSys::Get()->GetMachine()->CollectGarbage(true);
delete newObj;
}
void App::SetCursor(int a_x, int a_y)
{
ClipScreenCoordsi(a_x, a_y);
COORD point;
point.X = (short) a_x;
point.Y = (short) a_y;
SetConsoleCursorPosition(m_console, point);
}
void App::ClearScreen()
{
COORD coordScreen = { 0, 0 };
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD dwConSize;
GetConsoleScreenBufferInfo(m_console, &csbi);
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
FillConsoleOutputCharacter(m_console, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
GetConsoleScreenBufferInfo(m_console, &csbi);
FillConsoleOutputAttribute(m_console, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
SetConsoleCursorPosition(m_console, coordScreen);
}
void App::Print(const char* a_string)
{
printf("%s", a_string);
}
void App::PrintAt(int a_x, int a_y, const char* a_string)
{
SetCursor(a_x, a_y);
Print(a_string);
}
int App::GetAttribFromColIndex(int a_colorIndex, bool a_isForeground)
{
// WARNING These struct must match the color enums
static int foreColors[COLOR_MAX]=
{
0, //COLOR_BLACK
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, //COLOR_WHITE,
FOREGROUND_RED, //COLOR_RED
FOREGROUND_GREEN, //COLOR_GREEN,
FOREGROUND_BLUE, //COLOR_BLUE,
FOREGROUND_RED | FOREGROUND_BLUE, //COLOR_MAGENTA,
FOREGROUND_GREEN | FOREGROUND_BLUE, //COLOR_CYAN,
FOREGROUND_RED | FOREGROUND_GREEN, //COLOR_YELLOW,
};
static int backColors[COLOR_MAX]=
{
0, //COLOR_BLACK
BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE, //COLOR_WHITE,
BACKGROUND_RED, //COLOR_RED
BACKGROUND_GREEN, //COLOR_GREEN,
BACKGROUND_BLUE, //COLOR_BLUE,
BACKGROUND_RED | BACKGROUND_BLUE, //COLOR_MAGENTA,
BACKGROUND_GREEN | BACKGROUND_BLUE, //COLOR_CYAN,
BACKGROUND_RED | BACKGROUND_GREEN, //COLOR_YELLOW,
};
if( (a_colorIndex < COLOR_MIN) && (a_colorIndex >= COLOR_MAX) )
{
if(a_isForeground)
{
return foreColors[COLOR_WHITE];
}
else
{
return backColors[COLOR_WHITE];
}
}
if(a_isForeground)
{
return foreColors[a_colorIndex];
}
else
{
return backColors[a_colorIndex];
}
}
void App::SetColor(int a_foreColorIndex, int a_backColorIndex)
{
int foreCol = GetAttribFromColIndex(a_foreColorIndex, true);
int backCol = GetAttribFromColIndex(a_backColorIndex, false);
int param = foreCol | backCol;
SetConsoleTextAttribute(m_console, (short) param);
}
bool App::ClipScreenCoordsf(float& a_posX, float& a_posY)
{
bool wasClipped = false;
if(a_posX < 0.0f)
{
a_posX = 0.0f;
wasClipped = true;
}
else if(a_posX >= (float)App::Get()->GetScreenSizeX())
{
a_posX = (float)(App::Get()->GetScreenSizeX() - 1);
wasClipped = true;
}
if(a_posY < 0.0f)
{
a_posY = 0.0f;
wasClipped = true;
}
else if(a_posY >= (float)App::Get()->GetScreenSizeY())
{
a_posY = (float)(App::Get()->GetScreenSizeY() - 1);
wasClipped = true;
}
return wasClipped;
}
bool App::ClipScreenCoordsi(int& a_posX, int& a_posY)
{
bool wasClipped = false;
if(a_posX < 0)
{
a_posX = 0;
wasClipped = true;
}
else if(a_posX >= App::Get()->GetScreenSizeX())
{
a_posX = App::Get()->GetScreenSizeX() - 1;
wasClipped = true;
}
if(a_posY < 0)
{
a_posY = 0;
wasClipped = true;
}
else if(a_posY >= App::Get()->GetScreenSizeY())
{
a_posY = App::Get()->GetScreenSizeY() - 1;
wasClipped = true;
}
return wasClipped;
}
//////////////////////////////////////////////////
// Script bindings
//////////////////////////////////////////////////
int GM_CDECL App::Console_Print(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(1);
GM_CHECK_STRING_PARAM(a_string, 0);
App::Get()->Print(a_string);
return GM_OK;
}
int GM_CDECL App::Console_SetCursor(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(2);
GM_CHECK_INT_PARAM(a_curX, 0);
GM_CHECK_INT_PARAM(a_curY, 1);
App::Get()->ClipScreenCoordsi(a_curX, a_curY);
App::Get()->SetCursor(a_curX, a_curY);
return GM_OK;
}
int GM_CDECL App::Console_SetColor(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(2);
GM_CHECK_INT_PARAM(a_foreCol, 0);
GM_CHECK_INT_PARAM(a_backCol, 1);
App::Get()->SetColor(a_foreCol, a_backCol);
return GM_OK;
}
int GM_CDECL App::Input_KeyPressed(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(1);
GM_CHECK_INT_PARAM(a_vKey, 0);
if(InputKBWin32::Get().IsKeyPressed(a_vKey))
{
a_thread->PushInt(1);
}
else
{
a_thread->PushInt(0);
}
return GM_OK;
}
int GM_CDECL App::Input_KeyDown(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(1);
GM_CHECK_INT_PARAM(a_vKey, 0);
if(InputKBWin32::Get().IsKeyDown(a_vKey))
{
a_thread->PushInt(1);
}
else
{
a_thread->PushInt(0);
}
return GM_OK;
}
void App::RegisterScriptBindings()
{
static gmFunctionEntry ConsoleLib[] =
{
/*gm
\lib Console
\brief Console Library
*/
/*gm
\function Print
\brief Print string at current cursor position
\param string a_string
*/
{"Print", Console_Print},
/*gm
\function SetCursor
\brief Set cursor position
\param int a_curX Cursor x position
\param int a_curY Cursor y position
*/
{"SetCursor", Console_SetCursor},
/*gm
\function SetColor
\brief Set text color
\param int a_foreCol Foreground color
\param int a_backCol Background color
*/
{"SetColor", Console_SetColor},
};
static gmFunctionEntry InputLib[] =
{
/*gm
\lib Console
\brief Console Library
*/
/*gm
\function KeyPressed
\brief Was this key pressed
\param int a_vKey windows virtual key code (Most match ascii uppercase)
\return true if key was pressed this frame
*/
{"KeyPressed", Input_KeyPressed},
/*gm
\function KeyDown
\brief Is this key down
\param int a_vKey windows virtual key code (Most match ascii uppercase)
\return true if is down
*/
{"KeyDown", Input_KeyDown},
};
gmMachine* machine = ScriptSys::Get()->GetMachine();
machine->RegisterLibrary(ConsoleLib, sizeof(ConsoleLib) / sizeof(ConsoleLib[0]), "Console");
machine->RegisterLibrary(InputLib, sizeof(InputLib) / sizeof(InputLib[0]), "Input");
// Make some global constants
machine->GetGlobals()->Set(machine, "COLOR_BLACK", gmVariable(GM_INT, COLOR_BLACK));
machine->GetGlobals()->Set(machine, "COLOR_WHITE", gmVariable(GM_INT, COLOR_WHITE));
machine->GetGlobals()->Set(machine, "COLOR_RED", gmVariable(GM_INT, COLOR_RED));
machine->GetGlobals()->Set(machine, "COLOR_GREEN", gmVariable(GM_INT, COLOR_GREEN));
machine->GetGlobals()->Set(machine, "COLOR_BLUE", gmVariable(GM_INT, COLOR_BLUE));
machine->GetGlobals()->Set(machine, "COLOR_MAGENTA", gmVariable(GM_INT, COLOR_MAGENTA));
machine->GetGlobals()->Set(machine, "COLOR_CYAN", gmVariable(GM_INT, COLOR_CYAN));
machine->GetGlobals()->Set(machine, "COLOR_YELLOW", gmVariable(GM_INT, COLOR_YELLOW));
}
@@ -0,0 +1,72 @@
//
// Example application
//
#include <Windows.h>
#include "gmThread.h"
class App
{
public:
enum
{
COLOR_MIN = 0,
COLOR_BLACK = COLOR_MIN,
COLOR_WHITE,
COLOR_RED,
COLOR_GREEN,
COLOR_BLUE,
COLOR_MAGENTA,
COLOR_CYAN,
COLOR_YELLOW,
COLOR_MAX
};
static App* Get() { return s_instancePtr; }
App();
~App();
bool Init();
void Destroy();
bool Update();
void SetCursor(int a_x, int a_y);
void ClearScreen();
void Print(const char* a_string);
void PrintAt(int a_x, int a_y, const char* a_string);
void SetColor(int a_foreColorIndex, int a_backColorIndex);
int GetScreenSizeX() { return m_screenSizeX; }
int GetScreenSizeY() { return m_screenSizeY; }
bool ClipScreenCoordsf(float& a_posX, float& a_posY);
bool ClipScreenCoordsi(int& a_posX, int& a_posY);
protected:
int GetAttribFromColIndex(int a_colorIndex, bool a_isForeground);
void InitConsole();
void RegisterScriptBindings();
static int GM_CDECL Console_Print(gmThread* a_thread);
static int GM_CDECL Console_SetCursor(gmThread* a_thread);
static int GM_CDECL Console_SetColor(gmThread* a_thread);
static int GM_CDECL Input_KeyPressed(gmThread* a_thread);
static int GM_CDECL Input_KeyDown(gmThread* a_thread);
void TestA();
void TestB();
void TestC();
int m_deltaTime;
int m_lastTime;
int m_screenSizeX;
int m_screenSizeY;
HANDLE m_console;
static App* s_instancePtr; ///< Ptr to instance of this class when created
};
@@ -0,0 +1,317 @@
//
// GameObj.cpp
//
#include <math.h>
#include "GameObj.h"
#include "App.h"
#include "ScriptObj.h"
#include "ScriptSys.h"
GameObj::GameObj()
{
m_scriptObj = NULL;
m_posX = -1;
m_posY = -1;
m_destX = m_posX;
m_destY = m_posY;
m_speed = 1.0f;
m_colorIndex = App::COLOR_WHITE;
m_scriptObj = new ScriptObj(this);
}
GameObj::~GameObj()
{
if(m_scriptObj)
{
delete m_scriptObj;
}
}
float GameObj::GetPosX() const
{
return m_posX;
}
float GameObj::GetPosY() const
{
return m_posY;
}
void GameObj::SetPos(const float a_x, const float a_y)
{
m_posX = a_x;
m_posY = a_y;
App::Get()->ClipScreenCoordsf(m_posX, m_posY);
m_destX = m_posX;
m_destY = m_posY;
}
void GameObj::MoveTo(const float a_x, const float a_y)
{
m_destX = a_x;
m_destY = a_y;
App::Get()->ClipScreenCoordsf(m_destX, m_destY);
}
void GameObj::SetSpeed(const float a_speed)
{
m_speed = a_speed;
}
float GameObj::GetSpeed()
{
return m_speed;
}
void GameObj::SetColor(int a_colorIndex)
{
if(a_colorIndex >= App::COLOR_MIN && a_colorIndex < App::COLOR_MAX)
{
m_colorIndex = a_colorIndex;
}
}
void GameObj::Update(float a_deltaTime)
{
// NOTE: A real game would probably not update each object each frame
// but instead only update an object in a particular way when required.
// This example will do all updating in one place, and do so each frame.
// Update movement
{
float dx = m_destX - m_posX;
float dy = m_destY - m_posY;
float len2 = dx*dx + dy*dy;
if(len2 > 0.0f)
{
float moveThisFrame = a_deltaTime * m_speed;
float distToGo = sqrtf(len2);
// We can reach dest this frame
if(moveThisFrame > distToGo)
{
m_posX = m_destX;
m_posY = m_destY;
}
else
{
m_posX += dx * moveThisFrame;
m_posY += dy * moveThisFrame;
}
}
}
}
void GameObj::Render()
{
}
//////////////////////////////////////////////////
// Script
//////////////////////////////////////////////////
int GM_CDECL GameObj::GameObj_MoveTo(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(2);
GM_CHECK_FLOAT_PARAM(destX, 0);
GM_CHECK_FLOAT_PARAM(destY, 1);
GameObj* thisPtr = GetThisGameObj(a_thread);
if(!thisPtr)
{
return GM_EXCEPTION;
}
thisPtr->MoveTo(destX, destY);
return GM_OK;
}
int GM_CDECL GameObj::GameObj_SetPos(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(2);
GM_CHECK_FLOAT_PARAM(posX, 0);
GM_CHECK_FLOAT_PARAM(posY, 1);
GameObj* thisPtr = GetThisGameObj(a_thread);
if(!thisPtr)
{
return GM_EXCEPTION;
}
thisPtr->SetPos(posX, posY);
return GM_OK;
}
int GM_CDECL GameObj::GameObj_GetPosX(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(0);
GameObj* thisPtr = GetThisGameObj(a_thread);
if(!thisPtr)
{
return GM_EXCEPTION;
}
a_thread->PushFloat(thisPtr->GetPosX());
return GM_OK;
}
int GM_CDECL GameObj::GameObj_GetPosY(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(0);
GameObj* thisPtr = GetThisGameObj(a_thread);
if(!thisPtr)
{
return GM_EXCEPTION;
}
a_thread->PushFloat(thisPtr->GetPosY());
return GM_OK;
}
int GM_CDECL GameObj::GameObj_IsValid(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(0);
GameObj* thisPtr = GetThisGameObj(a_thread);
if(!thisPtr)
{
a_thread->PushInt(false);
}
else
{
a_thread->PushInt(true);
}
return GM_OK;
}
int GM_CDECL GameObj::GameObj_SetSpeed(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(1);
GM_CHECK_FLOAT_PARAM(speed, 0);
GameObj* thisPtr = GetThisGameObj(a_thread);
if(!thisPtr)
{
return GM_EXCEPTION;
}
thisPtr->SetSpeed(speed);
return GM_OK;
}
int GM_CDECL GameObj::GameObj_GetSpeed(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(0);
GameObj* thisPtr = GetThisGameObj(a_thread);
if(!thisPtr)
{
return GM_EXCEPTION;
}
a_thread->PushFloat(thisPtr->GetSpeed());
return GM_OK;
}
int GM_CDECL GameObj::GameObj_SetColor(gmThread* a_thread)
{
GM_CHECK_NUM_PARAMS(1);
GM_CHECK_INT_PARAM(colorIndex, 0);
GameObj* thisPtr = GetThisGameObj(a_thread);
if(!thisPtr)
{
return GM_EXCEPTION;
}
thisPtr->SetColor(colorIndex);
return GM_OK;
}
void GameObj::RegisterScriptBindings()
{
static gmFunctionEntry gameObjTypeLib[] =
{
/*gm
\lib GameObj
\brief Game Object class
*/
/*gm
\function SetPos
\brief Set position
\param float a_posX New position X component
\param float a_posY New position Y component
*/
{"SetPos", GameObj_SetPos},
/*gm
\function GetPosX
\brief Get position X
\return float Get position X component.
*/
{"GetPosX", GameObj_GetPosX},
/*gm
\function GetPosY
\brief Get position Y
\return float Get position Y component.
*/
{"GetPosY", GameObj_GetPosY},
/*gm
\function IsValid
\brief Is this a valid object, or has it been deleted or such
\return int true if valid
*/
{"IsValid", GameObj_IsValid},
/*gm
\function SetSpeed
\brief Set speed
\param a_speed New speed
*/
{"SetSpeed", GameObj_SetSpeed},
/*gm
\function GetSpeed
\brief Get speed
\return float Current speed
*/
{"GetSpeed", GameObj_GetSpeed},
/*gm
\function SetColor
\brief Set color
\param a_color New color
*/
{"SetColor", GameObj_SetColor},
};
ScriptSys::Get()->GetMachine()->RegisterTypeLibrary(ScriptObj::GMTYPE_GAMEOBJ, gameObjTypeLib, sizeof(gameObjTypeLib) / sizeof(gameObjTypeLib[0]));
}
@@ -0,0 +1,61 @@
#ifndef GAMEOBJ_H
#define GAMEOBJ_H
#include "gmThread.h"
//
// GameObj.h
//
// Example game object that uses the script interface component
//
// Fwd decls
class ScriptObj;
class GameObj
{
public:
GameObj();
virtual ~GameObj();
ScriptObj* GetScriptObj() { return m_scriptObj; }
float GetPosX() const;
float GetPosY() const;
void SetPos(const float a_x, const float a_y);
void MoveTo(const float a_x, const float a_y);
void SetSpeed(const float a_speed);
float GetSpeed();
void SetColor(int a_colorIndex);
void Update(float a_deltaTime);
void Render();
static void RegisterScriptBindings();
private:
static int GM_CDECL GameObj_SetPos(gmThread* a_thread);
static int GM_CDECL GameObj_GetPosX(gmThread* a_thread);
static int GM_CDECL GameObj_GetPosY(gmThread* a_thread);
static int GM_CDECL GameObj_IsValid(gmThread* a_thread);
static int GM_CDECL GameObj_MoveTo(gmThread* a_thread);
static int GM_CDECL GameObj_SetSpeed(gmThread* a_thread);
static int GM_CDECL GameObj_GetSpeed(gmThread* a_thread);
static int GM_CDECL GameObj_SetColor(gmThread* a_thread);
ScriptObj* m_scriptObj;
float m_posX;
float m_posY;
float m_destX;
float m_destY;
float m_speed;
int m_colorIndex;
};
#endif //GAMEOBJ_H
@@ -0,0 +1,470 @@
# Microsoft Developer Studio Project File - Name="GameObject" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=GameObject - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "GameObject.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "GameObject.mak" CFG="GameObject - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "GameObject - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "GameObject - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "Perforce Project"
# PROP Scc_LocalPath "..\.."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "GameObject - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\gm" /I "..\..\platform\win32msvc" /I "..\..\binds" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0xc09 /d "NDEBUG"
# ADD RSC /l 0xc09 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "GameObject - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\gm" /I "..\..\platform\win32msvc" /I "..\..\binds" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0xc09 /d "_DEBUG"
# ADD RSC /l 0xc09 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "GameObject - Win32 Release"
# Name "GameObject - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\App.cpp
# End Source File
# Begin Source File
SOURCE=.\App.h
# End Source File
# Begin Source File
SOURCE=.\GameObj.cpp
# End Source File
# Begin Source File
SOURCE=.\GameObj.h
# End Source File
# Begin Source File
SOURCE=.\InputKBWin32.cpp
# End Source File
# Begin Source File
SOURCE=.\InputKBWin32.h
# End Source File
# Begin Source File
SOURCE=.\main.cpp
# End Source File
# Begin Source File
SOURCE=.\NetClient.cpp
# End Source File
# Begin Source File
SOURCE=.\NetClient.h
# End Source File
# Begin Source File
SOURCE=.\ReadMe.txt
# End Source File
# Begin Source File
SOURCE=.\ScriptObj.cpp
# End Source File
# Begin Source File
SOURCE=.\ScriptObj.h
# End Source File
# Begin Source File
SOURCE=.\ScriptSys.cpp
# End Source File
# Begin Source File
SOURCE=.\ScriptSys.h
# End Source File
# Begin Source File
SOURCE=.\StdStuff.cpp
# End Source File
# Begin Source File
SOURCE=.\StdStuff.h
# End Source File
# Begin Source File
SOURCE=.\TestGameObj.gm
# End Source File
# End Group
# Begin Group "gm"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\gm\gmArraySimple.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmArraySimple.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmByteCode.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmByteCode.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmByteCodeGen.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmByteCodeGen.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeGen.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeGen.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeGenHooks.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeGenHooks.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeTree.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeTree.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmConfig.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCrc.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCrc.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmDebug.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmDebug.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmFunctionObject.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmFunctionObject.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmHash.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmHash.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmIncGC.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmIncGC.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmIterator.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmLibHooks.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmLibHooks.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmListDouble.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmListDouble.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmLog.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmLog.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMachine.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMachine.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMachineLib.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMachineLib.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMem.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMem.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemChain.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemChain.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemFixed.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemFixed.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemFixedSet.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemFixedSet.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmOperators.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmOperators.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmParser.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmParser.cpp.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmScanner.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmScanner.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStream.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStream.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStreamBuffer.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStreamBuffer.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStringObject.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStringObject.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmTableObject.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmTableObject.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmThread.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmThread.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmUserObject.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmUserObject.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmUtil.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmUtil.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmVariable.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmVariable.h
# End Source File
# End Group
# Begin Group "gmBinds"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\binds\gmCall.cpp
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmCall.h
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmHelpers.cpp
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmHelpers.h
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmMathLib.cpp
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmMathLib.h
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmStringLib.cpp
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmStringLib.h
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmSystemLib.cpp
# End Source File
# Begin Source File
SOURCE=..\..\binds\gmSystemLib.h
# End Source File
# End Group
# Begin Group "gmConfig"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\platform\win32msvc\gmConfig_p.h
# End Source File
# End Group
# End Target
# End Project
@@ -0,0 +1,33 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "GameObject"=.\GameObject.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
Perforce Project
..\..
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,102 @@
//
// InputKBWin32.cpp
//
#include <windows.h>
#include "InputKBWin32.h"
// Init statics and constants
InputKBWin32 InputKBWin32::s_staticInstance;
InputKBWin32::InputKBWin32()
{
m_keyDownBufferIndex = 0;
Init();
}
InputKBWin32::~InputKBWin32()
{
}
void InputKBWin32::Init()
{
for(int kIndex=0; kIndex<MAX_KEYS; ++kIndex)
{
m_keyDownBuffer[0][kIndex] = 0;
m_keyDownBuffer[1][kIndex] = 0;
m_keyStatus[kIndex] = KEY_STATUS_UP;
}
}
void InputKBWin32::Update()
{
//#define HAS_WINDOW_UPDATE // Define this if we have a window and a message pump
int lastBuffIndex = !m_keyDownBufferIndex;
int curBuffIndex = m_keyDownBufferIndex;
m_keyDownBufferIndex = lastBuffIndex; // Flip buffers
char* bufferCurrent = &m_keyDownBuffer[curBuffIndex][0];
char* bufferLast = &m_keyDownBuffer[lastBuffIndex][0];
// Get the button states from Win32
#ifdef HAS_WINDOW_UPDATE
// We have a window and message pump
BYTE win32KeyBuffer[256];
GetKeyboardState(win32KeyBuffer);
#else // HAS_WINDOW_UPDATE
short win32KeyBuffer[256];
for(int vkIndex=0; vkIndex < 256; ++vkIndex)
{
win32KeyBuffer[vkIndex] = GetAsyncKeyState(vkIndex);
}
#endif //HAS_WINDOW_UPDATE
// Find state changes
for(int kIndex=0; kIndex < MAX_KEYS; ++kIndex)
{
int status;
// Convert win32 keystate to true / false
#ifdef HAS_WINDOW_UPDATE
if(win32KeyBuffer[kIndex] & (1<<7))
#else // HAS_WINDOW_UPDATE
if(win32KeyBuffer[kIndex] & (1<<15))
#endif // HAS_WINDOW_UPDATE
{
bufferCurrent[kIndex] = true;
}
else
{
bufferCurrent[kIndex] = false;
}
status = 0;
if(bufferCurrent[kIndex])
{
status |= KEY_STATUS_DOWN;
if(!bufferLast[kIndex])
{
status |= KEY_STATUS_PRESSED;
}
}
else
{
status |= KEY_STATUS_UP;
if(bufferLast[kIndex])
{
status |= KEY_STATUS_RELEASED;
}
}
m_keyStatus[kIndex] = status;
}
}
@@ -0,0 +1,90 @@
#ifndef INPUTKBWIN32_H
#define INPUTKBWIN32_H
//
// InputKBWin32.h
//
#include "gmThread.h" // For some basic types
/// A simple keyboard input class for Win32.
class InputKBWin32
{
public:
enum
{
MAX_KEYS = 256, ///< Max keys on keyboard (for buffer size etc.)
};
enum
{
KEY_STATUS_UNKNOWN = 0, ///< Invalid status
KEY_STATUS_UP = (1<<0), ///< Button is up
KEY_STATUS_RELEASED = (1<<1), ///< Button released this frame
KEY_STATUS_DOWN = (1<<2), ///< Button is down
KEY_STATUS_PRESSED = (1<<3), ///< Button pressed this frame
};
/// Access single instance of this class
static InputKBWin32& Get() { return s_staticInstance; }
/// Destructor
virtual ~InputKBWin32();
/// Initialize. Call before use.
void Init();
/// Call each frame.
void Update();
/// What is the status of a key. Returns one of the KEY_STATUS_* enums.
inline int GetKeyStatus(int a_keyIndex)
{
GM_ASSERT((a_keyIndex >=0) && (a_keyIndex < MAX_KEYS));
return m_keyStatus[a_keyIndex];
}
/// Was key pressed this frame? (Non-zero if true)
inline int IsKeyPressed(int a_keyIndex)
{
GM_ASSERT((a_keyIndex >= 0) && (a_keyIndex < MAX_KEYS));
return (m_keyStatus[a_keyIndex] & KEY_STATUS_PRESSED);
}
/// Is key down this frame? (Non-zero if true)
inline int IsKeyDown(int a_keyIndex)
{
GM_ASSERT((a_keyIndex >= 0) && (a_keyIndex < MAX_KEYS));
return (m_keyStatus[a_keyIndex] & KEY_STATUS_DOWN);
}
/// Was key released this frame? (Non-zero if true)
inline int IsKeyRelesed(int a_keyIndex)
{
GM_ASSERT((a_keyIndex >= 0) && (a_keyIndex < MAX_KEYS));
return (m_keyStatus[a_keyIndex] & KEY_STATUS_RELEASED);
}
/// Is key up this frame? (Non-zero if true)
inline int IsKeyUp(int a_keyIndex)
{
GM_ASSERT((a_keyIndex >= 0) && (a_keyIndex < MAX_KEYS));
return (m_keyStatus[a_keyIndex] & KEY_STATUS_UP);
}
private:
/// Constructor, non-public to prevent multiple instances
InputKBWin32();
char m_keyDownBuffer[2][MAX_KEYS]; ///< Store current and last frame snapshot
int m_keyDownBufferIndex; ///< Index to swap buffers for current and last frame
int m_keyStatus[MAX_KEYS]; ///< Status of keys for this frame, persists until updated.
static InputKBWin32 s_staticInstance; ///< Single instance of this class
};
#endif //INPUTKBWIN32_H
@@ -0,0 +1,356 @@
// See Copyright Notice in gmMachine.h
#include "NetClient.h"
#include <windows.h>
#include <process.h> // Requires Multi threaded library for _beginthread and _endthread
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>
#include <winsock.h> // Requires Ws2_32.lib
#include <math.h>
#undef SendMessage // stupid windows
// These two are for MSVS 2005 security consciousness until safe std lib funcs are available
#pragma warning(disable : 4996) // Deprecated functions
#define _CRT_SECURE_NO_DEPRECATE // Allow old unsecure standard library functions, Disable some 'warning C4996 - function was deprecated'
struct nPacket
{
int id; // id == 0x4fe27d9a
int len;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// QUEUE
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct nQueueNode
{
char * m_buffer;
int m_len;
nQueueNode * m_next;
};
class nQueue
{
public:
nQueue()
{
m_queue = NULL;
m_lastDeQueue = NULL;
m_mutex = CreateMutex(NULL, FALSE, NULL);
}
~nQueue()
{
WaitForSingleObject(m_mutex, INFINITE);
int a;
while(DeQueue(a));
DeQueue(a);
ReleaseMutex(m_mutex);
// destroy mutex... todo
}
bool EnQueue(const char * a_buffer, int a_len)
{
WaitForSingleObject(m_mutex, INFINITE);
nQueueNode * node = new nQueueNode;
node->m_len = a_len;
node->m_buffer = new char[a_len];
memcpy(node->m_buffer, a_buffer, a_len);
node->m_next = NULL;
// add to end of list
nQueueNode ** n = &m_queue;
while(*n) n = &(*n)->m_next;
*n = node;
ReleaseMutex(m_mutex);
return true;
}
const char * DeQueue(int &a_len)
{
const char * ret = NULL;
WaitForSingleObject(m_mutex, INFINITE);
if(m_lastDeQueue)
{
delete[] m_lastDeQueue->m_buffer;
delete m_lastDeQueue;
m_lastDeQueue = NULL;
}
if(m_queue)
{
m_lastDeQueue = m_queue;
m_queue = m_queue->m_next;
a_len = m_lastDeQueue->m_len;
ret = m_lastDeQueue->m_buffer;
}
ReleaseMutex(m_mutex);
return ret;
}
bool IsEmpty() { return (m_queue == NULL); }
private:
HANDLE m_mutex;
nQueueNode * m_lastDeQueue;
nQueueNode * m_queue;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// CLIENT
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct nClientData
{
SOCKET client;
nQueue messages;
CRITICAL_SECTION criticalSection;
bool threadAlive;
};
nClient::nClient()
{
nClientData * cd = new nClientData;
cd->threadAlive = false;
cd->client = INVALID_SOCKET;
InitializeCriticalSection(&cd->criticalSection);
m_data = cd;
}
nClient::~nClient()
{
Close();
nClientData * cd = (nClientData *) m_data;
DeleteCriticalSection(&cd->criticalSection);
delete cd;
}
void nClient::Close()
{
nClientData * cd = (nClientData *) m_data;
EnterCriticalSection(&cd->criticalSection);
if(cd->client != INVALID_SOCKET)
{
closesocket(cd->client);
cd->client = INVALID_SOCKET;
}
LeaveCriticalSection(&cd->criticalSection);
// wait for the thread to die.
while(cd->threadAlive)
{
_sleep(0);
}
WSACleanup();
}
bool nClient::IsConnected()
{
bool result = false;
nClientData * cd = (nClientData *) m_data;
EnterCriticalSection(&cd->criticalSection);
if(cd->client != INVALID_SOCKET)
{
result = true;
}
LeaveCriticalSection(&cd->criticalSection);
return result;
}
bool nClient::SendMessage(const char * a_buffer, int a_len)
{
bool res = false;
nClientData * cd = (nClientData *) m_data;
nPacket packet;
packet.id = 0x4fe27d9a;
packet.len = a_len;
EnterCriticalSection(&cd->criticalSection);
if(cd->client != INVALID_SOCKET)
{
send(cd->client, (const char *) &packet, sizeof(nPacket), 0);
send(cd->client, (const char *) a_buffer, a_len, 0);
res = true;
}
LeaveCriticalSection(&cd->criticalSection);
return res;
}
const char * nClient::PumpMessage(int &a_len)
{
nClientData * cd = (nClientData *) m_data;
const char * buffer = cd->messages.DeQueue(a_len);
return buffer;
}
void nClientThread(void * param)
{
nClientData * cd = (nClientData *) param;
EnterCriticalSection(&cd->criticalSection);
cd->threadAlive = true;
SOCKET client = cd->client;
LeaveCriticalSection(&cd->criticalSection);
char * dbuffer = NULL;
char buffer[4096];
char * sbp;
int state = 0; // 0 searching for packet, 1 getting message
int need = sizeof(nPacket);
// packet header
nPacket packet;
char * dbp = (char *) &packet;
// packet data
int dbufferSize = 0, n;
// read loop
for(;;)
{
// read
n = recv(client, buffer, 4096, 0);
if(n == SOCKET_ERROR || n == 0) break;
sbp = buffer;
// consume
while(n > 0)
{
int have = (n > need) ? need : n;
need -= have;
n -= have;
memcpy(dbp, sbp, have);
sbp += have;
dbp += have;
// can we change state?
if(need == 0)
{
if(state == 0)
{
if(packet.id != 0x4fe27d9a) goto terror;
state = 1;
need = packet.len;
// allocate the dbuffer
if(need > dbufferSize)
{
if(dbuffer) { delete[] dbuffer; }
dbufferSize = need + 512;
dbuffer = new char[dbufferSize];
}
dbp = dbuffer;
}
else if(state == 1)
{
cd->messages.EnQueue(dbuffer, packet.len);
dbp = (char *) &packet;
need = sizeof(nPacket);
state = 0;
}
}
}
}
terror:
if(dbuffer) { delete[] dbuffer; }
EnterCriticalSection(&cd->criticalSection);
cd->threadAlive = false;
LeaveCriticalSection(&cd->criticalSection);
_endthread();
}
bool nClient::Connect(const char * a_server, short a_port)
{
WSADATA wsaData;
struct hostent *hp;
unsigned int addr;
struct sockaddr_in server;
int wsaret=WSAStartup(0x101,&wsaData);
if(wsaret)
return false;
SOCKET conn;
conn = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(conn==INVALID_SOCKET)
return false;
addr=inet_addr(a_server);
hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
if(hp==NULL)
{
closesocket(conn);
return false;
}
server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
server.sin_family=AF_INET;
server.sin_port=htons((u_short) a_port);
if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
{
closesocket(conn);
return false;
}
nClientData * cd = (nClientData *) m_data;
EnterCriticalSection(&cd->criticalSection);
cd->client = conn;
LeaveCriticalSection(&cd->criticalSection);
_beginthread(nClientThread, 0, cd);
_sleep(0);
return true;
}
@@ -0,0 +1,30 @@
#ifndef _NETCLIENT_H_
#define _NETCLIENT_H_
// See Copyright Notice in gmMachine.h
#undef SendMessage // windows clash
//
// nClient
//
class nClient
{
public:
nClient();
~nClient();
bool Connect(const char * a_server, short a_port);
void Close();
bool IsConnected();
bool SendMessage(const char * a_buffer, int a_len);
const char * PumpMessage(int &a_len);
private:
void * m_data;
};
#endif //_NETCLIENT_H_
@@ -0,0 +1,10 @@
This example is simply one way to implement 'Game Objects'. The example is a work in
progress, and is included because some of the code may provide useful to look at.
TODO
o make 'triggers' and 'units'
o make IsUnitInSquare function to clip movement
o use states for units to be 'player' 'following' 'mental'
o make triggers that change unit color and triggers that create mental state if not player
o highlight player by color and allow player to cycle through units to control
@@ -0,0 +1,326 @@
//
// ScriptObj.cpp
//
#include "gmCall.h"
#include "ScriptObj.h"
#include "ScriptSys.h"
#include "GameObj.h"
// Init statics and constants
gmType ScriptObj::GMTYPE_GAMEOBJ = -1;
ScriptObj::ScriptObj(GameObj* a_gameObj)
{
GM_ASSERT(ScriptSys::Get());
m_userObject = NULL; // A user object will be created when it is first used, and shared by all script variables.
m_gameObj = a_gameObj;
m_tableObject = ScriptSys::Get()->GetMachine()->AllocTableObject();
ScriptSys::Get()->GetMachine()->AddCPPOwnedGMObject(m_tableObject);
}
ScriptObj::~ScriptObj()
{
// Stop related threads
KillThreads();
if(m_userObject)
{
// Nullify script link to C object
m_userObject->m_user = NULL;
}
// Destruct the gmObjects
#if GM_USE_INCGC
// Do nothing, it will be collected later, just nullify all reference to it
#else
if(m_userObject)
{
m_userObject->Destruct(ScriptSys::Get()->GetMachine());
}
m_tableObject->Destruct(ScriptSys::Get()->GetMachine());
#endif
// Remove object from the list of all objects
ScriptSys::Get()->GetMachine()->RemoveCPPOwnedGMObject(m_tableObject);
if( m_userObject )
{
ScriptSys::Get()->GetMachine()->RemoveCPPOwnedGMObject(m_userObject);
}
}
gmUserObject* ScriptObj::GetUserObject()
{
if(!m_userObject)
{
m_userObject = ScriptSys::Get()->GetMachine()->AllocUserObject(this, GMTYPE_GAMEOBJ);
ScriptSys::Get()->GetMachine()->AddCPPOwnedGMObject(m_userObject);
}
return m_userObject;
}
void ScriptObj::KillThreads()
{
for(unsigned int tIndex=0; tIndex<m_threads.GetSize(); ++tIndex)
{
ScriptSys::Get()->RemoveThreadIdButDontTouchGameObj(m_threads[tIndex]);
ScriptSys::Get()->GetMachine()->KillThread(m_threads[tIndex]);
}
m_threads.Reset();
}
void ScriptObj::ExecuteStringOnThis(const char* a_string)
{
gmMachine* machine = ScriptSys::Get()->GetMachine();
gmVariable thisVar;
thisVar.SetUser(GetUserObject());
int threadId = GM_INVALID_THREAD;
int errors = machine->ExecuteString(a_string, &threadId, true, NULL, &thisVar);
if(errors)
{
bool first = true;
const char * message;
while((message = machine->GetLog().GetEntry(first)))
{
ScriptSys::Get()->LogError("%s\n", message);
}
machine->GetLog().Reset();
}
else
{
ScriptSys::Get()->AssociateThreadIdWithGameObj(threadId, *GetGameObj());
}
}
bool ScriptObj::ExecuteGlobalFunctionOnThis(const char* a_functionName)
{
gmVariable thisVar;
thisVar.SetUser(GetUserObject());
gmCall call;
if(call.BeginGlobalFunction(ScriptSys::Get()->GetMachine(), a_functionName, thisVar, false))
{
call.End();
return true;
}
return false;
}
void ScriptObj::SetMemberInt(const char* a_memberName, int a_int)
{
ScriptSys::Get()->SetTableInt(a_memberName, a_int, m_tableObject);
}
void ScriptObj::SetMemberFloat(const char* a_memberName, float a_float)
{
ScriptSys::Get()->SetTableFloat(a_memberName, a_float, m_tableObject);
}
void ScriptObj::SetMemberString(const char* a_memberName, const char* a_string, int a_strLength)
{
ScriptSys::Get()->SetTableString(a_memberName, a_string, a_strLength, m_tableObject);
}
void ScriptObj::SetMemberGameObj(const char* a_memberName, GameObj* a_gameObj)
{
ScriptSys::Get()->SetTableGameObj(a_memberName, a_gameObj, m_tableObject);
}
gmTableObject* ScriptObj::SetMemberTable(const char* a_memberName)
{
return ScriptSys::Get()->SetTableTable(a_memberName, m_tableObject);
}
bool ScriptObj::GetMemberInt(const char* a_memberName, int& a_int)
{
return ScriptSys::Get()->GetTableInt(a_memberName, a_int, m_tableObject);
}
bool ScriptObj::GetMemberFloat(const char* a_memberName, float& a_float)
{
return ScriptSys::Get()->GetTableFloat(a_memberName, a_float, m_tableObject);
}
bool ScriptObj::GetMemberString(const char* a_memberName, String& a_string)
{
return ScriptSys::Get()->GetTableString(a_memberName, a_string, m_tableObject);
}
bool ScriptObj::GetMemberGameObj(const char* a_memberName, GameObj*& a_gameObj)
{
return ScriptSys::Get()->GetTableGameObj(a_memberName, a_gameObj, m_tableObject);
}
bool ScriptObj::GetMemberTable(const char* a_memberName, gmTableObject*& a_retTable)
{
return ScriptSys::Get()->GetTableTable(a_memberName, a_retTable, m_tableObject);
}
void GM_CDECL ScriptObj::GameObjCallback_AsString(gmUserObject * a_object, char* a_buffer, int a_bufferLen)
{
char mixBuffer[128];
ScriptObj* scriptObj = (ScriptObj*)a_object->m_user;
GameObj* gameObjPtr = NULL;
if(scriptObj)
{
gameObjPtr = scriptObj->GetGameObj();
}
sprintf(mixBuffer,"CPtr: %x", gameObjPtr);
int mixLength = strlen(mixBuffer);
int useLength = gmMin(mixLength, a_bufferLen-1);
GM_ASSERT(useLength > 0);
strncpy(a_buffer, mixBuffer, useLength);
a_buffer[useLength] = 0;
}
#if GM_USE_INCGC
bool GM_CDECL ScriptObj::GameObjCallback_GCTrace(gmMachine * a_machine, gmUserObject* a_object, gmGarbageCollector* a_gc, const int a_workRemaining, int& a_workDone)
{
GM_ASSERT(a_object->m_userType == GMTYPE_GAMEOBJ);
ScriptObj* scriptObj = (ScriptObj*)a_object->m_user;
if(scriptObj)
{
a_gc->GetNextObject(scriptObj->GetTableObject());
}
a_workDone +=2;
return true;
}
void GM_CDECL ScriptObj::GameObjCallback_GCDestruct(gmMachine * a_machine, gmUserObject * a_object)
{
GM_ASSERT(a_object->m_userType == GMTYPE_GAMEOBJ);
ScriptObj* scriptObj = (ScriptObj*)a_object->m_user;
if(scriptObj)
{
scriptObj->m_userObject = NULL;
}
}
#else //GM_USE_INCGC
void GM_CDECL ScriptObj::GameObjCallback_GCMark(gmMachine * a_machine, gmUserObject * a_object, gmuint32 a_mark)
{
GM_ASSERT(a_object->m_userType == GMTYPE_GAMEOBJ);
ScriptObj* scriptObj = (ScriptObj*)a_object->m_user;
if(scriptObj)
{
if(scriptObj->GetTableObject()->NeedsMark(a_mark))
{
scriptObj->GetTableObject()->Mark(a_machine, a_mark);
}
}
}
void GM_CDECL ScriptObj::GameObjCallback_GCCollect(gmMachine * a_machine, gmUserObject * a_object, gmuint32 a_mark)
{
GM_ASSERT(a_object->m_userType == GMTYPE_GAMEOBJ);
ScriptObj* scriptObj = (ScriptObj*)a_object->m_user;
if(scriptObj)
{
scriptObj->m_userObject = NULL;
}
}
#endif //GM_USE_INCGC
// NOTE: If you wanted to enable other dot operator behavior
// here is the place to do it, in the GetDot and SetDot operators.
// This example merely uses the gmTable embedded in the GameObj
// to allow script functions and data to be members of this object type.
// GameObj also registers 'type' functions that are accessed via the
// dot operator.
void GM_CDECL ScriptObj::GameObj_GetDot(gmThread * a_thread, gmVariable * a_operands)
{
//O_GETDOT = 0, // object, "member" (tos is a_operands + 2)
GM_ASSERT(a_operands[0].m_type == GMTYPE_GAMEOBJ);
gmUserObject* userObj = (gmUserObject*) GM_OBJECT(a_operands[0].m_value.m_ref);
ScriptObj* scriptObj = (ScriptObj*)userObj->m_user;
if(!scriptObj)
{
a_operands[0].Nullify();
return;
}
a_operands[0] = scriptObj->GetTableObject()->Get(a_operands[1]);
}
void GM_CDECL ScriptObj::GameObj_SetDot(gmThread * a_thread, gmVariable * a_operands)
{
//O_SETDOT, // object, value, "member" (tos is a_operands + 3)
GM_ASSERT(a_operands[0].m_type == GMTYPE_GAMEOBJ);
gmUserObject* userObj = (gmUserObject*) GM_OBJECT(a_operands[0].m_value.m_ref);
ScriptObj* scriptObj = (ScriptObj*)userObj->m_user;
if(scriptObj)
{
scriptObj->GetTableObject()->Set(a_thread->GetMachine(), a_operands[2], a_operands[1]);
}
}
void ScriptObj::RegisterScriptBindings()
{
gmMachine* machine = ScriptSys::Get()->GetMachine();
GM_ASSERT(machine);
// Register new user type
GMTYPE_GAMEOBJ = machine->CreateUserType("GameObj");
// Register garbage collection for our new type
#if GM_USE_INCGC
machine->RegisterUserCallbacks(GMTYPE_GAMEOBJ, GameObjCallback_GCTrace, GameObjCallback_GCDestruct, GameObjCallback_AsString);
#else //GM_USE_INCGC
machine->RegisterUserCallbacks(GMTYPE_GAMEOBJ, GameObjCallback_GCMark, GameObjCallback_GCCollect, GameObjCallback_AsString);
#endif //GM_USE_INCGC
// Bind Get dot operator for our type
machine->RegisterTypeOperator(GMTYPE_GAMEOBJ, O_GETDOT, NULL, GameObj_GetDot);
// Bind Set dot operator for our type
machine->RegisterTypeOperator(GMTYPE_GAMEOBJ, O_SETDOT, NULL, GameObj_SetDot);
// Bind functions
// machine->RegisterLibrary(regFuncList, sizeof(regFuncList) / sizeof(regFuncList[0]));
// Bind type functions
// machine->RegisterTypeLibrary(GM_GOB, regTypeFuncList, sizeof(regTypeFuncList) / sizeof(regTypeFuncList[0]));
}
@@ -0,0 +1,165 @@
#ifndef SCRIPTOBJ_H
#define SCRIPTOBJ_H
//
// ScriptObj.h
//
// Example script interface component for game object
//
#include "gmThread.h"
#include "StdStuff.h"
// Fwd decls
class GameObj;
// NOTE: In this implementation, the 'gmUserObject' only exists when the cpp object is used or needed by script.
// This implementation also shares that single user object amongst all referencing variables in script.
// Because of this, the cpp code does not need to handle the user object as if it were owned by cpp.
// The cpp object does however always contain a gmTableObject, and this is owned by cpp as it may not
// exist (be referenced) within the script. For this reason, the gmTableObject must be handled as a
// cpp owned object to allow correct GC handling.
//
// An alternate method, would be to always have a gmUserObject and let cpp code own this. This
// user object would be the root of its own child objects like the gmTableObject. This method may
// be simpler.
//
// Script interface for game objects
class ScriptObj
{
public:
static gmType GMTYPE_GAMEOBJ; ///< The user type of a game object
static void RegisterScriptBindings(); ///< Register game object script bindings
ScriptObj(GameObj* a_gameObj);
virtual ~ScriptObj();
GameObj* GetGameObj() { return m_gameObj; }
gmTableObject* GetTableObject() { return m_tableObject; }
gmUserObject* GetUserObject();
void AddThreadId(int a_threadId)
{
m_threads.InsertLast(a_threadId);
}
void RemoveThreadId(int a_threadId)
{
for(unsigned int tIndex=0; tIndex < m_threads.GetSize(); ++tIndex)
{
if(m_threads[tIndex] == a_threadId)
{
m_threads.RemoveSwapLast(tIndex);
}
}
}
/// Kill all threads running on this object
void KillThreads();
void ExecuteStringOnThis(const char* a_string);
bool ExecuteGlobalFunctionOnThis(const char* a_functionName);
void SetMemberInt(const char* a_memberName, int a_int);
void SetMemberFloat(const char* a_memberName, float a_float);
void SetMemberString(const char* a_memberName, const char* a_string, int a_strLength = -1);
void SetMemberGameObj(const char* a_memberName, GameObj* a_gameObj);
gmTableObject* SetMemberTable(const char* a_memberName);
bool GetMemberInt(const char* a_memberName, int& a_int);
bool GetMemberFloat(const char* a_memberName, float& a_float);
bool GetMemberString(const char* a_memberName, String& a_string);
bool GetMemberGameObj(const char* a_memberName, GameObj*& a_gameObj);
bool GetMemberTable(const char* a_memberName, gmTableObject*& a_retTable);
protected:
static void GM_CDECL GameObjCallback_AsString(gmUserObject * a_object, char* a_buffer, int a_bufferLen);
#if GM_USE_INCGC
static bool GM_CDECL GameObjCallback_GCTrace(gmMachine * a_machine, gmUserObject* a_object, gmGarbageCollector* a_gc, const int a_workRemaining, int& a_workDone);
static void GM_CDECL GameObjCallback_GCDestruct(gmMachine * a_machine, gmUserObject * a_object);
#else //GM_USE_INCGC
static void GM_CDECL GameObjCallback_GCMark(gmMachine * a_machine, gmUserObject * a_object, gmuint32 a_mark);
static void GM_CDECL GameObjCallback_GCCollect(gmMachine * a_machine, gmUserObject * a_object, gmuint32 a_mark);
#endif //GM_USE_INCGC
static void GM_CDECL GameObj_GetDot(gmThread * a_thread, gmVariable * a_operands);
static void GM_CDECL GameObj_SetDot(gmThread * a_thread, gmVariable * a_operands);
GameObj* m_gameObj; ///< The game object owner of this interface
gmUserObject* m_userObject; ///< The script object
gmTableObject* m_tableObject; ///< Table functionality for script object members
gmArraySimple<int> m_threads; ///< Threads associated with this game object
};
/*
/// \brief Get 'this' as GameObj of TYPE
/// Eg. Soldier* obj = GetThisGameObj<Soldier>(a_thread);
template<class TYPE>
TYPE* GetThisGameObj(gmThread* a_thread)
{
GM_ASSERT(a_thread->GetThis()->m_type == ScriptObj::GMTYPE_GAMEOBJ); //Paranoid check for type function
ScriptObj* scriptObj = (ScriptObj*)a_thread->ThisUser();
CHECK(scriptObj); //Check for null GameObj ptr
// You can check for valid derived type here
return static_cast<TYPE*>(scriptObj->GetGameObj());
}
/// \brief Get param as GameObj of TYPE
/// Eg. Soldier* obj = GetGameObjParam<Soldier>(a_thread, 0);
template<class TYPE>
TYPE* GetGameObjParam(gmThread* a_thread, int a_paramIndex)
{
ScriptObj* scriptObj = (ScriptObj*)a_thread->ParamUserCheckType(a_paramIndex, ScriptObj::GMTYPE_GAMEOBJ);
CHECK(scriptObj); //Check for null GameObj ptr
// You can check for valid derived type here
return static_cast<TYPE*>(scriptObj->GetGameObj());
}
*/
/// \brief Get 'this' as GameObj of TYPE
inline GameObj* GetThisGameObj(gmThread* a_thread)
{
GM_ASSERT(a_thread->GetThis()->m_type == ScriptObj::GMTYPE_GAMEOBJ); //Paranoid check for type function
ScriptObj* scriptObj = (ScriptObj*)a_thread->ThisUser();
if(!scriptObj)
{
return NULL;
}
return scriptObj->GetGameObj();
}
/// \brief Get param as GameObj of TYPE
inline GameObj* GetGameObjParam(gmThread* a_thread, int a_paramIndex)
{
ScriptObj* scriptObj = (ScriptObj*)a_thread->ParamUserCheckType(a_paramIndex, ScriptObj::GMTYPE_GAMEOBJ);
if(!scriptObj)
{
return NULL;
}
return scriptObj->GetGameObj();
}
#endif //SCRIPTOBJ_H
@@ -0,0 +1,432 @@
//
// ScriptSys.cpp
//
#include "gmCall.h"
#include "ScriptSys.h"
#include "ScriptObj.h"
#include "GameObj.h"
// Init statics and constants
ScriptSys* ScriptSys::s_instance = NULL;
const int ScriptSys::DEBUGGER_DEFAULT_PORT = 49001;
const char* ScriptSys::DEBUGGER_DEFAULT_IP = "127.0.0.1"; // localhost
void ScriptSys::Init()
{
GM_ASSERT( !s_instance ); // Just have one instance for this example
s_instance = new ScriptSys;
// Register Game Object type and bindings
ScriptObj::RegisterScriptBindings();
GameObj::RegisterScriptBindings();
}
void ScriptSys::Destroy()
{
delete s_instance;
s_instance = NULL;
}
void ScriptSys::DebuggerSendMessage(gmDebugSession * a_session, const void * a_command, int a_len)
{
nClient * client = (nClient *) a_session->m_user;
client->SendMessage((const char *) a_command, a_len);
}
const void* ScriptSys::DebuggerPumpMessage(gmDebugSession * a_session, int &a_len)
{
nClient * client = (nClient *) a_session->m_user;
return client->PumpMessage(a_len);
}
ScriptSys::ScriptSys()
{
m_machine = new gmMachine;
//Set machine callbacks
gmMachine::s_machineCallback = ScriptSysCallback_Machine;
gmMachine::s_printCallback = ScriptSysCallback_Print;
// Init debugger
gmBindDebugLib(m_machine); // Register debugging library
m_debuggerIP = DEBUGGER_DEFAULT_IP;
m_debuggerPort = DEBUGGER_DEFAULT_PORT;
m_debugSession.m_sendMessage = DebuggerSendMessage;
m_debugSession.m_pumpMessage = DebuggerPumpMessage;
m_debugSession.m_user = &m_debugClient;
if(m_debugClient.Connect(m_debuggerIP, ((short) m_debuggerPort)))
{
m_debugSession.Open(m_machine);
fprintf(stderr, "Debug session opened"GM_NL);
}
m_machine->SetDebugMode(true);
}
ScriptSys::~ScriptSys()
{
// End debugger session if any
m_debugSession.Close();
m_debugClient.Close();
// For debugging
_gmDumpLeaks();
delete m_machine;
}
void __cdecl ScriptSys::LogError(const char *a_str, ...)
{
// WARNING This is not safe for longer strings, should use non-ansi vsprintnf, string type, or similar.
const int MAX_CHARS = 512;
char buffer[MAX_CHARS];
va_list args;
va_start(args, a_str);
vsprintf(buffer, a_str, args);
va_end(args);
fprintf(stderr, "ERROR: %s", a_str);
}
GameObj* ScriptSys::GetGameObjFromThreadId(int a_threadId)
{
ScriptObj* scriptObj;
if(m_mapThreadGameObjs.GetAt(a_threadId, scriptObj))
{
return scriptObj->GetGameObj();
}
return NULL;
}
void ScriptSys::AssociateThreadIdWithGameObj(int a_threadId, GameObj& a_gameObj)
{
ScriptObj* scriptObj = a_gameObj.GetScriptObj();
scriptObj->AddThreadId(a_threadId);
m_mapThreadGameObjs.SetAt(a_threadId, scriptObj);
}
void ScriptSys::DisassociateThreadIdWithGameObj(int a_threadId)
{
ScriptObj* scriptObj;
if(m_mapThreadGameObjs.RemoveAt(a_threadId, scriptObj))
{
scriptObj->RemoveThreadId(a_threadId);
}
}
void ScriptSys::RemoveThreadIdButDontTouchGameObj(int a_threadId)
{
m_mapThreadGameObjs.RemoveAt(a_threadId);
}
void ScriptSys::SetTableNull(const char* a_memberName, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable newVar;
newVar.Nullify();
table->Set(m_machine, a_memberName, newVar);
}
void ScriptSys::SetTableInt(const char* a_memberName, int a_int, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable newVar;
newVar.SetInt(a_int);
table->Set(m_machine, a_memberName, newVar);
}
void ScriptSys::SetTableFloat(const char* a_memberName, float a_float, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable newVar;
newVar.SetFloat(a_float);
table->Set(m_machine, a_memberName, newVar);
}
void ScriptSys::SetTableString(const char* a_memberName, const char* a_string, int a_strLength, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable newVar;
newVar.SetString(m_machine->AllocStringObject(a_string, a_strLength));
table->Set(m_machine, a_memberName, newVar);
}
void ScriptSys::SetTableGameObj(const char* a_memberName, GameObj* a_gameObj, gmTableObject* a_table)
{
GM_ASSERT(a_table);
GM_ASSERT(a_gameObj);
gmTableObject* table = a_table;
gmVariable newVar;
newVar.SetUser(a_gameObj->GetScriptObj()->GetUserObject());
table->Set(m_machine, a_memberName, newVar);
}
gmTableObject* ScriptSys::SetTableTable(const char* a_memberName, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmMachine* machine = m_machine;
gmVariable newVar;
gmTableObject* newTable = machine->AllocTableObject();
newVar.SetTable(newTable);
table->Set(machine, a_memberName, newVar);
return newTable; //Return the table so we can potentially put things in it
}
bool ScriptSys::GetTableInt(const char* a_memberName, int& a_int, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable stringName;
gmVariable retVar;
stringName.SetString(m_machine->AllocStringObject(a_memberName));
retVar = table->Get(stringName);
if(retVar.m_type == GM_INT)
{
a_int = retVar.m_value.m_int;
return true;
}
return false;
}
bool ScriptSys::GetTableFloat(const char* a_memberName, float& a_float, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable stringName;
gmVariable retVar;
stringName.SetString(m_machine->AllocStringObject(a_memberName));
retVar = table->Get(stringName);
if(retVar.m_type == GM_FLOAT)
{
a_float = retVar.m_value.m_float;
return true;
}
return false;
}
bool ScriptSys::GetTableString(const char* a_memberName, String& a_string, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable stringName;
gmVariable retVar;
stringName.SetString(m_machine->AllocStringObject(a_memberName));
retVar = table->Get(stringName);
if(retVar.m_type == GM_STRING)
{
gmStringObject* stringObj = (gmStringObject*)GM_MOBJECT(m_machine, retVar.m_value.m_ref);
a_string = stringObj->GetString();
return true;
}
return false;
}
bool ScriptSys::GetTableGameObj(const char* a_memberName, GameObj*& a_gameObj, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable stringName;
gmVariable retVar;
stringName.SetString(m_machine->AllocStringObject(a_memberName));
retVar = table->Get(stringName);
if(retVar.m_type == ScriptObj::GMTYPE_GAMEOBJ)
{
gmUserObject* userObj = (gmUserObject*)GM_MOBJECT(m_machine, retVar.m_value.m_ref);
a_gameObj = ((ScriptObj*)userObj->m_user)->GetGameObj();
return true;
}
return false;
}
bool ScriptSys::GetTableTable(const char* a_memberName, gmTableObject*& a_retTable, gmTableObject* a_table)
{
GM_ASSERT(a_table);
gmTableObject* table = a_table;
gmVariable stringName;
gmVariable retVar;
stringName.SetString(m_machine->AllocStringObject(a_memberName));
retVar = table->Get(stringName);
if(retVar.m_type == GM_TABLE)
{
a_retTable = (gmTableObject*)GM_MOBJECT(m_machine, retVar.m_value.m_ref);
return true;
}
return false;
}
void GM_CDECL ScriptSys::ScriptSysCallback_Print(gmMachine* a_machine, const char* a_string)
{
printf("%s\n", a_string);
}
bool GM_CDECL ScriptSys::ScriptSysCallback_Machine(gmMachine* a_machine, gmMachineCommand a_command, const void* a_context)
{
switch(a_command)
{
case MC_THREAD_EXCEPTION:
{
ScriptSys::Get()->LogAnyMachineErrorMessages();
break;
}
case MC_COLLECT_GARBAGE:
{
/* // Old code
#if GM_USE_INCGC
gmGarbageCollector* gc = a_machine->GetGC();
for(unsigned int objIndex = 0; objIndex<ScriptSys::Get()->m_allScriptObjs.Count(); ++objIndex)
{
ScriptObj* scriptObj = ScriptSys::Get()->m_allScriptObjs[objIndex];
gc->GetNextObject(scriptObj->GetTableObject());
}
#else //GM_USE_INCGC
gmuint32 mark = *(gmuint32*)a_context;
for(unsigned int objIndex = 0; objIndex<ScriptSys::Get()->m_allScriptObjs.Count(); ++objIndex)
{
ScriptObj* scriptObj = ScriptSys::Get()->m_allScriptObjs[objIndex];
if(scriptObj->GetTableObject()->NeedsMark(mark))
{
scriptObj->GetTableObject()->Mark(a_machine, mark);
}
}
#endif //GM_USE_INCGC
*/
break;
}
case MC_THREAD_CREATE: // Called when a thread is created. a_context is the thread.
{
break;
}
case MC_THREAD_DESTROY: // Called when a thread is destroyed. a_context is the thread that is about to die
{
gmThread* thread = (gmThread*)a_context;
ScriptSys::Get()->DisassociateThreadIdWithGameObj(thread->GetId());
break;
}
}
return false;
}
bool ScriptSys::ExecuteFile(const char* a_fileName)
{
FILE* scriptFile = NULL;
char* fileString = NULL;
int fileSize = 0;
GM_ASSERT(m_machine);
if( !(scriptFile = fopen(a_fileName, "rb")) )
{
return false;
}
fseek(scriptFile, 0, SEEK_END);
fileSize = ftell(scriptFile);
fseek(scriptFile, 0, SEEK_SET);
fileString = new char [fileSize+1];
fread(fileString, fileSize, 1, scriptFile);
fileString[fileSize] = 0; // Terminating null
fclose(scriptFile);
int threadId = GM_INVALID_THREAD;
int errors = m_machine->ExecuteString(fileString, &threadId, true, a_fileName);
if(errors)
{
LogAnyMachineErrorMessages();
}
delete [] fileString;
return true;
}
bool ScriptSys::ExecuteString(const char* a_string)
{
GM_ASSERT(m_machine);
int threadId = GM_INVALID_THREAD;
int errors = m_machine->ExecuteString(a_string, &threadId, true);
if (errors)
{
LogAnyMachineErrorMessages();
}
return true;
}
int ScriptSys::Execute(unsigned int a_deltaTimeMS)
{
int numThreads = m_machine->Execute(a_deltaTimeMS);
if(m_debugClient.IsConnected())
{
m_debugSession.Update();
}
else
{
m_debugSession.Close();
}
return numThreads;
}
void ScriptSys::LogAnyMachineErrorMessages()
{
bool first = true;
const char * message;
while((message = m_machine->GetLog().GetEntry(first)))
{
LogError("%s"GM_NL, message);
}
m_machine->GetLog().Reset();
}
@@ -0,0 +1,107 @@
#ifndef SCRIPTSYS_H
#define SCRIPTSYS_H
//
// ScriptSys.h
//
// Example script system to support scriptable game objects
//
#include "gmThread.h"
#include "gmDebug.h"
#include "gmArraySimple.h"
#include "StdStuff.h"
#include "NetClient.h"
// Fwd decls
class GameObj;
class ScriptObj;
// Script system to support and control the virtual machine
class ScriptSys
{
public:
/// Access this system from anywhere once it has been initialized for convenience
static ScriptSys* Get() { return s_instance; }
ScriptSys();
virtual ~ScriptSys();
/// Get the GM machine
gmMachine* GetMachine() { return m_machine; }
/// Set bindings and Init constant strings
static void Init();
/// Clean out this structure
static void Destroy();
/// Log an error message
void __cdecl LogError(const char *a_str, ...);
/// Log any machine error messages that may be waiting
void LogAnyMachineErrorMessages();
/// Get GameObj that was associated with a thread Id.
GameObj* GetGameObjFromThreadId(int a_threadId);
/// Associate a threadId with a GameObj, logically as a primary thread.
void AssociateThreadIdWithGameObj(int a_threadId, GameObj& a_gameObj);
/// Disassociate a threadId with a GameObj.
void DisassociateThreadIdWithGameObj(int a_threadId);
/// Remove the thread Id association, but don't modify the GameObj.
/// This can be used internally by GameObj to perform iteration and removal.
void RemoveThreadIdButDontTouchGameObj(int a_threadId);
/// Run a script file
bool ExecuteFile(const char* a_fileName);
/// Executes a string.
bool ExecuteString(const char* a_str);
/// Update the virtual machine.
int Execute(unsigned int a_deltaTimeMS);
void SetTableNull(const char* a_memberName, gmTableObject* a_table);
void SetTableInt(const char* a_memberName, int a_int, gmTableObject* a_table);
void SetTableFloat(const char* a_memberName, float a_float, gmTableObject* a_table);
void SetTableString(const char* a_memberName, const char* a_string, int a_strLength, gmTableObject* a_table);
void SetTableGameObj(const char* a_memberName, GameObj* a_gameObj, gmTableObject* a_table);
gmTableObject* SetTableTable(const char* a_memberName, gmTableObject* a_table);
bool GetTableInt(const char* a_memberName, int& a_int, gmTableObject* a_table);
bool GetTableFloat(const char* a_memberName, float& a_float, gmTableObject* a_table);
bool GetTableString(const char* a_memberName, String& a_string, gmTableObject* a_table);
bool GetTableGameObj(const char* a_memberName, GameObj*& a_gameObj, gmTableObject* a_table);
bool GetTableTable(const char* a_memberName, gmTableObject*& a_retTable, gmTableObject* a_table);
protected:
/// Machine 'print' binding callback
static void GM_CDECL ScriptSysCallback_Print(gmMachine* a_machine, const char* a_string);
/// Machine general and exception callback
static bool GM_CDECL ScriptSysCallback_Machine(gmMachine* a_machine, gmMachineCommand a_command, const void* a_context);
/// Debugging support Send a message
static void DebuggerSendMessage(gmDebugSession * a_session, const void * a_command, int a_len);
/// Debugging support Pump a message
static const void* DebuggerPumpMessage(gmDebugSession * a_session, int &a_len);
gmMachine* m_machine; ///< GM machine instance
Map<int, ScriptObj*> m_mapThreadGameObjs; ///< Map script threadId to game object
/* // Old code
gmArraySimple<ScriptObj*> m_allScriptObjs; ///< All the script objects, for garbage collection handling
*/
nClient m_debugClient; ///< Debugger network client
gmDebugSession m_debugSession; ///< Debugger session
const char* m_debuggerIP; ///< Debugger IP
int m_debuggerPort; ///< Debugger port
static const int DEBUGGER_DEFAULT_PORT; ///< Debugger port number
static const char* DEBUGGER_DEFAULT_IP; ///< Debugger port number
static ScriptSys* s_instance; ///< Static instance for convenience
};
#endif //SCRIPTSYS_H
@@ -0,0 +1,5 @@
//
// StdStuff.cpp
//
#include "StdStuff.h"
@@ -0,0 +1,194 @@
#ifndef STDSTUFF_H
#define STDSTUFF_H
//
// StdStuff.h
//
// Merely some containers and standard things you would
// find in MFC, STL, or your favourite library/engine.
// These were implemented as quickly and minimally as possible
// rather than introduce more code or external libraries.
//
#include "gmHash.h"
// Quick n dirty Map using the available hash table
template<class KEY, class VALUE>
class Map
{
public:
Map()
: m_hashTable(1024) // Just an arbitrary number at present
{
}
virtual ~Map()
{
m_hashTable.RemoveAndDeleteAll();
}
/// \brief Insert a element associated with a key.
/// \param a_key Key to identify data.
/// \param a_value Data associated with Key.
void SetAt(const KEY& a_key, const VALUE& a_value)
{
HashNode* node = m_hashTable.Find(a_key);
if(node)
{
node->m_value = a_value;
}
else
{
node = new HashNode;
node->m_key = a_key;
node->m_value = a_value;
m_hashTable.Insert(node);
}
};
/// \brief Find a node in the map.
/// \param a_key Key to identiy element.
/// \param a_value Found element returned here.
/// \return TRUE if found, FALSE if not in map.
bool GetAt(const KEY& a_key, VALUE& a_value)
{
HashNode* node = m_hashTable.Find(a_key);
if(node)
{
a_value = node->m_value;
return true;
}
return false;
}
/// \brief Remove a node from the map.
/// \param a_key Key to identiy element.
/// \param a_removedData Found element returned here.
/// \return TRUE if found, FALSE if not in map.
bool RemoveAt(const KEY& a_key, VALUE& a_removedData)
{
HashNode* node = m_hashTable.Find(a_key);
if(node)
{
a_removedData = node->m_value;
m_hashTable.Remove(node);
delete node;
return true;
}
return false;
}
/// \brief Remove a node from the map.
/// \param a_key Key to identiy element.
/// \return TRUE if found, FALSE if not in map.
bool RemoveAt(const KEY& a_key)
{
HashNode* node = m_hashTable.Find(a_key);
if(node)
{
m_hashTable.Remove(node);
delete node;
return true;
}
return false;
}
protected:
struct HashNode : public gmHashNode<KEY, HashNode, HashNode>
{
VALUE m_value;
KEY m_key;
virtual const KEY& GetKey() const { return m_key; }
static inline gmuint Hash(const KEY& a_key)
{
return (unsigned int)a_key;
}
static inline int Compare(const KEY& a_keyA, const KEY& a_keyB)
{
if(a_keyA < a_keyB)
{ return -1; }
if(a_keyA > a_keyB)
{ return 1; }
return 0;
}
};
// Blocking
gmHash<KEY, HashNode, HashNode> m_hashTable;
};
// The most crap string implementation ever
class String
{
public:
String()
{
m_buffer = NULL;
SetBuffer("");
}
String(const char* a_newString)
{
m_buffer = NULL;
SetBuffer(a_newString);
}
String(const char* a_newString, const int a_newStringLength)
{
m_buffer = NULL;
SetBuffer(a_newString, a_newStringLength);
}
~String()
{
delete [] m_buffer;
}
operator const char* () const
{
return m_buffer;
}
const char* operator = (const char* a_newString)
{
SetBuffer(a_newString);
return m_buffer;
}
const char* operator = (const String& a_newString)
{
SetBuffer(a_newString);
return m_buffer;
}
private:
void SetBuffer(const char* a_newString, const int a_newStringLength)
{
delete [] m_buffer;
m_buffer = new char [a_newStringLength + 1];
memcpy(m_buffer, a_newString, a_newStringLength);
m_buffer[a_newStringLength] = 0;
}
void SetBuffer(const char* a_newString)
{
int newStringLength = strlen(a_newString);
SetBuffer(a_newString, newStringLength);
}
char * m_buffer;
};
#endif //STDSTUFF_H
@@ -0,0 +1,44 @@
// Just a bunch of tests that don't mean anything at present.
global WhatsMyName = function()
{
print("m_name = ", .m_name);
print("this = ", this);
if(.IsValid())
{
.SetPos(23.0f, 56.0f);
print("position(", .GetPosX(), ",", .GetPosY(), ")");
global g_globalObj = this;
}
};
global RunGlobalObject = function ()
{
g_globalObj:WhatsMyName();
};
global ThreadYieldTest = function()
{
count = 0;
while(count < 30)
{
sleep(0.5f);
count += 1;
print("count=",count);
yield();
}
};
Console.SetColor(COLOR_RED, COLOR_BLACK);
Console.Print("Red");
Console.SetColor(COLOR_GREEN, COLOR_BLACK);
Console.Print("Green");
Console.Print("\n");
Console.SetColor(COLOR_WHITE, COLOR_BLACK);
print("Script compiled and executed. \n");
@@ -0,0 +1,30 @@
#include <windows.h>
#include "StdStuff.h"
#include "App.h"
// Entry point for Win32 app
int main(int argc, char* argv[])
{
String test1("hello");
test1 = "world";
const char* huh = test1;
App app;
if(!app.Init())
{
fprintf(stderr,"Failed App::Init()");
return 1;
}
while(app.Update())
{
}
app.Destroy();
printf("App finished, press ENTER to exit.");
getchar(); // Wait for key press
return 0;
}
@@ -0,0 +1,362 @@
# Microsoft Developer Studio Project File - Name="Minimal" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=Minimal - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "Minimal.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "Minimal.mak" CFG="Minimal - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Minimal - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Minimal - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "Perforce Project"
# PROP Scc_LocalPath "..\.."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Minimal - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "..\..\gm" /I "..\..\platform\win32msvc" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0xc09 /d "NDEBUG"
# ADD RSC /l 0xc09 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "Minimal - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\gm" /I "..\..\platform\win32msvc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0xc09 /d "_DEBUG"
# ADD RSC /l 0xc09 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "Minimal - Win32 Release"
# Name "Minimal - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\main.cpp
# End Source File
# End Group
# Begin Group "gm"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\gm\gmArraySimple.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmArraySimple.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmByteCode.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmByteCode.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmByteCodeGen.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmByteCodeGen.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeGen.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeGen.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeGenHooks.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeGenHooks.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeTree.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCodeTree.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmConfig.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCrc.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmCrc.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmDebug.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmDebug.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmFunctionObject.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmFunctionObject.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmHash.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmHash.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmIncGC.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmIncGC.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmIterator.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmLibHooks.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmLibHooks.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmListDouble.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmListDouble.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmLog.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmLog.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMachine.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMachine.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMachineLib.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMachineLib.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMem.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMem.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemChain.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemChain.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemFixed.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemFixed.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemFixedSet.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmMemFixedSet.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmOperators.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmOperators.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmParser.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmParser.cpp.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmScanner.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmScanner.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStream.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStream.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStreamBuffer.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStreamBuffer.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStringObject.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmStringObject.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmTableObject.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmTableObject.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmThread.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmThread.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmUserObject.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmUserObject.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmUtil.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmUtil.h
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmVariable.cpp
# End Source File
# Begin Source File
SOURCE=..\..\gm\gmVariable.h
# End Source File
# End Group
# Begin Group "win32"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\platform\win32msvc\gmConfig_p.h
# End Source File
# End Group
# End Target
# End Project
@@ -0,0 +1,33 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "Minimal"=.\Minimal.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
Perforce Project
..\..
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,78 @@
#if 0 // This is trully the smallest app
#include "gmThread.h" // game monkey script
int main(int argc, char* argv[])
{
gmMachine machine;
machine.ExecuteString("print(`Hello world`);");
getchar(); // Keypress before exit
return 0;
}
#else // This is a tiny app
#include <windows.h>
#include <mmsystem.h> // multimedia timer (may need winmm.lib)
#include "gmThread.h" // game monkey script
int main(int argc, char* argv[])
{
// Create virtual machine
gmMachine* machine = new gmMachine;
// Get a script from stdin. Some examples:
// print("Hello world");
// for( i = 0; i < 10; i=i+1 ) { print("i=",i); sleep(1.0); }
fprintf(stdout,"Please enter one line of script\n>");
const int MAX_SCRIPT_SIZE = 4096;
char script[MAX_SCRIPT_SIZE];
fgets(script, MAX_SCRIPT_SIZE-1, stdin);
// Compile the script, but don't run it for now
int errors = machine->ExecuteString(script, NULL, false, NULL);
// Dump compile time errors to output
if(errors)
{
bool first = true;
const char * message;
while((message = machine->GetLog().GetEntry(first)))
{
fprintf(stderr, "%s"GM_NL, message);
}
machine->GetLog().Reset();
}
else
{
int deltaTime = 0;
int lastTime = timeGetTime();
// Keep executing script while threads persist
while(machine->Execute(deltaTime))
{
// Update delta time
int curTime = timeGetTime();
deltaTime = curTime - lastTime;
lastTime = curTime;
// Dump run time errors to output
bool first = true;
const char * message;
while((message = machine->GetLog().GetEntry(first)))
{
fprintf(stderr, "%s"GM_NL, message);
}
machine->GetLog().Reset();
}
}
delete machine; // Finished with VM
fprintf(stdout,"Script complete. Press a key to exit.");
getchar(); // Keypress before exit
return 0;
}
#endif // Minimal build type