Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

655 lines
13 KiB

//=== ======= Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose: Script initially run after squirrel VM is initialized
//
//=============================================================================
//-----------------------------------------------------------------------------
// General
//-----------------------------------------------------------------------------
function printl( text )
{
return print( text + "\n" );
}
function Msg( text )
{
return print( text );
}
function Assert( b, msg = null )
{
if ( b )
return;
if ( msg != null )
{
throw "Assertion failed: " + msg;
}
else
{
throw "Assertion failed";
}
}
//-----------------------------------------------------------------------------
// Documentation table
//-----------------------------------------------------------------------------
if ( developer() > 0 )
{
Documentation <-
{
classes = {}
functions = {}
instances = {}
}
function RetrieveNativeSignature( nativeFunction )
{
if ( nativeFunction in NativeFunctionSignatures )
{
return NativeFunctionSignatures[nativeFunction]
}
return "<unnamed>"
}
function RegisterFunctionDocumentation( func, name, signature, description )
{
if ( description.len() )
{
local b = ( description[0] == '#' );
if ( description[0] == '#' )
{
local colon = description.find( ":" );
if ( colon == null )
{
colon = description.len();
}
local alias = description.slice( 1, colon );
description = description.slice( colon + 1 );
name = alias;
signature = "#";
}
}
Documentation.functions[name] <- [ signature, description ]
}
function Document( symbolOrTable, itemIfSymbol = null, descriptionIfSymbol = null )
{
if ( typeof( symbolOrTable ) == "table" )
{
foreach( symbol, itemDescription in symbolOrTable )
{
Assert( typeof(symbol) == "string" )
Document( symbol, itemDescription[0], itemDescription[1] );
}
}
else
{
printl( symbolOrTable + ":" + itemIfSymbol.tostring() + "/" + descriptionIfSymbol );
}
}
function PrintHelp( string = "*", exact = false )
{
local matches = []
if ( string == "*" || !exact )
{
foreach( name, documentation in Documentation.functions )
{
if ( string != "*" && name.tolower().find( string.tolower() ) == null )
{
continue;
}
matches.append( name );
}
}
else if ( exact )
{
if ( string in Documentation.functions )
matches.append( string )
}
if ( matches.len() == 0 )
{
printl( "Symbol " + string + " not found" );
return;
}
matches.sort();
foreach( name in matches )
{
local result = name;
local documentation = Documentation.functions[name];
printl( "Function: " + name );
local signature;
if ( documentation[0] != "#" )
{
signature = documentation[0];
}
else
{
signature = GetFunctionSignature( this[name], name );
}
printl( "Signature: " + signature );
if ( documentation[1].len() )
printl( "Description: " + documentation[1] );
print( "\n" );
}
}
}
else
{
function RetrieveNativeSignature( nativeFunction ) { return "<unnamed>"; }
function Document( symbolOrTable, itemIfSymbol = null, descriptionIfSymbol = null ) {}
function PrintHelp( string = "*", exact = false ) {}
}
//-----------------------------------------------------------------------------
// VSquirrel support functions
//-----------------------------------------------------------------------------
function VSquirrel_OnCreateScope( name, outer )
{
local result;
if ( !(name in outer) )
{
result = outer[name] <- { __vname=name, __vrefs = 1 };
delegate outer : result;
}
else
{
result = outer[name];
result.__vrefs += 1;
}
return result;
}
function VSquirrel_OnReleaseScope( scope )
{
scope.__vrefs -= 1;
if ( scope.__vrefs < 0 )
{
throw "Bad reference counting on scope " + scope.__vname;
}
else if ( scope.__vrefs == 0 )
{
delete scope.parent[scope.__vname];
scope.__vname = null;
delegate null : scope;
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CCallChainer
{
constructor( prefixString, scopeForThis = null )
{
prefix = prefixString;
if ( scopeForThis != null )
scope = scopeForThis;
else
scope = ::getroottable();
chains = {};
// Expose a bound global function to dispatch to this object
scope[ "Dispatch" + prefixString ] <- Call.bindenv( this );
}
function PostScriptExecute()
{
foreach( key, value in scope )
{
if ( typeof( value ) == "function" )
{
if ( key.find( prefix ) == 0 )
{
key = key.slice( prefix.len() );
if ( !(key in chains) )
{
//::print( "Creating new call chain " + key + "\n");
chains[key] <- [];
}
local chain = chains[key];
if ( !chain.len() || chain.top() != value )
{
chain.push( value );
//::print( "Added " + value + " to call chain " + key + "\n" );
}
}
}
}
}
function Call( event, ... )
{
if ( event in chains )
{
local chain = chains[event];
if ( chain.len() )
{
local i;
local args = [];
if ( vargc > 0 )
{
args.push( scope );
for ( i = 0; i < vargc; i++ )
{
args.push( vargv[i] );
}
}
for ( i = chain.len() - 1; i >= 0; i -= 1 )
{
local func = chain[i];
local result;
if ( !args.len() )
{
result = func();
}
else
{
result = func.acall( args );
}
if ( result != null && !result )
return false;
}
}
}
return true;
}
scope = null;
prefix = null;
chains = null;
};
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CSimpleCallChainer
{
constructor( prefixString, scopeForThis = null, exactNameMatch = false )
{
prefix = prefixString;
if ( scopeForThis != null )
scope = scopeForThis;
else
scope = ::getroottable();
chain = [];
// Expose a bound global function to dispatch to this object
scope[ "Dispatch" + prefixString ] <- Call.bindenv( this );
exactMatch = exactNameMatch
}
function PostScriptExecute()
{
foreach( key, value in scope )
{
if ( typeof( value ) == "function" )
{
local foundMatch = false;
if ( exactMatch )
{
foundMatch = ( prefix == key );
}
else
{
foundMatch = ( key.find( prefix ) == 0 )
}
if ( foundMatch )
{
if ( !exactMatch )
key = key.slice( prefix.len() );
if ( !(chain) )
{
//::print( "Creating new call simple chain\n");
chain <- [];
}
if ( !chain.len() || chain != value )
{
chain.push( value );
//::print( "Added " + value + " to call chain.\n" );
}
}
}
}
}
function Call( ... )
{
if ( chain.len() )
{
local i;
local args = [];
if ( vargc > 0 )
{
args.push( scope );
for ( i = 0; i < vargc; i++ )
{
args.push( vargv[i] );
}
}
for ( i = chain.len() - 1; i >= 0; i -= 1 )
{
local func = chain[i];
local result;
if ( !args.len() )
{
result = func.pcall( scope );
}
else
{
result = func.pacall( scope, args );
}
if ( result != null && !result )
return false;
}
}
return true;
}
exactMatch = false
scope = null;
prefix = null;
chain = null;
};
//-----------------------------------------------------------------------------
// Late binding: allows a table to refer to parts of itself, it's children,
// it's owner, and then have the references fixed up after it's fully parsed
//
// Usage:
// lateBinder <- LateBinder();
// lateBinder.Begin( this );
//
// Test1 <-
// {
// Foo=1
// }
//
// Test2 <-
// {
// FooFoo = "I'm foo foo"
// BarBar="@Test1.Foo"
// SubTable = { boo=[bah, "@Test2.FooFoo", "@Test1.Foo"], booboo2={one=bah, two="@Test2.FooFoo", three="@Test1.Foo"} }
// booboo=[bah, "@Test2.FooFoo", "@Test1.Foo"]
// booboo2={one=bah, two="@Test2.FooFoo", three="@Test1.Foo"}
// bah=wha
// }
//
// lateBinder.End();
// delete lateBinder;
//
// When End() is called, all of the unresolved symbols in the tables and arrays will be resolved,
// any left unresolved will become a string prepended with '~', which later code can deal with
//-----------------------------------------------------------------------------
class LateBinder
{
// public:
function Begin( target, log = false )
{
m_log = log;
HookRootMetamethod( "_get", function( key ) { return "^" + key; } );
HookRootMetamethod( "_newslot", function( key, value ) { if ( typeof value == "table" ) { m_fixupSet.push( [ key, value ] ); this.rawset( key, value ); }; }.bindenv(this) );
m_targetTable = target;
Log( "Begin late bind on table " + m_targetTable );
}
function End()
{
UnhookRootMetamethod( "_get" );
UnhookRootMetamethod( "_newslot" );
Log( "End late bind on table " + m_targetTable );
foreach( subTablePair in m_fixupSet )
{
EstablishDelegation( m_targetTable, subTablePair[1] );
}
Log( "Begin resolution... " )
m_logIndent++;
local found = true;
while ( found )
{
foreach( subTablePair in m_fixupSet )
{
Log( subTablePair[0] + " = " );
Log( "{" );
if ( !Resolve( subTablePair[1], subTablePair[1], false ) )
{
found = false;
}
Log( "}" );
}
}
m_logIndent--;
foreach( subTablePair in m_fixupSet )
{
RemoveDelegation( subTablePair[1] );
}
Log( "...end resolution" );
}
// private:
function HookRootMetamethod( name, value )
{
local saved = null;
local roottable = getroottable();
if ( name in roottable )
{
saved = roottable[name];
}
roottable[name] <- value;
roottable["__saved" + name] <- saved;
}
function UnhookRootMetamethod( name )
{
local saveSlot = "__saved" + name;
local roottable = getroottable();
local saved = roottable[saveSlot];
if ( saved != null )
{
roottable[name] = saved;
}
else
{
delete roottable[name];
}
delete roottable[saveSlot];
}
function EstablishDelegation( parentTable, childTable )
{
delegate parentTable : childTable;
foreach( key, value in childTable )
{
local type = typeof value;
if ( type == "table" )
{
EstablishDelegation( childTable, value );
}
}
}
function RemoveDelegation( childTable )
{
delegate null : childTable;
foreach( key, value in childTable )
{
local type = typeof value;
if ( type == "table" )
{
RemoveDelegation( value );
}
}
}
function Resolve( lookupTable, subTableOrArray, throwException = false )
{
m_logIndent++;
local found = false;
foreach( key, value in subTableOrArray )
{
local type = typeof value;
if ( type == "string" )
{
if ( value.len() )
{
local unresolvedId = null;
local controlChar = value[0]
if ( controlChar == '^' )
{
found = true;
value = value.slice( 1 );
if ( value in lookupTable )
{
subTableOrArray[key] = lookupTable[value];
Log( key + " = " + lookupTable[value] + " <-- " + value );
}
else
{
subTableOrArray[key] = "~" + value;
unresolvedId = value;
Log( key + " = \"" + "~" + value + "\" (unresolved)" );
}
}
else if ( controlChar == '@' )
{
found = true;
local identifiers = [];
local iLast = 1;
local iNext;
while ( ( iNext = value.find( ".", iLast ) ) != null )
{
identifiers.push( value.slice( iLast, iNext ) );
iLast = iNext + 1;
}
identifiers.push( value.slice( iLast ) );
local depthSuccess = 0;
local result = lookupTable;
foreach( identifier in identifiers )
{
if ( identifier in result )
{
depthSuccess++;
result = result[identifier];
}
else
{
break;
}
}
if ( depthSuccess == identifiers.len() )
{
subTableOrArray[key] = result;
Log( key + " = " + result + " <-- " + value );
}
else
{
subTableOrArray[key] = "~" + value.slice( 1 );
unresolvedId = value;
Log( key + " = \"" + "~" + value + "\" (unresolved)" );
}
}
if ( unresolvedId != null )
{
if ( throwException )
{
local exception = "Unresolved symbol: " + bind + " in ";
foreach ( entry in m_bindNamesStack )
{
exception += entry;
exception += "."
}
exception += unresolvedId;
throw exception;
}
}
}
}
}
foreach( key, value in subTableOrArray )
{
local type = typeof value;
local isTable = ( type == "table" );
local isArray = ( type == "array" )
if ( isTable || isArray )
{
Log( key + " =" );
Log( isTable ? "{" : "[" );
m_bindNamesStack.push( key );
if ( Resolve( ( isTable ) ? value : lookupTable, value, throwException ) )
{
found = true;
}
m_bindNamesStack.pop();
Log( isTable ? "}" : "]" );
}
}
m_logIndent--;
return found;
}
function Log( string )
{
if ( m_log )
{
for ( local i = 0; i < m_logIndent; i++ )
{
print( " " );
}
printl( string );
}
}
m_targetTable = null;
m_fixupSet = [];
m_bindNamesStack = [];
m_log = false;
m_logIndent = 0;
}