Merge Mapbase v8.0 into the MP branch

This commit is contained in:
Blixibon 2025-07-29 13:01:57 -05:00
commit 0d7c5b4fd3
66 changed files with 6822 additions and 2749 deletions

View File

@ -52,6 +52,7 @@ Mapbase uses content from the following non-Source SDK 2013 Valve games or SDKs:
-- Alien Swarm (Used to port assets from the aforementioned SDK code features, e.g. game instructor icons)
-- Left 4 Dead (Used to port certain animations as well as assets from the aforementioned SDK code features, e.g. particle rain)
-- Half-Life: Source (Used to port friction tool textures)
-- Half-Life 2: Survivor (Used to port Gordon Freeman model)
Valve allows assets from these titles to be distributed for modding purposes. Note that ported assets are only used in the release build, not the code repository.
@ -118,6 +119,7 @@ Direct contributions:
- https://github.com/mapbase-source/source-sdk-2013/pull/245 (ViewPunch random fix by Mr0maks)
- https://github.com/mapbase-source/source-sdk-2013/pull/248 (soundlevel_t conversation warning fix by Mechami)
- https://github.com/mapbase-source/source-sdk-2013/pull/266 ("OnPhysGunPull" output in CPhysicsProp by rlenhub)
- https://github.com/mapbase-source/source-sdk-2013/pull/281 (npc_combinedropship DropStrider input by Bronzehawk75)
- https://github.com/mapbase-source/source-sdk-2013/pull/292 (env_headcrabcanister random spawn type by arbabf)
- https://github.com/mapbase-source/source-sdk-2013/pull/293 (Restore text selection code by SanyaSho)
- https://github.com/mapbase-source/source-sdk-2013/pull/294 (SDK_LightmappedGeneric editor blend swap fix by azzyr)
@ -133,17 +135,27 @@ Direct contributions:
- https://github.com/mapbase-source/source-sdk-2013/pull/391 (VRAD -extrapasses command by Unusuario2)
- https://github.com/mapbase-source/source-sdk-2013/pull/393 (Additional VBSP options doc by Unusuario2)
- https://github.com/mapbase-source/source-sdk-2013/pull/397 (Viewmodel camera bone by Nbc66)
- https://github.com/mapbase-source/source-sdk-2013/pull/412 (Compile tool negative threads support by Unusuario2)
- https://github.com/mapbase-source/source-sdk-2013/pull/414 (VRAD %alphatexture by SirYodaJedi)
- https://github.com/mapbase-source/source-sdk-2013/pull/415 (Parallax corrected cubemaps optimization and fix by Zeldaboy14 and White_Red_Dragons)
- https://github.com/mapbase-source/source-sdk-2013/pull/418 (Server ragdoll death poses by AnOldLady)
- https://github.com/mapbase-source/source-sdk-2013/pull/419 (npc_helicopter removal crash fix by Wikot235)
- https://github.com/mapbase-source/source-sdk-2013/pull/420 (sk_combine_head_dmg_multiplier cvar by Wikot235)
- https://github.com/mapbase-source/source-sdk-2013/pull/422 (Expanded HL2 NPC custom model support by Maestra Fenix [committed by Blixibon])
- https://github.com/mapbase-source/mapbase-game-src/pull/1 (Advanced video options duplicate field name fix by arbabf; This is asset-based and not reflected in the code)
- https://github.com/mapbase-source/mapbase-game-src/pull/2 (gameinfo.txt typo fix by CarePackage17; This is asset-based and not reflected in the code)
- https://github.com/mapbase-source/mapbase-game-src/pull/3 (HudMessage cutoff fix by arbabf; This is asset-based and not reflected in the code)
- Demo autorecord code provided by Klems
- cc_emit crash fix provided by 1upD
- npc_barnacle poison zombie crash fix provided by Agrimar
- Custom HL2 ammo crate models created by Rykah (Textures created by Blixibon; This is asset-based and, aside from the SLAM crate, not reflected in the code)
- Combine lock hardware on door01_left.mdl created by Kralich (This is asset-based and not reflected in the code)
- npc_vehicledriver fixes provided by CrAzY
- npc_combine cover behavior patches provided by iohnnyboy
- logic_playmovie icon created by URAKOLOUY5 (This is asset-based and not reflected in the code)
- Dropship APC save/load fix provided by Cvoxulary
- c_arms support on HL2 viewmodels by Inaki and ReverendV92 (This is asset-based and not reflected in the code)
- Custom c_arms for HL2 characters by Notewell (This is asset-based and not reflected in the code)
== Contributions from samisalreadytaken:
=-- https://github.com/mapbase-source/source-sdk-2013/pull/47 (VScript utility/consistency changes)
@ -166,8 +178,14 @@ Direct contributions:
=-- https://github.com/mapbase-source/source-sdk-2013/pull/260 (CScriptNetPropManager rewrite)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/261 (Misc VScript additions)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/279 (weapon_custom_scripted fixes)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/302 (VScript debugger)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/331 (VScript leak fixes)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/332 (Fix OOB access)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/411 (VScript debugger cleanup)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/423 (GetPropFloatArray Vector indexing fix)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/431 (VScript save/restore and debugger fixes)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/441 (VScript instance helper fallback)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/447 (Update VScript sqdbg)
== Contributions from z33ky:
=-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes)
@ -184,6 +202,7 @@ Direct contributions:
=-- https://github.com/mapbase-source/source-sdk-2013/pull/320 (Fix ScriptHook_t initialization order)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/321 (Prevent return of dangling Vector/QAngle to VScript)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/322 (Small Mapbase fixes)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/436 (VScript member function call safety)
== Contributions from Petercov:
=-- https://github.com/mapbase-source/source-sdk-2013/pull/182 (NPCs load dynamic interactions from all animation MDLs)
@ -194,6 +213,7 @@ Direct contributions:
=-- https://github.com/mapbase-source/source-sdk-2013/pull/230 (Caption fixes)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/231 (Sentence source bug fix)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/264 (Outputs for vgui_screen)
=-- https://github.com/mapbase-source/source-sdk-2013/pull/427 (CBaseCombatWeapon::WeaponClassFromString typo fix [committed by vizzys])
//-------------------------------------------------------------------------------------------------------------------------

View File

@ -49,6 +49,8 @@ $Project
$File "$SRCDIR\game\shared\mapbase\MapEdit.h"
$File "$SRCDIR\game\shared\mapbase\matchers.cpp"
$File "$SRCDIR\game\shared\mapbase\matchers.h"
$File "$SRCDIR\game\shared\mapbase\game_timer.cpp"
$File "$SRCDIR\game\shared\mapbase\game_timer.h"
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.h" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\vscript_singletons.cpp" [$MAPBASE_VSCRIPT]

View File

@ -16,6 +16,7 @@ $Project
$File "$SRCDIR\game\shared\mapbase\protagonist_system.h"
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_hl2.cpp" [$MAPBASE_VSCRIPT]
$File "mapbase\c_weapon_custom_hl2.cpp"
$File "mapbase\hud_generic_timer.cpp"
}
$Folder "HL2 DLL"

View File

@ -0,0 +1,511 @@
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
//
// Purpose: Generic timer HUD element for HL2-based mods
//
// Author: Blixibon
//
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "hud_macros.h"
#include "hudelement.h"
#include "hud_numericdisplay.h"
#include "iclientmode.h"
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <vgui_controls/AnimationController.h>
#include <vgui_controls/EditablePanel.h>
#include "baseviewport.h"
#include "mapbase/game_timer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool g_bAnyGameTimerActive;
ConVar hud_timer_max_bars( "hud_timer_max_bars", "15" );
//-----------------------------------------------------------------------------
// Purpose: Timer panel
//-----------------------------------------------------------------------------
class CHudGenericGameTimer : public CHudElement, public vgui::Panel
{
DECLARE_CLASS_SIMPLE( CHudGenericGameTimer, vgui::Panel );
public:
CHudGenericGameTimer( const char *pElementName );
virtual void Init( void );
virtual void VidInit( void );
virtual void Reset( void );
virtual void OnThink();
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
virtual bool ShouldDraw( void );
virtual void Paint();
C_GameTimer *GetTimer();
bool FindTimer();
void SetDisplayValue( int value ) { m_iValue = value; }
void SetLabelText( const wchar_t *text );
virtual void PaintNumbers( vgui::HFont font, int xpos, int ypos );
virtual void PaintBars( int xpos, int ypos, int wide );
int GetTimerIndex() const { return m_iTimerIndex; }
private:
void SetTimerLabel( void );
private:
int m_iTimerIndex;
bool m_bTimerDisplayed;
bool m_bPlayingFadeout;
float m_flShutoffTime;
bool m_bTimerPaused;
bool m_bTimerWarned;
int m_iValue;
int m_iTimerMaxLength;
bool m_bShowTimeRemaining;
int m_nProgressBarMax;
int m_nProgressBarOverride;
float m_flOverrideX, m_flOverrideY;
wchar_t m_LabelText[32];
int m_nLabelWidth, m_nLabelHeight;
int m_nTimerWidth, m_nTimerHeight;
CPanelAnimationVarAliasType( float, m_flMinWidth, "MinWidth", "100", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flBorder, "Border", "24", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flLabelTimerSpacing, "LabelTimerSpacing", "2", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flBarHeight, "BarHeight", "5", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flBarChunkGap, "BarChunkGap", "3", "proportional_float" );
CPanelAnimationVarAliasType( float, m_flBarVerticalGap, "BarVerticalGap", "8", "proportional_float" );
CPanelAnimationVar( int, m_iBarDisabledAlpha, "BarDisabledAlpha", "70" );
CPanelAnimationVar( float, m_flBlur, "Blur", "0" );
CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudHintTextLarge" );
CPanelAnimationVar( vgui::HFont, m_hNumberGlowFont, "NumberGlowFont", "HudHintTextLarge" );
CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudHintTextSmall" );
};
DECLARE_HUDELEMENT( CHudGenericGameTimer );
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CHudGenericGameTimer::CHudGenericGameTimer( const char *pElementName )
: CHudElement( pElementName ),
BaseClass( NULL, "HudGenericGameTimer" )
{
Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
SetHiddenBits( HIDEHUD_MISCSTATUS );
m_iTimerIndex = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::Init()
{
Reset();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::Reset()
{
SetDisplayValue( 0 );
SetAlpha( 0 );
m_flShutoffTime = 0.0f;
m_bTimerDisplayed = false;
m_iTimerIndex = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::VidInit()
{
Reset();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::OnThink()
{
C_BasePlayer *local = C_BasePlayer::GetLocalPlayer();
if ( !local )
{
// Not ready to init!
return;
}
// If our timer has been disabled, close the menu
C_GameTimer *pTimer = GetTimer();
if ( !pTimer || pTimer->IsDisabled() || pTimer->IsMarkedForDeletion() )
{
if ( m_flShutoffTime == 0.0f )
{
m_flShutoffTime = gpGlobals->curtime + 1.0f;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "GenericGameTimerClose" );
}
m_iTimerIndex = 0;
return;
}
// Check pause state
if ( m_bTimerPaused && !pTimer->IsTimerPaused() )
{
m_bTimerPaused = false;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "GenericGameTimerPulse" );
}
else if ( pTimer->IsTimerPaused() )
{
m_bTimerPaused = true;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "GenericGameTimerPulseOnce" );
}
float flTimeRemaining = floorf( pTimer->GetTimeRemaining() );
// Check warn state
float flWarnTime = pTimer->GetWarnTime();
if (flWarnTime > 0.0f)
{
if ( m_bTimerWarned && flTimeRemaining > flWarnTime )
{
// Turn back to normal
m_bTimerWarned = false;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "GenericGameTimerUnwarn" );
}
else if ( flTimeRemaining <= flWarnTime )
{
// Turn red
m_bTimerWarned = true;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "GenericGameTimerWarn" );
}
}
SetDisplayValue( flTimeRemaining );
m_iTimerMaxLength = pTimer->GetTimerMaxLength();
m_bShowTimeRemaining = pTimer->ShowTimeRemaining();
m_nProgressBarMax = pTimer->GetProgressBarMaxSegments();
if (m_nProgressBarMax == -1)
{
// Default to timer max length
m_nProgressBarMax = min( m_iTimerMaxLength, hud_timer_max_bars.GetInt() );
}
m_nProgressBarOverride = pTimer->GetProgressBarOverride();
pTimer->GetPositionOverride( m_flOverrideX, m_flOverrideY );
}
//-----------------------------------------------------------------------------
// Purpose: hud scheme settings
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetPaintBackgroundEnabled( false );
// set our size
int screenWide, screenTall;
int x, y;
GetPos( x, y );
GetHudSize( screenWide, screenTall );
SetBounds( 0, y, screenWide, screenTall - y );
// Start with a 0:00 timer
m_nTimerWidth = (vgui::surface()->GetCharacterWidth( m_hNumberFont, '0' ) * 3);
m_nTimerWidth += vgui::surface()->GetCharacterWidth( m_hNumberFont, ':' );
m_nTimerHeight = vgui::surface()->GetFontTall( m_hNumberFont );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHudGenericGameTimer::ShouldDraw( void )
{
if ( !CHudElement::ShouldDraw() )
return false;
if ( !m_bTimerDisplayed )
{
// Check if we should find a new timer
if ( g_bAnyGameTimerActive )
{
if ( FindTimer() )
return true;
}
return false;
}
// check for if menu is set to disappear
if ( m_flShutoffTime > 0 && m_flShutoffTime <= gpGlobals->curtime )
{
// times up, shutoff
m_bTimerDisplayed = false;
return false;
}
if ( m_flOverrideX == -1.0f && m_flOverrideY == -1.0f )
{
// Don't overlap with the weapon selection HUD
vgui::Panel *pWeaponSelection = GetParent()->FindChildByName( "HudWeaponSelection" );
if ( pWeaponSelection && pWeaponSelection->IsVisible() )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline C_GameTimer *CHudGenericGameTimer::GetTimer()
{
if (m_iTimerIndex <= 0)
return NULL;
// Need to do a dynamic_cast because this entity index could've been replaced since it was last used
return dynamic_cast<C_GameTimer*>(C_BaseEntity::Instance( m_iTimerIndex ));
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHudGenericGameTimer::FindTimer()
{
// Find a new timer
for ( int i = 0; i < IGameTimerAutoList::AutoList().Count(); i++ )
{
C_GameTimer *pTimer = static_cast<C_GameTimer *>( IGameTimerAutoList::AutoList()[i] );
if ( !pTimer->IsDisabled() && !pTimer->IsMarkedForDeletion() )
{
m_iTimerIndex = pTimer->entindex();
break;
}
}
C_GameTimer *pTimer = GetTimer();
if ( pTimer )
{
// New timer selected, set the caption
wchar_t wszLabelText[128];
const wchar_t *wLocalizedItem = g_pVGuiLocalize->Find( pTimer->GetTimerCaption() );
if (wLocalizedItem)
{
V_wcsncpy( wszLabelText, wLocalizedItem, sizeof( wszLabelText ) );
}
else
{
g_pVGuiLocalize->ConvertANSIToUnicode( pTimer->GetTimerCaption(), wszLabelText, sizeof( wszLabelText ) );
}
SetLabelText( wszLabelText );
m_flShutoffTime = 0;
m_bTimerDisplayed = true;
m_bTimerPaused = pTimer->IsTimerPaused();
m_bTimerWarned = false;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_bTimerPaused ? "GenericGameTimerShow" : "GenericGameTimerShowFlash" );
SetDisplayValue( ceil( pTimer->GetTimeRemaining() ) );
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::SetLabelText( const wchar_t *text )
{
wcsncpy( m_LabelText, text, sizeof( m_LabelText ) / sizeof( wchar_t ) );
m_LabelText[(sizeof( m_LabelText ) / sizeof( wchar_t )) - 1] = 0;
m_nLabelWidth = 0;
m_nLabelHeight = 0;
if (m_LabelText[0] != '\0')
{
int nLabelLen = V_wcslen( m_LabelText );
for (int ch = 0; ch < nLabelLen; ch++)
{
m_nLabelWidth += vgui::surface()->GetCharacterWidth( m_hTextFont, m_LabelText[ch] );
}
m_nLabelHeight = vgui::surface()->GetFontTall( m_hTextFont );
m_nLabelHeight += m_flLabelTimerSpacing;
}
}
//-----------------------------------------------------------------------------
// Purpose: paints a number at the specified position
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::PaintNumbers( vgui::HFont font, int xpos, int ypos )
{
vgui::surface()->DrawSetTextFont(font);
int nTimeToDisplay = m_iValue;
if ( !m_bShowTimeRemaining )
{
nTimeToDisplay = m_iTimerMaxLength - nTimeToDisplay;
}
int nMinutes = 0;
int nSeconds = 0;
wchar_t unicode[6];
if (nTimeToDisplay <= 0)
{
nMinutes = 0;
nSeconds = 0;
}
else
{
nMinutes = nTimeToDisplay / 60;
nSeconds = nTimeToDisplay % 60;
}
V_snwprintf( unicode, ARRAYSIZE(unicode), L"%d:%02d", nMinutes, nSeconds );
vgui::surface()->DrawSetTextPos( xpos, ypos );
vgui::surface()->DrawUnicodeString( unicode );
// draw the overbright blur
for (float fl = m_flBlur; fl > 0.0f; fl -= 1.0f)
{
if (fl >= 1.0f)
{
vgui::surface()->DrawSetTextPos( xpos, ypos );
vgui::surface()->DrawUnicodeString( unicode );
}
else
{
// draw a percentage of the last one
Color col = GetFgColor();
col[3] *= fl;
vgui::surface()->DrawSetTextColor( col );
vgui::surface()->DrawSetTextPos( xpos, ypos );
vgui::surface()->DrawUnicodeString( unicode );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: paints bars at the specified position
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::PaintBars( int xpos, int ypos, int wide )
{
// get bar chunks
int barChunkWidth = (wide / m_nProgressBarMax) - m_flBarChunkGap;
int enabledChunks;
if (m_nProgressBarOverride > -1)
enabledChunks = m_nProgressBarOverride;
else
{
enabledChunks = (int)floorf( ((float)m_iValue / (float)m_iTimerMaxLength) * (float)m_nProgressBarMax );
if (!m_bShowTimeRemaining)
{
enabledChunks = m_nProgressBarMax - enabledChunks;
}
}
// draw the suit power bar
vgui::surface()->DrawSetColor( GetFgColor() );
for (int i = 0; i < enabledChunks; i++)
{
vgui::surface()->DrawFilledRect( xpos, ypos, xpos + barChunkWidth, ypos + m_flBarHeight );
xpos += (barChunkWidth + m_flBarChunkGap);
}
// draw the exhausted portion of the bar.
Color clrExhausted = GetFgColor();
clrExhausted[3] = ((float)clrExhausted[3] / 255.0f) * m_iBarDisabledAlpha;
vgui::surface()->DrawSetColor( clrExhausted );
for (int i = enabledChunks; i < m_nProgressBarMax; i++)
{
vgui::surface()->DrawFilledRect( xpos, ypos, xpos + barChunkWidth, ypos + m_flBarHeight );
xpos += (barChunkWidth + m_flBarChunkGap);
}
}
//-----------------------------------------------------------------------------
// Purpose: renders the vgui panel
//-----------------------------------------------------------------------------
void CHudGenericGameTimer::Paint()
{
// Check for 00:00 timer
int nTimerWidth = m_nTimerWidth;
if (m_iValue > 600)
nTimerWidth += vgui::surface()->GetCharacterWidth( m_hNumberFont, '0' );
// draw the background
int wide = max( nTimerWidth, m_nLabelWidth ) + m_flBorder;
if (m_flMinWidth > wide)
wide = m_flMinWidth;
int tall = m_nTimerHeight + m_nLabelHeight + (m_flBorder/2);
if (m_nProgressBarMax > 0)
tall += m_flBarHeight + m_flBarVerticalGap;
else
tall += (m_flBorder/2);
int screenW, screenH;
GetHudSize( screenW, screenH );
float flScalarX = (m_flOverrideX != -1.0f ? m_flOverrideX : 0.5f);
float flScalarY = (m_flOverrideY != -1.0f ? m_flOverrideY : 0.05f);
int x = (screenW - wide) * flScalarX;
int y = (screenH - tall) * flScalarY;
DrawBox( x, y, wide, tall, GetBgColor(), 1.0f);
y += (m_flBorder/2);
// draw our bars
if (m_nProgressBarMax > 0)
{
int barX = x + (m_flBorder/2);
PaintBars( barX, y, wide - m_flBorder );
y += m_flBarVerticalGap;
}
if (m_nLabelHeight > 0)
{
vgui::surface()->DrawSetTextFont( m_hTextFont );
vgui::surface()->DrawSetTextColor( GetFgColor() );
vgui::surface()->DrawSetTextPos( x + ((wide - m_nLabelWidth) * 0.5f), y );
vgui::surface()->DrawUnicodeString( m_LabelText );
y += m_nLabelHeight;
}
// draw our numbers
vgui::surface()->DrawSetTextColor( GetFgColor() );
int digitX = x + ((wide - nTimerWidth) * 0.5f);
int digitY = y;
PaintNumbers( m_hNumberFont, digitX, digitY );
}

View File

@ -37,6 +37,9 @@ char g_szPrelocalisedMenuString[MAX_MENU_STRING];
DECLARE_HUDELEMENT( CHudMenu );
DECLARE_HUD_MESSAGE( CHudMenu, ShowMenu );
#ifdef MAPBASE
DECLARE_HUD_MESSAGE( CHudMenu, ShowMenuComplex );
#endif
//
//-----------------------------------------------------
@ -71,6 +74,9 @@ CHudMenu::CHudMenu( const char *pElementName ) :
void CHudMenu::Init( void )
{
HOOK_HUD_MESSAGE( CHudMenu, ShowMenu );
#ifdef MAPBASE
HOOK_HUD_MESSAGE( CHudMenu, ShowMenuComplex );
#endif
m_bMenuTakesInput = false;
m_bMenuDisplayed = false;
@ -81,6 +87,24 @@ void CHudMenu::Init( void )
Reset();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudMenu::LevelInit()
{
CHudElement::LevelInit();
#ifdef MAPBASE
if (m_bMapDefinedMenu)
{
// Fixes menu retaining on level change/reload
// TODO: Would non-map menus benefit from this as well?
m_bMenuTakesInput = false;
m_bMenuDisplayed = false;
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -114,7 +138,11 @@ void CHudMenu::OnThink()
float flSelectionTimeout = MENU_SELECTION_TIMEOUT;
// If we've been open for a while without input, hide
#ifdef MAPBASE
if ( m_bMenuDisplayed && ( gpGlobals->curtime - m_flSelectionTime > flSelectionTimeout && !m_bMapDefinedMenu ) )
#else
if ( m_bMenuDisplayed && ( gpGlobals->curtime - m_flSelectionTime > flSelectionTimeout ) )
#endif
{
m_bMenuDisplayed = false;
}
@ -130,11 +158,24 @@ bool CHudMenu::ShouldDraw( void )
return false;
// check for if menu is set to disappear
if ( m_flShutoffTime > 0 && m_flShutoffTime <= gpGlobals->realtime )
if ( m_flShutoffTime > 0 )
{
// times up, shutoff
m_bMenuDisplayed = false;
return false;
#ifdef MAPBASE
if ( m_bMapDefinedMenu && !m_bPlayingFadeout && (m_flShutoffTime - m_flOpenCloseTime) <= GetMenuTime() )
{
// Begin closing the menu
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MenuClose" );
m_bMenuTakesInput = false;
m_bPlayingFadeout = true;
}
else
#endif
if ( m_flShutoffTime <= GetMenuTime() )
{
// times up, shutoff
m_bMenuDisplayed = false;
return false;
}
}
return draw;
@ -169,23 +210,21 @@ void CHudMenu::Paint()
return;
// center it
int x = 20;
int x = m_nBorder;
Color menuColor = m_MenuColor;
Color itemColor = m_ItemColor;
int c = m_Processed.Count();
int border = 20;
int wide = m_nMaxPixels + border;
int tall = m_nHeight + border;
int wide = m_nMaxPixels + m_nBorder;
int tall = m_nHeight + m_nBorder;
int y = ( ScreenHeight() - tall ) * 0.5f;
DrawBox( x - border/2, y - border/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
DrawBox( x - m_nBorder/2, y - m_nBorder/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
//DrawTexturedBox( x - border/2, y - border/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
//DrawTexturedBox( x - m_nBorder/2, y - m_nBorder/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
menuColor[3] = menuColor[3] * ( m_flSelectionAlphaOverride / 255.0f );
itemColor[3] = itemColor[3] * ( m_flSelectionAlphaOverride / 255.0f );
@ -195,7 +234,18 @@ void CHudMenu::Paint()
ProcessedLine *line = &m_Processed[ i ];
Assert( line );
Color clr = line->menuitem != 0 ? itemColor : menuColor;
#ifdef MAPBASE
bool isItem = true;
if (line->menuitem == 0 && line->startchar < (MAX_MENU_STRING-1) && g_szMenuString[ line->startchar ] != L'0' && g_szMenuString[ line->startchar+1 ] != L'.')
{
// Can't use 0 directly because it gets conflated with the cancel item
isItem = false;
}
#else
bool isItem = line->menuitem != 0;
#endif
Color clr = isItem ? itemColor : menuColor;
bool canblur = false;
if ( line->menuitem != 0 &&
@ -208,15 +258,15 @@ void CHudMenu::Paint()
vgui::surface()->DrawSetTextColor( clr );
int drawLen = line->length;
if ( line->menuitem != 0 )
if (isItem)
{
drawLen *= m_flTextScan;
}
vgui::surface()->DrawSetTextFont( line->menuitem != 0 ? m_hItemFont : m_hTextFont );
vgui::surface()->DrawSetTextFont( isItem ? m_hItemFont : m_hTextFont );
PaintString( &g_szMenuString[ line->startchar ], drawLen,
line->menuitem != 0 ? m_hItemFont : m_hTextFont, x, y );
isItem ? m_hItemFont : m_hTextFont, x, y );
if ( canblur )
{
@ -242,6 +292,20 @@ void CHudMenu::Paint()
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline float CHudMenu::GetMenuTime( void )
{
#ifdef MAPBASE
// In singleplayer, use the curtime instead. This fixes issues with menus disappearing after pausing
if (gpGlobals->maxClients <= 1)
return gpGlobals->curtime;
#endif
return gpGlobals->realtime;
}
//-----------------------------------------------------------------------------
// Purpose: selects an item from the menu
//-----------------------------------------------------------------------------
@ -260,7 +324,7 @@ void CHudMenu::SelectMenuItem( int menu_item )
// remove the menu quickly
m_bMenuTakesInput = false;
m_flShutoffTime = gpGlobals->realtime + m_flOpenCloseTime;
m_flShutoffTime = GetMenuTime() + m_flOpenCloseTime;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuClose");
}
}
@ -339,9 +403,20 @@ void CHudMenu::ProcessText( void )
{
ProcessedLine *l = &m_Processed[ i ];
Assert( l );
#ifdef MAPBASE
bool isItem = true;
if (l->menuitem == 0 && l->startchar < (MAX_MENU_STRING-1) && g_szMenuString[ l->startchar ] != L'0' && g_szMenuString[ l->startchar+1 ] != L'.')
{
// Can't use 0 directly because it gets conflated with the cancel item
isItem = false;
}
#else
bool isItem = l->menuitem != 0;
#endif
int pixels = 0;
vgui::HFont font = l->menuitem != 0 ? m_hItemFont : m_hTextFont;
vgui::HFont font = isItem ? m_hItemFont : m_hTextFont;
for ( int ch = 0; ch < l->length; ch++ )
{
@ -364,7 +439,7 @@ void CHudMenu::ProcessText( void )
void CHudMenu::HideMenu( void )
{
m_bMenuTakesInput = false;
m_flShutoffTime = gpGlobals->realtime + m_flOpenCloseTime;
m_flShutoffTime = GetMenuTime() + m_flOpenCloseTime;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuClose");
}
@ -381,6 +456,11 @@ void CHudMenu::ShowMenu( const char * menuName, int validSlots )
m_flShutoffTime = -1;
m_bitsValidSlots = validSlots;
m_fWaitingForMore = 0;
m_nBorder = 20;
#ifdef MAPBASE
m_bMapDefinedMenu = false;
m_bPlayingFadeout = false;
#endif
Q_strncpy( g_szPrelocalisedMenuString, menuName, sizeof( g_szPrelocalisedMenuString ) );
@ -408,6 +488,11 @@ void CHudMenu::ShowMenu_KeyValueItems( KeyValues *pKV )
m_flShutoffTime = -1;
m_fWaitingForMore = 0;
m_bitsValidSlots = 0;
m_nBorder = 20;
#ifdef MAPBASE
m_bMapDefinedMenu = false;
m_bPlayingFadeout = false;
#endif
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuOpen");
m_nSelectedItem = -1;
@ -426,7 +511,11 @@ void CHudMenu::ShowMenu_KeyValueItems( KeyValues *pKV )
const char *pszItem = item->GetName();
const wchar_t *wLocalizedItem = g_pVGuiLocalize->Find( pszItem );
#ifdef MAPBASE
nCount = _snwprintf( pWritePosition, nRemaining, L"->%d. %ls\n", i+1, wLocalizedItem );
#else
nCount = _snwprintf( pWritePosition, nRemaining, L"%d. %ls\n", i+1, wLocalizedItem );
#endif
nRemaining -= nCount;
pWritePosition += nCount;
@ -436,7 +525,11 @@ void CHudMenu::ShowMenu_KeyValueItems( KeyValues *pKV )
// put a cancel on the end
m_bitsValidSlots |= (1<<9);
#ifdef MAPBASE
nCount = _snwprintf( pWritePosition, nRemaining, L"->0. %ls\n", g_pVGuiLocalize->Find( "#Cancel" ) );
#else
nCount = _snwprintf( pWritePosition, nRemaining, L"0. %ls\n", g_pVGuiLocalize->Find( "#Cancel" ) );
#endif
nRemaining -= nCount;
pWritePosition += nCount;
@ -465,8 +558,7 @@ void CHudMenu::MsgFunc_ShowMenu( bf_read &msg)
if ( DisplayTime > 0 )
{
m_flShutoffTime = m_flOpenCloseTime + DisplayTime + gpGlobals->realtime;
m_flShutoffTime = m_flOpenCloseTime + DisplayTime + GetMenuTime();
}
else
{
@ -511,8 +603,131 @@ void CHudMenu::MsgFunc_ShowMenu( bf_read &msg)
}
m_fWaitingForMore = NeedMore;
m_nBorder = 20;
#ifdef MAPBASE
m_bMapDefinedMenu = false;
m_bPlayingFadeout = false;
#endif
}
#ifdef MAPBASE
ConVar hud_menu_complex_border( "hud_menu_complex_border", "30" );
//-----------------------------------------------------------------------------
// Purpose: Message handler for ShowMenu message with more options for game_menu
// takes four values:
// short : a bitfield of keys that are valid input
// float : the duration, in seconds, the menu should stay up. -1 means it stays until something is chosen.
// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, false if it's the last string
// string: menu string to display
// if this message is never received, then scores will simply be the combined totals of the players.
//-----------------------------------------------------------------------------
void CHudMenu::MsgFunc_ShowMenuComplex( bf_read &msg)
{
m_bitsValidSlots = (short)msg.ReadWord();
float DisplayTime = msg.ReadFloat();
int NeedMore = msg.ReadByte();
m_nBorder = hud_menu_complex_border.GetInt();
m_bMapDefinedMenu = true;
m_bPlayingFadeout = false;
if ( DisplayTime > 0 )
{
m_flShutoffTime = m_flOpenCloseTime + DisplayTime + GetMenuTime();
}
else
{
m_flShutoffTime = -1;
}
if ( m_bitsValidSlots > -1 )
{
char szString[2048];
msg.ReadString( szString, sizeof(szString) );
if ( !m_fWaitingForMore ) // this is the start of a new menu
{
Q_strncpy( g_szPrelocalisedMenuString, szString, sizeof( g_szPrelocalisedMenuString ) );
}
else
{ // append to the current menu string
Q_strncat( g_szPrelocalisedMenuString, szString, sizeof( g_szPrelocalisedMenuString ), COPY_ALL_CHARACTERS );
}
if ( !NeedMore )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuOpenFlash");
m_nSelectedItem = -1;
// we have the whole string, so we can localise it now
wchar_t *pWritePosition = g_szMenuString;
int nRemaining = sizeof( g_szMenuString ) / sizeof( wchar_t );
int nCount;
char *pszToken = strtok( szString, "\n" );
int nCurItem = 0;
for (; pszToken != NULL; pszToken = strtok( NULL, "\n" ), nCurItem++)
{
if (!*pszToken || *pszToken == ' ')
continue;
wchar_t wszMenuItem[128];
const wchar_t *wLocalizedItem = g_pVGuiLocalize->Find( pszToken );
if (wLocalizedItem)
{
V_wcsncpy( wszMenuItem, wLocalizedItem, sizeof( wszMenuItem ) );
}
else
{
g_pVGuiLocalize->ConvertANSIToUnicode( pszToken, wszMenuItem, sizeof( wszMenuItem ) );
}
if (nCurItem == 0)
{
// First item is title
nCount = _snwprintf( pWritePosition, nRemaining, L"%ls\n", wszMenuItem );
}
else
{
// If this item isn't valid, skip until it is
//while (!(m_bitsValidSlots & (1 << nCurItem)) && nCurItem < 10)
//{
// nCurItem++;
//}
if (nCurItem == 10)
nCurItem = 0;
nCount = _snwprintf( pWritePosition, nRemaining, L"->%d. %ls\n", nCurItem, wszMenuItem );
}
nRemaining -= nCount;
pWritePosition += nCount;
}
ProcessText();
}
m_bMenuDisplayed = true;
if (m_bitsValidSlots > 0)
m_bMenuTakesInput = true;
else
m_bMenuTakesInput = false;
m_flSelectionTime = gpGlobals->curtime;
}
else
{
HideMenu();
}
m_fWaitingForMore = NeedMore;
}
#endif
//-----------------------------------------------------------------------------
// Purpose: hud scheme settings
//-----------------------------------------------------------------------------

View File

@ -26,10 +26,14 @@ class CHudMenu : public CHudElement, public vgui::Panel
public:
CHudMenu( const char *pElementName );
void Init( void );
void LevelInit( void );
void VidInit( void );
void Reset( void );
virtual bool ShouldDraw( void );
void MsgFunc_ShowMenu( bf_read &msg );
#ifdef MAPBASE
void MsgFunc_ShowMenuComplex( bf_read &msg );
#endif
void HideMenu( void );
void ShowMenu( const char * menuName, int keySlot );
void ShowMenu_KeyValueItems( KeyValues *pKV );
@ -42,6 +46,8 @@ private:
virtual void Paint();
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
private:
float GetMenuTime( void );
void ProcessText( void );
void PaintString( const wchar_t *text, int textlen, vgui::HFont& font, int x, int y );
@ -59,6 +65,7 @@ private:
int m_nMaxPixels;
int m_nHeight;
int m_nBorder;
bool m_bMenuDisplayed;
int m_bitsValidSlots;
@ -69,6 +76,12 @@ private:
float m_flSelectionTime;
#ifdef MAPBASE
// Indicates this menu is defined by game_menu
bool m_bMapDefinedMenu;
bool m_bPlayingFadeout;
#endif
CPanelAnimationVar( float, m_flOpenCloseTime, "OpenCloseTime", "1" );
CPanelAnimationVar( float, m_flBlur, "Blur", "0" );

View File

@ -45,7 +45,7 @@ extern IScriptManager *scriptmanager;
extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
#ifdef MAPBASE_VSCRIPT
extern int vscript_debugger_port;
ConVar script_connect_debugger_on_mapspawn_client( "script_connect_debugger_on_mapspawn_client", "0" );
#endif
// #define VMPROFILE 1
@ -765,10 +765,13 @@ bool VScriptClientInit()
#endif
#ifdef MAPBASE_VSCRIPT
if ( vscript_debugger_port )
if ( script_connect_debugger_on_mapspawn_client.GetInt() == 2 )
{
g_pScriptVM->ConnectDebugger( vscript_debugger_port, 10.0f );
}
else if ( script_connect_debugger_on_mapspawn_client.GetInt() != 0 )
{
g_pScriptVM->ConnectDebugger( vscript_debugger_port );
vscript_debugger_port = 0;
}
#endif

View File

@ -3045,7 +3045,7 @@ void CAI_BaseNPC::SetHeadDirection( const Vector &vTargetPos, float flInterval)
//--------------------------------------
// Set head yaw
//--------------------------------------
float flDesiredYaw = VecToYaw(vTargetPos - GetLocalOrigin()) - GetLocalAngles().y;
float flDesiredYaw = VecToYaw(vTargetPos - GetAbsOrigin()) - GetAbsAngles().y;
if (flDesiredYaw > 180)
flDesiredYaw -= 360;
if (flDesiredYaw < -180)
@ -8005,7 +8005,7 @@ void CAI_BaseNPC::NPCInit ( void )
SetGravity(1.0); // Don't change
m_takedamage = DAMAGE_YES;
GetMotor()->SetIdealYaw( GetLocalAngles().y );
GetMotor()->SetIdealYaw( GetAbsAngles().y );
m_iMaxHealth = m_iHealth;
m_lifeState = LIFE_ALIVE;
SetIdealState( NPC_STATE_IDLE );// Assume npc will be idle, until proven otherwise
@ -9657,7 +9657,7 @@ float CAI_BaseNPC::CalcIdealYaw( const Vector &vecTarget )
vecProjection.y = vecTarget.x;
vecProjection.z = 0;
return UTIL_VecToYaw( vecProjection - GetLocalOrigin() );
return UTIL_VecToYaw( vecProjection - GetAbsOrigin() );
}
else if ( GetNavigator()->GetMovementActivity() == ACT_STRAFE_RIGHT )
{
@ -9665,7 +9665,7 @@ float CAI_BaseNPC::CalcIdealYaw( const Vector &vecTarget )
vecProjection.y = vecTarget.x;
vecProjection.z = 0;
return UTIL_VecToYaw( vecProjection - GetLocalOrigin() );
return UTIL_VecToYaw( vecProjection - GetAbsOrigin() );
}
#ifdef MAPBASE
// Allow hint nodes to override the yaw without needing to control AI
@ -9676,7 +9676,7 @@ float CAI_BaseNPC::CalcIdealYaw( const Vector &vecTarget )
#endif
else
{
return UTIL_VecToYaw ( vecTarget - GetLocalOrigin() );
return UTIL_VecToYaw ( vecTarget - GetAbsOrigin() );
}
}
@ -9876,7 +9876,7 @@ void CAI_BaseNPC::HandleAnimEvent( animevent_t *pEvent )
//DevMsg( "Turned!\n" );
SetIdealActivity( ACT_IDLE );
Forget( bits_MEMORY_TURNING );
SetBoneController( 0, GetLocalAngles().y );
SetBoneController( 0, GetAbsAngles().y );
IncrementInterpolationFrame();
break;
}
@ -11155,7 +11155,7 @@ Vector CAI_BaseNPC::GetShootEnemyDir( const Vector &shootOrigin, bool bNoisy )
else
{
Vector forward;
AngleVectors( GetLocalAngles(), &forward );
AngleVectors( GetAbsAngles(), &forward );
return forward;
}
}
@ -14193,7 +14193,7 @@ bool CAI_BaseNPC::OverrideMove( float flInterval )
float CAI_BaseNPC::VecToYaw( const Vector &vecDir )
{
if (vecDir.x == 0 && vecDir.y == 0 && vecDir.z == 0)
return GetLocalAngles().y;
return GetAbsAngles().y;
return UTIL_VecToYaw( vecDir );
}

View File

@ -1180,6 +1180,11 @@ public:
void SetDeathPose( const int &iDeathPose ) { m_iDeathPose = iDeathPose; }
void SetDeathPoseFrame( const int &iDeathPoseFrame ) { m_iDeathFrame = iDeathPoseFrame; }
#ifdef MAPBASE
int GetDeathPose() { return m_iDeathPose; }
int GetDeathPoseFrame() { return m_iDeathFrame; }
#endif
void SelectDeathPose( const CTakeDamageInfo &info );
virtual bool ShouldPickADeathPose( void ) { return true; }

View File

@ -964,7 +964,7 @@ void CAI_BaseNPC::StartTurn( float flDeltaYaw )
{
float flCurrentYaw;
flCurrentYaw = UTIL_AngleMod( GetLocalAngles().y );
flCurrentYaw = UTIL_AngleMod( GetAbsAngles().y );
GetMotor()->SetIdealYaw( UTIL_AngleMod( flCurrentYaw + flDeltaYaw ) );
SetTurnActivity();
}
@ -1157,7 +1157,7 @@ void CAI_BaseNPC::StartScriptMoveToTargetTask( int task )
{
TaskFail(FAIL_NO_TARGET);
}
else if ( (m_hTargetEnt->GetAbsOrigin() - GetLocalOrigin()).Length() < 1 )
else if ( (m_hTargetEnt->GetAbsOrigin() - GetAbsOrigin()).Length() < 1 )
{
TaskComplete();
}
@ -1622,7 +1622,7 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask )
break;
case TASK_SET_IDEAL_YAW_TO_CURRENT:
GetMotor()->SetIdealYaw( UTIL_AngleMod( GetLocalAngles().y ) );
GetMotor()->SetIdealYaw( UTIL_AngleMod( GetAbsAngles().y ) );
TaskComplete();
break;
@ -1776,7 +1776,7 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask )
{
TaskFail(FAIL_NO_TARGET);
}
else if ( (pTarget->GetAbsOrigin() - GetLocalOrigin()).Length() < 1 )
else if ( (pTarget->GetAbsOrigin() - GetAbsOrigin()).Length() < 1 )
{
TaskComplete();
}
@ -3021,7 +3021,7 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask )
{
if ( m_hTargetEnt != NULL )
{
GetMotor()->SetIdealYaw( UTIL_AngleMod( m_hTargetEnt->GetLocalAngles().y ) );
GetMotor()->SetIdealYaw( UTIL_AngleMod( m_hTargetEnt->GetAbsAngles().y ) );
}
if ( m_scriptState != SCRIPT_CUSTOM_MOVE_TO_MARK )
@ -3350,7 +3350,7 @@ void CAI_BaseNPC::RunTask( const Task_t *pTask )
pTarget = GetEnemy();
if ( pTarget )
{
GetMotor()->SetIdealYawAndUpdate( pTarget->GetAbsOrigin() - GetLocalOrigin() , AI_KEEP_YAW_SPEED );
GetMotor()->SetIdealYawAndUpdate( pTarget->GetAbsOrigin() - GetAbsOrigin(), AI_KEEP_YAW_SPEED );
}
if ( IsActivityFinished() )

View File

@ -1624,6 +1624,9 @@ void CHL2_Player::Spawn(void)
if (m_iszProtagonistName == NULL_STRING && *g_szDefaultProtagonist)
m_iszProtagonistName = MAKE_STRING( g_szDefaultProtagonist );
if (m_iszProtagonistName != NULL_STRING)
SetProtagonist( STRING( m_iszProtagonistName ) );
#endif
//

View File

@ -256,7 +256,7 @@ END_DATADESC()
//-----------------------------------------------------------------------------
void CNPC_PoisonZombie::Precache( void )
{
PrecacheModel("models/zombie/poison.mdl");
PrecacheModel( DefaultOrCustomModel( "models/zombie/poison.mdl" ) );
PrecacheScriptSound( "NPC_PoisonZombie.Die" );
PrecacheScriptSound( "NPC_PoisonZombie.ThrowWarn" );
@ -509,7 +509,7 @@ void CNPC_PoisonZombie::SetZombieModel( void )
}
else
{
SetModel( "models/zombie/poison.mdl" );
SetModel( DefaultOrCustomModel( "models/zombie/poison.mdl" ) );
SetHullType(HULL_HUMAN);
}

View File

@ -472,8 +472,8 @@ void CNPC_Antlion::Precache( void )
#ifdef HL2_EPISODIC
if ( IsWorker() )
{
PrecacheModel( ANTLION_WORKER_MODEL );
PropBreakablePrecacheAll( MAKE_STRING( ANTLION_WORKER_MODEL ) );
PrecacheModel( DefaultOrCustomModel( ANTLION_WORKER_MODEL ) );
PropBreakablePrecacheAll( MAKE_STRING( DefaultOrCustomModel( ANTLION_WORKER_MODEL ) ) );
UTIL_PrecacheOther( "grenade_spit" );
PrecacheParticleSystem( "blood_impact_antlion_worker_01" );
PrecacheParticleSystem( "antlion_gib_02" );
@ -482,8 +482,8 @@ void CNPC_Antlion::Precache( void )
else
#endif // HL2_EPISODIC
{
PrecacheModel( ANTLION_MODEL );
PropBreakablePrecacheAll( MAKE_STRING( ANTLION_MODEL ) );
PrecacheModel( DefaultOrCustomModel( ANTLION_MODEL ) );
PropBreakablePrecacheAll( MAKE_STRING( DefaultOrCustomModel( ANTLION_MODEL ) ) );
PrecacheParticleSystem( "blood_impact_antlion_01" );
PrecacheParticleSystem( "AntlionGib" );
}

View File

@ -4055,9 +4055,12 @@ void CNPC_AttackHelicopter::Event_Killed( const CTakeDamageInfo &info )
}
m_lifeState = LIFE_DYING;
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
controller.SoundChangeVolume( m_pGunFiringSound, 0.0, 0.1f );
if ( GetSleepState() != AISS_WAITING_FOR_INPUT )
{
CSoundEnvelopeController& controller = CSoundEnvelopeController::GetController();
controller.SoundChangeVolume( m_pGunFiringSound, 0.0, 0.1f );
}
if( GetCrashPoint() == NULL )
{

View File

@ -839,6 +839,9 @@ void CNPC_Citizen::SelectModel()
}
}
// Models selected this way must be unique to avoid conflicts in save/restore
m_Type = CT_UNIQUE;
// Just set the model right here
SetModelName( AllocPooledString( returnValue.m_pszString ) );
return;

View File

@ -275,7 +275,7 @@ CNPC_CombineCamera::~CNPC_CombineCamera()
//-----------------------------------------------------------------------------
void CNPC_CombineCamera::Precache()
{
PrecacheModel(COMBINE_CAMERA_MODEL);
PrecacheModel( DefaultOrCustomModel( COMBINE_CAMERA_MODEL ) );
PrecacheModel(COMBINE_CAMERA_GLOW_SPRITE);
PrecacheModel(COMBINE_CAMERA_FLASH_SPRITE);
@ -304,8 +304,7 @@ void CNPC_CombineCamera::Precache()
void CNPC_CombineCamera::Spawn()
{
Precache();
SetModel(COMBINE_CAMERA_MODEL);
SetModel( DefaultOrCustomModel( COMBINE_CAMERA_MODEL ) );
m_pEyeFlash = CSprite::SpriteCreate(COMBINE_CAMERA_FLASH_SPRITE, GetLocalOrigin(), FALSE);
m_pEyeFlash->SetTransparency(kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation);

View File

@ -1110,7 +1110,7 @@ void CNPC_CombineDropship::Spawn( void )
// moving this after we've created m_hContainer so we can properly setup the
// weapon_pitch and weapon_yaw pose parameter indexes in PopulatePoseParameters()
SetModel( "models/combine_dropship.mdl" );
SetModel( DefaultOrCustomModel( "models/combine_dropship.mdl" ) );
// Setup our bbox
if ( m_hContainer )
@ -1191,7 +1191,7 @@ void CNPC_CombineDropship::Activate( void )
void CNPC_CombineDropship::Precache( void )
{
// Models
PrecacheModel("models/combine_dropship.mdl");
PrecacheModel( DefaultOrCustomModel( "models/combine_dropship.mdl" ) );
switch ( m_iCrateType )
{
case CRATE_SOLDIER:

View File

@ -564,11 +564,11 @@ void CNPC_CombineGunship::Spawn( void )
if ( HasSpawnFlags( SF_GUNSHIP_USE_CHOPPER_MODEL ) )
{
SetModel( "models/combine_helicopter.mdl" );
SetModel( DefaultOrCustomModel( "models/combine_helicopter.mdl" ) );
}
else
{
SetModel( "models/gunship.mdl" );
SetModel( DefaultOrCustomModel( "models/gunship.mdl" ) );
}
ExtractBbox( SelectHeaviestSequence( ACT_GUNSHIP_PATROL ), m_cullBoxMins, m_cullBoxMaxs );
@ -690,12 +690,12 @@ void CNPC_CombineGunship::Precache( void )
{
if ( HasSpawnFlags( SF_GUNSHIP_USE_CHOPPER_MODEL ) )
{
PrecacheModel( "models/combine_helicopter.mdl" );
PrecacheModel( DefaultOrCustomModel( "models/combine_helicopter.mdl" ) );
Chopper_PrecacheChunks( this );
}
else
{
PrecacheModel("models/gunship.mdl");
PrecacheModel( DefaultOrCustomModel( "models/gunship.mdl" ) );
}
PrecacheModel("sprites/lgtning.vmt");
@ -725,7 +725,7 @@ void CNPC_CombineGunship::Precache( void )
g_iGunshipEffectIndex = PrecacheModel( "sprites/physbeam.vmt" );
}
PropBreakablePrecacheAll( MAKE_STRING("models/gunship.mdl") );
PropBreakablePrecacheAll( MAKE_STRING( DefaultOrCustomModel( "models/gunship.mdl" ) ) );
BaseClass::Precache();
}

View File

@ -38,6 +38,11 @@ ConVar sk_combine_guard_kick( "sk_combine_guard_kick", "0");
ConVar combine_guard_spawn_health( "combine_guard_spawn_health", "1" );
extern ConVar sk_plr_dmg_buckshot;
#ifdef MAPBASE
ConVar sk_combine_head_dmg_multiplier( "sk_combine_head_dmg_multiplier", "2" );
#endif
extern ConVar sk_plr_num_shotgun_pellets;
//Whether or not the combine should spawn health on death
@ -222,8 +227,14 @@ float CNPC_CombineS::GetHitgroupDamageMultiplier( int iHitGroup, const CTakeDama
{
case HITGROUP_HEAD:
{
#ifdef MAPBASE
// Now you can change the multiplier of headshot damage in console!
return sk_combine_head_dmg_multiplier.GetFloat();
#else
// Soldiers take double headshot damage
return 2.0f;
#endif
}
}

View File

@ -455,7 +455,7 @@ void CNPC_Dog::Spawn( void )
BaseClass::Spawn();
SetModel( "models/dog.mdl" );
SetModel( DefaultOrCustomModel( "models/dog.mdl" ) );
SetHullType( HULL_WIDE_HUMAN );
SetHullSizeNormal();
@ -638,7 +638,7 @@ void CNPC_Dog::PullObject( bool bMantain )
//-----------------------------------------------------------------------------
void CNPC_Dog::Precache( void )
{
PrecacheModel( "models/dog.mdl" );
PrecacheModel( DefaultOrCustomModel( "models/dog.mdl" ) );
PrecacheScriptSound( "Weapon_PhysCannon.Launch" );

View File

@ -396,7 +396,7 @@ static const char *s_pLegsModel = "models/gibs/fast_zombie_legs.mdl";
//-----------------------------------------------------------------------------
void CFastZombie::Precache( void )
{
PrecacheModel("models/zombie/fast.mdl");
PrecacheModel( DefaultOrCustomModel( "models/zombie/fast.mdl" ) );
#ifdef HL2_EPISODIC
PrecacheModel("models/zombie/Fast_torso.mdl");
PrecacheScriptSound( "NPC_FastZombie.CarEnter1" );
@ -773,7 +773,7 @@ void CFastZombie::SetZombieModel( void )
}
else
{
SetModel( "models/zombie/fast.mdl" );
SetModel( DefaultOrCustomModel( "models/zombie/fast.mdl" ) );
SetHullType(HULL_HUMAN);
}

View File

@ -133,7 +133,7 @@ END_DATADESC()
//-----------------------------------------------------------------------------
void CNPC_Fisherman::SelectModel()
{
SetModelName( AllocPooledString( FISHERMAN_MODEL ) );
SetModelName( AllocPooledString( DefaultOrCustomModel( FISHERMAN_MODEL ) ) );
}
//-----------------------------------------------------------------------------

View File

@ -97,7 +97,7 @@ void CNPC_GMan::Spawn()
BaseClass::Spawn();
SetModel( "models/gman.mdl" );
SetModel( DefaultOrCustomModel( "models/gman.mdl" ) );
SetHullType(HULL_HUMAN);
SetHullSizeNormal();
@ -123,7 +123,7 @@ void CNPC_GMan::Spawn()
//-----------------------------------------------------------------------------
void CNPC_GMan::Precache()
{
PrecacheModel( "models/gman.mdl" );
PrecacheModel( DefaultOrCustomModel( "models/gman.mdl" ) );
BaseClass::Precache();
}

View File

@ -299,7 +299,7 @@ Activity CNPC_Monk::NPC_TranslateActivity( Activity eNewActivity )
//-----------------------------------------------------------------------------
void CNPC_Monk::Precache()
{
PrecacheModel( "models/Monk.mdl" );
PrecacheModel( DefaultOrCustomModel( "models/Monk.mdl" ) );
PrecacheScriptSound( "NPC_Citizen.FootstepLeft" );
PrecacheScriptSound( "NPC_Citizen.FootstepRight" );
@ -317,7 +317,7 @@ void CNPC_Monk::Spawn()
BaseClass::Spawn();
SetModel( "models/Monk.mdl" );
SetModel( DefaultOrCustomModel( "models/Monk.mdl" ) );
SetHullType(HULL_HUMAN);
SetHullSizeNormal();

View File

@ -99,7 +99,7 @@ void CNPC_Mossman::Spawn()
BaseClass::Spawn();
SetModel( "models/mossman.mdl" );
SetModel( DefaultOrCustomModel( "models/mossman.mdl" ) );
SetHullType(HULL_HUMAN);
SetHullSizeNormal();
@ -124,7 +124,7 @@ void CNPC_Mossman::Spawn()
//-----------------------------------------------------------------------------
void CNPC_Mossman::Precache()
{
PrecacheModel( "models/mossman.mdl" );
PrecacheModel( DefaultOrCustomModel( "models/mossman.mdl" ) );
BaseClass::Precache();
}

View File

@ -250,7 +250,7 @@ void CZombie::Precache( void )
{
BaseClass::Precache();
PrecacheModel( "models/zombie/classic.mdl" );
PrecacheModel( DefaultOrCustomModel( "models/zombie/classic.mdl" ) );
PrecacheModel( "models/zombie/classic_torso.mdl" );
PrecacheModel( "models/zombie/classic_legs.mdl" );
@ -515,7 +515,7 @@ void CZombie::SetZombieModel( void )
}
else
{
SetModel( "models/zombie/classic.mdl" );
SetModel( DefaultOrCustomModel( "models/zombie/classic.mdl" ) );
SetHullType( HULL_HUMAN );
}

View File

@ -249,7 +249,7 @@ void CNPC_Zombine::Precache( void )
{
BaseClass::Precache();
PrecacheModel( "models/zombie/zombie_soldier.mdl" );
PrecacheModel( DefaultOrCustomModel( "models/zombie/zombie_soldier.mdl" ) );
PrecacheScriptSound( "Zombie.FootstepRight" );
PrecacheScriptSound( "Zombie.FootstepLeft" );
@ -270,7 +270,7 @@ void CNPC_Zombine::Precache( void )
void CNPC_Zombine::SetZombieModel( void )
{
SetModel( "models/zombie/zombie_soldier.mdl" );
SetModel( DefaultOrCustomModel( "models/zombie/zombie_soldier.mdl" ) );
SetHullType( HULL_HUMAN );
SetBodygroup( ZOMBIE_BODYGROUP_HEADCRAB, !m_fIsHeadless );

View File

@ -14,6 +14,7 @@
#include "entityoutput.h"
#ifdef MAPBASE
#include "eventqueue.h"
#include "saverestore_utlvector.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
@ -824,3 +825,449 @@ void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Displays a custom number menu for player(s)
//-----------------------------------------------------------------------------
LINK_ENTITY_TO_CLASS( game_menu, CGameMenu );
BEGIN_DATADESC( CGameMenu )
DEFINE_UTLVECTOR( m_ActivePlayers, FIELD_EHANDLE ),
DEFINE_UTLVECTOR( m_ActivePlayerTimes, FIELD_TIME ),
DEFINE_KEYFIELD( m_flDisplayTime, FIELD_FLOAT, "holdtime" ),
DEFINE_KEYFIELD( m_iszTitle, FIELD_STRING, "Title" ),
DEFINE_KEYFIELD( m_iszOption[0], FIELD_STRING, "Case01" ),
DEFINE_KEYFIELD( m_iszOption[1], FIELD_STRING, "Case02" ),
DEFINE_KEYFIELD( m_iszOption[2], FIELD_STRING, "Case03" ),
DEFINE_KEYFIELD( m_iszOption[3], FIELD_STRING, "Case04" ),
DEFINE_KEYFIELD( m_iszOption[4], FIELD_STRING, "Case05" ),
DEFINE_KEYFIELD( m_iszOption[5], FIELD_STRING, "Case06" ),
DEFINE_KEYFIELD( m_iszOption[6], FIELD_STRING, "Case07" ),
DEFINE_KEYFIELD( m_iszOption[7], FIELD_STRING, "Case08" ),
DEFINE_KEYFIELD( m_iszOption[8], FIELD_STRING, "Case09" ),
DEFINE_KEYFIELD( m_iszOption[9], FIELD_STRING, "Case10" ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "ShowMenu", InputShowMenu ),
DEFINE_INPUTFUNC( FIELD_VOID, "HideMenu", InputHideMenu ),
DEFINE_INPUTFUNC( FIELD_VOID, "__DoRestore", InputDoRestore ),
// Outputs
DEFINE_OUTPUT( m_OnCase[0], "OnCase01" ),
DEFINE_OUTPUT( m_OnCase[1], "OnCase02" ),
DEFINE_OUTPUT( m_OnCase[2], "OnCase03" ),
DEFINE_OUTPUT( m_OnCase[3], "OnCase04" ),
DEFINE_OUTPUT( m_OnCase[4], "OnCase05" ),
DEFINE_OUTPUT( m_OnCase[5], "OnCase06" ),
DEFINE_OUTPUT( m_OnCase[6], "OnCase07" ),
DEFINE_OUTPUT( m_OnCase[7], "OnCase08" ),
DEFINE_OUTPUT( m_OnCase[8], "OnCase09" ),
DEFINE_OUTPUT( m_OnCase[9], "OnCase10" ),
DEFINE_OUTPUT( m_OutValue, "OutValue" ),
DEFINE_OUTPUT( m_OnTimeout, "OnTimeout" ),
DEFINE_THINKFUNC( TimeoutThink ),
END_DATADESC()
IMPLEMENT_AUTO_LIST( IGameMenuAutoList );
static const char *s_pTimeoutContext = "TimeoutContext";
#define MENU_INFINITE_TIME -1.0f
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CGameMenu::CGameMenu()
{
m_flDisplayTime = 5.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::OnRestore()
{
BaseClass::OnRestore();
// Do this a bit after we restore since the HUD might not be ready yet
g_EventQueue.AddEvent( this, "__DoRestore", 0.4f, this, this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::InputDoRestore( inputdata_t &inputdata )
{
// Check if we should restore the menu on anyone
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
{
if (m_ActivePlayers[i].Get())
{
if (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME)
{
CRecipientFilter filter;
filter.AddRecipient( static_cast<CBasePlayer*>( m_ActivePlayers[i].Get() ) );
ShowMenu( filter, m_ActivePlayerTimes[i] - gpGlobals->curtime );
continue;
}
}
// Remove this player since it's no longer valid
m_ActivePlayers.Remove( i );
m_ActivePlayerTimes.Remove( i );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::TimeoutThink()
{
float flNextLowestTime = FLT_MAX;
FOR_EACH_VEC( m_ActivePlayerTimes, i )
{
// If the player is still in our list, then they must not have selected an option
if (m_ActivePlayerTimes[i] != MENU_INFINITE_TIME)
{
if (m_ActivePlayerTimes[i] <= gpGlobals->curtime)
{
m_OnTimeout.FireOutput( m_ActivePlayers[i], this );
// Remove this player since it's no longer valid
m_ActivePlayers.Remove( i );
m_ActivePlayerTimes.Remove( i );
break;
}
else if (m_ActivePlayerTimes[i] < flNextLowestTime)
{
flNextLowestTime = m_ActivePlayerTimes[i];
}
}
}
if (flNextLowestTime < FLT_MAX)
{
SetNextThink( flNextLowestTime, s_pTimeoutContext );
}
else
{
SetContextThink( NULL, TICK_NEVER_THINK, s_pTimeoutContext );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::ShowMenu( CRecipientFilter &filter, float flDisplayTime )
{
// Before showing the menu, check each menu to see if there's already one being shown to one of our recipients
for ( int i = 0; i < IGameMenuAutoList::AutoList().Count(); i++ )
{
CGameMenu *pMenu = static_cast<CGameMenu*>( IGameMenuAutoList::AutoList()[i] );
if ( pMenu != this && pMenu->IsActive() )
{
for ( int j = 0; j < filter.GetRecipientCount(); j++ )
{
CBaseEntity *ent = CBaseEntity::Instance( filter.GetRecipientIndex( j ) );
if ( pMenu->IsActiveOnTarget( ent ) )
{
Msg( "%s overriding menu %s for player %i\n", GetDebugName(), pMenu->GetDebugName(), j );
pMenu->RemoveTarget( ent );
}
}
}
}
if (flDisplayTime == 0.0f)
{
flDisplayTime = m_flDisplayTime;
}
char szString[512] = { 0 };
int nBitsValidSlots = 0;
if (m_iszTitle != NULL_STRING)
{
V_strncat( szString, STRING( m_iszTitle ), sizeof( szString ) );
}
else
{
// Insert space to tell menu code to skip
V_strncat( szString, " ", sizeof( szString ) );
}
// Insert newline even if there's no string
V_strncat( szString, "\n", sizeof( szString ) );
// Populate the options
for (int i = 0; i < MAX_MENU_OPTIONS; i++)
{
if (m_iszOption[i] != NULL_STRING)
{
nBitsValidSlots |= (1 << i);
V_strncat( szString, STRING( m_iszOption[i] ), sizeof( szString ) );
}
else
{
// Insert space to tell menu code to skip
V_strncat( szString, " ", sizeof( szString ) );
}
// Insert newline even if there's no string
V_strncat( szString, "\n", sizeof( szString ) );
}
if (nBitsValidSlots <= 0 && m_iszTitle == NULL_STRING)
{
Warning( "%s ShowMenu: Can't show menu with no options or title\n", GetDebugName() );
return;
}
UserMessageBegin( filter, "ShowMenuComplex" );
WRITE_WORD( nBitsValidSlots );
WRITE_FLOAT( flDisplayTime );
WRITE_BYTE( 0 );
WRITE_STRING( szString );
MessageEnd();
float flMenuTime;
if (flDisplayTime <= 0.0f)
{
flMenuTime = MENU_INFINITE_TIME;
}
else
{
flMenuTime = gpGlobals->curtime + flDisplayTime;
}
for ( int j = 0; j < filter.GetRecipientCount(); j++ )
{
CBaseEntity *ent = CBaseEntity::Instance( filter.GetRecipientIndex( j ) );
// Check if we already track this player. If not, make a new one
bool bFound = false;
FOR_EACH_VEC( m_ActivePlayers, i )
{
if (m_ActivePlayers[i].Get() == ent)
{
m_ActivePlayerTimes[i] = flMenuTime;
bFound = true;
break;
}
}
if (!bFound)
{
m_ActivePlayers.AddToTail( ent );
m_ActivePlayerTimes.AddToTail( flMenuTime );
}
}
if (GetNextThink( s_pTimeoutContext ) == TICK_NEVER_THINK)
{
SetContextThink( &CGameMenu::TimeoutThink, gpGlobals->curtime + flDisplayTime, s_pTimeoutContext );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::HideMenu( CRecipientFilter &filter )
{
UserMessageBegin( filter, "ShowMenuComplex" );
WRITE_WORD( -1 );
WRITE_FLOAT( 0.0f );
WRITE_BYTE( 0 );
WRITE_STRING( "" );
MessageEnd();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::MenuSelected( int nSlot, CBaseEntity *pActivator )
{
if (nSlot <= 0 || nSlot > MAX_MENU_OPTIONS)
{
Warning( "%s: Invalid slot %i\n", GetDebugName(), nSlot );
return;
}
m_OnCase[nSlot-1].FireOutput( pActivator, this );
m_OutValue.Set( nSlot, pActivator, this );
RemoveTarget( pActivator );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CGameMenu::IsActive()
{
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
{
if (m_ActivePlayers[i].Get())
{
if (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME)
return true;
}
// Remove this player since it's no longer valid
m_ActivePlayers.Remove( i );
m_ActivePlayerTimes.Remove( i );
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CGameMenu::IsActiveOnTarget( CBaseEntity *pPlayer )
{
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
{
if (m_ActivePlayers[i].Get() == pPlayer)
{
if (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME)
return true;
// Remove this player since it's no longer valid
m_ActivePlayers.Remove( i );
m_ActivePlayerTimes.Remove( i );
return false;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::RemoveTarget( CBaseEntity *pPlayer )
{
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
{
if (m_ActivePlayers[i].Get() == pPlayer)
{
m_ActivePlayers.Remove( i );
m_ActivePlayerTimes.Remove( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::InputShowMenu( inputdata_t &inputdata )
{
if (HasSpawnFlags( SF_GAMEMENU_ALLPLAYERS ))
{
CRecipientFilter filter;
filter.AddAllPlayers();
ShowMenu( filter );
}
else
{
CBasePlayer *pPlayer = NULL;
// If we're in singleplayer, show the message to the player.
if ( gpGlobals->maxClients == 1 )
{
pPlayer = UTIL_GetLocalPlayer();
}
// Otherwise show the message to the player that triggered us.
else if ( inputdata.pActivator && inputdata.pActivator->IsNetClient() )
{
pPlayer = ToBasePlayer( inputdata.pActivator );
}
if (pPlayer)
{
CRecipientFilter filter;
filter.AddRecipient( pPlayer );
ShowMenu( filter );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMenu::InputHideMenu( inputdata_t &inputdata )
{
if (HasSpawnFlags( SF_GAMEMENU_ALLPLAYERS ))
{
CRecipientFilter filter;
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
{
// Select all players in our list who are still active, and remove them
if (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME)
{
filter.AddRecipient( static_cast<CBasePlayer*>(m_ActivePlayers[i].Get()) );
}
m_ActivePlayers.Remove( i );
m_ActivePlayerTimes.Remove( i );
}
if (filter.GetRecipientCount() <= 0)
return;
HideMenu( filter );
}
else
{
CBasePlayer *pPlayer = NULL;
// If we're in singleplayer, show the message to the player.
if ( gpGlobals->maxClients == 1 )
{
pPlayer = UTIL_GetLocalPlayer();
}
// Otherwise show the message to the player that triggered us.
else if ( inputdata.pActivator && inputdata.pActivator->IsNetClient() )
{
pPlayer = ToBasePlayer( inputdata.pActivator );
}
if (!pPlayer)
return;
// Verify that this player is in our list
CRecipientFilter filter;
FOR_EACH_VEC( m_ActivePlayers, i )
{
if (m_ActivePlayers[i].Get() == pPlayer && (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME))
{
filter.AddRecipient( pPlayer );
// Remove since the player won't have the menu anymore
m_ActivePlayers.Remove( i );
m_ActivePlayerTimes.Remove( i );
break;
}
}
if (filter.GetRecipientCount() <= 0)
return;
HideMenu( filter );
}
}
#endif

View File

@ -9,7 +9,55 @@
#ifndef MAPRULES_H
#define MAPRULES_H
#ifdef MAPBASE
#define MAX_MENU_OPTIONS 10
#define SF_GAMEMENU_ALLPLAYERS 0x0001
//-----------------------------------------------------------------------------
// Purpose: Displays a custom number menu for player(s)
//-----------------------------------------------------------------------------
DECLARE_AUTO_LIST( IGameMenuAutoList );
class CGameMenu : public CLogicalEntity, public IGameMenuAutoList
{
public:
DECLARE_CLASS( CGameMenu, CLogicalEntity );
DECLARE_DATADESC();
CGameMenu();
void OnRestore();
void InputDoRestore( inputdata_t &inputdata );
void TimeoutThink();
void ShowMenu( CRecipientFilter &filter, float flDisplayTime = 0.0f );
void HideMenu( CRecipientFilter &filter );
void MenuSelected( int nSlot, CBaseEntity *pActivator );
bool IsActive();
bool IsActiveOnTarget( CBaseEntity *pPlayer );
void RemoveTarget( CBaseEntity *pPlayer );
// Inputs
void InputShowMenu( inputdata_t &inputdata );
void InputHideMenu( inputdata_t &inputdata );
private:
CUtlVector<EHANDLE> m_ActivePlayers;
CUtlVector<float> m_ActivePlayerTimes;
float m_flDisplayTime;
string_t m_iszTitle;
string_t m_iszOption[MAX_MENU_OPTIONS];
// Outputs
COutputEvent m_OnCase[MAX_MENU_OPTIONS]; // Fired for the option chosen
COutputInt m_OutValue; // Outputs the option chosen
COutputEvent m_OnTimeout; // Fires when no option was chosen in time
};
#endif
#endif // MAPRULES_H

View File

@ -22,6 +22,7 @@
#include "hierarchy.h"
#ifdef MAPBASE
#include "decals.h"
#include "death_pose.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
@ -29,6 +30,7 @@
#ifdef MAPBASE
ConVar ragdoll_autointeractions("ragdoll_autointeractions", "1", FCVAR_NONE, "Controls whether we should rely on hardcoded keyvalues or automatic flesh checks for ragdoll physgun interactions.");
ConVar ai_death_pose_server_enabled("ai_death_pose_server_enabled", "1", FCVAR_NONE, "Toggles the death pose fix code, but for server ragdolls.");
#define IsBody() VPhysicsIsFlesh()
ConVar ragdoll_always_allow_use( "ragdoll_always_allow_use", "0", FCVAR_NONE, "Allows all ragdolls to be used and, if they aren't explicitly set to prevent pickup, picked up." );
@ -788,7 +790,11 @@ void CRagdollProp::SetOverlaySequence( Activity activity )
}
}
#ifdef MAPBASE
void CRagdollProp::InitRagdoll( const Vector& forceVector, int forceBone, const Vector& forcePos, matrix3x4_t* pPrevBones, matrix3x4_t* pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll, bool bDeathPose )
#else
void CRagdollProp::InitRagdoll( const Vector &forceVector, int forceBone, const Vector &forcePos, matrix3x4_t *pPrevBones, matrix3x4_t *pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll )
#endif
{
SetCollisionGroup( collisionGroup );
@ -811,7 +817,11 @@ void CRagdollProp::InitRagdoll( const Vector &forceVector, int forceBone, const
params.forceVector = forceVector;
params.forceBoneIndex = forceBone;
params.forcePosition = forcePos;
#ifdef MAPBASE
params.pCurrentBones = bDeathPose ? pPrevBones : pBoneToWorld;
#else
params.pCurrentBones = pBoneToWorld;
#endif
params.jointFrictionScale = 1.0;
params.allowStretch = HasSpawnFlags(SF_RAGDOLLPROP_ALLOW_STRETCH);
#ifdef MAPBASE
@ -1492,6 +1502,43 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con
float fPreviousCycle = clamp(pAnimating->GetCycle()-( dt * ( 1 / fSequenceDuration ) ),0.f,1.f);
float fCurCycle = pAnimating->GetCycle();
#ifdef MAPBASE
int deathpose = ACT_INVALID;
int deathframe = 0;
if (ai_death_pose_server_enabled.GetBool() && pAnimating->IsNPC()) {
CAI_BaseNPC* npc = (CAI_BaseNPC*)pAnimating;
if (npc) {
deathpose = Activity(npc->GetDeathPose());
deathframe = npc->GetDeathPoseFrame();
}
}
if (deathpose != ACT_INVALID) {
int currentSequence = pAnimating->GetSequence();
//Force pAnimating to position the deathpose
pAnimating->SetSequence(deathpose);
pAnimating->SetCycle((float)deathframe / MAX_DEATHPOSE_FRAMES);
//Store the position
pAnimating->SetupBones(pBoneToWorldNext, BONE_USED_BY_ANYTHING);
//Restore the current sequence and cycle
pAnimating->SetSequence(currentSequence);
pAnimating->SetCycle(fCurCycle);
pAnimating->SetupBones(pBoneToWorld, BONE_USED_BY_ANYTHING);
}
else {
// Get current bones positions
pAnimating->SetupBones(pBoneToWorldNext, BONE_USED_BY_ANYTHING);
// Get previous bones positions
pAnimating->SetCycle(fPreviousCycle);
pAnimating->SetupBones(pBoneToWorld, BONE_USED_BY_ANYTHING);
// Restore current cycle
pAnimating->SetCycle(fCurCycle);
}
#else
// Get current bones positions
pAnimating->SetupBones( pBoneToWorldNext, BONE_USED_BY_ANYTHING );
// Get previous bones positions
@ -1499,6 +1546,7 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con
pAnimating->SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING );
// Restore current cycle
pAnimating->SetCycle( fCurCycle );
#endif
// Reset previous bone flags
pAnimating->ClearBoneCacheFlags( BCF_NO_ANIMATION_SKIP );
@ -1573,7 +1621,11 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con
}
else
{
#ifdef MAPBASE
pRagdoll->InitRagdoll(info.GetDamageForce(), forceBone, info.GetDamagePosition(), pBoneToWorld, pBoneToWorldNext, dt, collisionGroup, true, true, deathpose != ACT_INVALID);
#else
pRagdoll->InitRagdoll( info.GetDamageForce(), forceBone, info.GetDamagePosition(), pBoneToWorld, pBoneToWorldNext, dt, collisionGroup, true );
#endif
}
// Are we dissolving?

View File

@ -75,7 +75,11 @@ public:
// locals
void InitRagdollAnimation( void );
#ifdef MAPBASE
void InitRagdoll( const Vector& forceVector, int forceBone, const Vector& forcePos, matrix3x4_t* pPrevBones, matrix3x4_t* pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll = true, bool bDeathPose = false );
#else
void InitRagdoll( const Vector &forceVector, int forceBone, const Vector &forcePos, matrix3x4_t *pPrevBones, matrix3x4_t *pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll = true );
#endif
void RecheckCollisionFilter( void );
void SetDebrisThink();

View File

@ -48,6 +48,8 @@ $Project
$File "$SRCDIR\game\shared\mapbase\MapEdit.h"
$File "$SRCDIR\game\shared\mapbase\matchers.cpp"
$File "$SRCDIR\game\shared\mapbase\matchers.h"
$File "$SRCDIR\game\shared\mapbase\game_timer.cpp"
$File "$SRCDIR\game\shared\mapbase\game_timer.h"
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.h" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\vscript_singletons.cpp" [$MAPBASE_VSCRIPT]

View File

@ -60,10 +60,6 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
extern CServerGameDLL g_ServerGameDLL;
#ifdef MAPBASE_VSCRIPT
extern int vscript_debugger_port;
#endif
// #define VMPROFILE 1
#ifdef VMPROFILE
@ -3769,10 +3765,13 @@ REGISTER_SCRIPT_CONST_TABLE( Server )
g_pScriptVM->SetValue( "Constants", vConstantsTable );
#ifdef MAPBASE_VSCRIPT
if ( vscript_debugger_port )
if ( script_connect_debugger_on_mapspawn.GetInt() == 2 )
{
g_pScriptVM->ConnectDebugger( vscript_debugger_port, 10.0f );
}
else if ( script_connect_debugger_on_mapspawn.GetInt() != 0 )
{
g_pScriptVM->ConnectDebugger( vscript_debugger_port );
vscript_debugger_port = 0;
}
#endif
@ -3793,10 +3792,12 @@ REGISTER_SCRIPT_CONST_TABLE( Server )
GetWorldEntity()->RunVScripts();
#endif
#ifndef MAPBASE_VSCRIPT
if ( script_connect_debugger_on_mapspawn.GetBool() )
{
g_pScriptVM->ConnectDebugger();
}
#endif
VMPROF_SHOW( pszScriptLanguage, "virtual machine startup" );

View File

@ -1149,7 +1149,7 @@ WeaponClass_t CBaseCombatWeapon::WeaponClassFromString(const char *str)
return WEPCLASS_RIFLE;
else if (FStrEq(str, "WEPCLASS_SHOTGUN"))
return WEPCLASS_SHOTGUN;
else if (FStrEq(str, "WEPCLASS_HEAY"))
else if (FStrEq(str, "WEPCLASS_HEAVY"))
return WEPCLASS_HEAVY;
else if (FStrEq(str, "WEPCLASS_MELEE"))

View File

@ -29,6 +29,9 @@
#include "player_resource.h"
#include "tactical_mission.h"
#include "gamestats.h"
#ifdef MAPBASE
#include "maprules.h"
#endif
#endif
@ -621,6 +624,27 @@ bool CGameRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args )
{
if( GetVoiceGameMgr()->ClientCommand( static_cast<CBasePlayer*>(pEdict), args ) )
return true;
#ifdef MAPBASE
if ( FStrEq( args[0], "menuselect" ) )
{
if ( args.ArgC() >= 2 )
{
int slot = atoi( args[1] );
// See if this is from a game_menu
for ( int i = 0; i < IGameMenuAutoList::AutoList().Count(); i++ )
{
CGameMenu *pMenu = static_cast<CGameMenu*>( IGameMenuAutoList::AutoList()[i] );
if ( pMenu->IsActiveOnTarget( pEdict ) )
{
pMenu->MenuSelected( slot, pEdict );
return true;
}
}
}
}
#endif
}
return false;

View File

@ -0,0 +1,658 @@
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
//
// Purpose: Generic custom timer entity
//
// Author: Blixibon
//
//=============================================================================//
#include "cbase.h"
#include "game_timer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool IsInCommentaryMode( void );
ConVar sv_game_menu_default_warn_frac( "sv_game_menu_default_warn_frac", "0.25", FCVAR_REPLICATED );
LINK_ENTITY_TO_CLASS( game_timer, CGameTimer );
IMPLEMENT_NETWORKCLASS_ALIASED( GameTimer, DT_GameTimer )
BEGIN_NETWORK_TABLE_NOBASE( CGameTimer, DT_GameTimer )
#ifdef CLIENT_DLL
RecvPropBool( RECVINFO( m_bTimerPaused ) ),
RecvPropTime( RECVINFO( m_flTimerInitialLength ) ),
RecvPropTime( RECVINFO( m_flTimerMaxLength ) ),
RecvPropTime( RECVINFO( m_flTimeRemaining ) ),
RecvPropTime( RECVINFO( m_flTimerEndTime ) ),
RecvPropTime( RECVINFO( m_flWarnTime ) ),
RecvPropBool( RECVINFO( m_bIsDisabled ) ),
RecvPropBool( RECVINFO( m_bStartPaused ) ),
RecvPropBool( RECVINFO( m_bShowTimeRemaining ) ),
RecvPropInt( RECVINFO( m_nProgressBarMaxSegments ) ),
RecvPropInt( RECVINFO( m_nProgressBarOverride ) ),
RecvPropFloat( RECVINFO( m_flOverrideX ) ),
RecvPropFloat( RECVINFO( m_flOverrideY ) ),
RecvPropString( RECVINFO( m_szTimerCaption ) ),
RecvPropInt( RECVINFO( m_iTeamNum ) ),
#else
SendPropBool( SENDINFO( m_bTimerPaused ) ),
SendPropTime( SENDINFO( m_flTimerInitialLength ) ),
SendPropTime( SENDINFO( m_flTimerMaxLength ) ),
SendPropTime( SENDINFO( m_flTimeRemaining ) ),
SendPropTime( SENDINFO( m_flTimerEndTime ) ),
SendPropTime( SENDINFO( m_flWarnTime ) ),
SendPropBool( SENDINFO( m_bIsDisabled ) ),
SendPropBool( SENDINFO( m_bStartPaused ) ),
SendPropBool( SENDINFO( m_bShowTimeRemaining ) ),
SendPropInt( SENDINFO( m_nProgressBarMaxSegments ) ),
SendPropInt( SENDINFO( m_nProgressBarOverride ) ),
SendPropFloat( SENDINFO( m_flOverrideX ) ),
SendPropFloat( SENDINFO( m_flOverrideY ) ),
SendPropString( SENDINFO( m_szTimerCaption ) ),
SendPropInt( SENDINFO( m_iTeamNum ), TEAMNUM_NUM_BITS, 0 ),
#endif
END_NETWORK_TABLE()
#ifndef CLIENT_DLL
BEGIN_DATADESC( CGameTimer )
DEFINE_KEYFIELD( m_flTimerInitialLength, FIELD_FLOAT, "timer_length" ),
DEFINE_KEYFIELD( m_flTimerMaxLength, FIELD_FLOAT, "max_length" ),
DEFINE_KEYFIELD( m_flWarnTime, FIELD_FLOAT, "warn_time" ),
DEFINE_KEYFIELD( m_bIsDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_KEYFIELD( m_bStartPaused, FIELD_BOOLEAN, "start_paused" ),
DEFINE_KEYFIELD( m_bShowTimeRemaining, FIELD_BOOLEAN, "show_time_remaining" ),
DEFINE_KEYFIELD( m_bDisableOnFinish, FIELD_BOOLEAN, "disable_on_finish" ),
DEFINE_KEYFIELD( m_bShowInHUD, FIELD_BOOLEAN, "show_in_hud" ),
DEFINE_KEYFIELD( m_nProgressBarMaxSegments, FIELD_INTEGER, "progress_bar_max" ),
DEFINE_KEYFIELD( m_nProgressBarOverride, FIELD_INTEGER, "progress_bar_override" ),
DEFINE_KEYFIELD( m_flOverrideX, FIELD_FLOAT, "x" ),
DEFINE_KEYFIELD( m_flOverrideY, FIELD_FLOAT, "y" ),
DEFINE_AUTO_ARRAY( m_szTimerCaption, FIELD_CHARACTER ),
DEFINE_KEYFIELD( m_iszPlayerFilterName, FIELD_STRING, "PlayerFilter" ),
DEFINE_FIELD( m_hPlayerFilter, FIELD_EHANDLE ),
DEFINE_FIELD( m_flTimerEndTime, FIELD_TIME ),
DEFINE_FIELD( m_flTimeRemaining, FIELD_FLOAT ),
DEFINE_FIELD( m_bTimerPaused, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bStartedWarn, FIELD_BOOLEAN ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Pause", InputPause ),
DEFINE_INPUTFUNC( FIELD_VOID, "Resume", InputResume ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetTime", InputSetTime ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "AddTime", InputAddTime ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "RemoveTime", InputRemoveTime ),
DEFINE_INPUTFUNC( FIELD_VOID, "Restart", InputRestart ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetMaxTime", InputSetMaxTime ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetTimerCaption", InputSetTimerCaption ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetProgressBarMaxSegments", InputSetProgressBarMaxSegments ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetProgressBarOverride", InputSetProgressBarOverride ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetX", InputSetX ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetY", InputSetY ),
DEFINE_INPUTFUNC( FIELD_VOID, "GetTimeRemaining", InputGetTimeRemaining ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetPlayerFilter", InputSetPlayerFilter ),
DEFINE_OUTPUT( m_OnFinished, "OnFinished" ),
DEFINE_OUTPUT( m_OnPaused, "OnPaused" ),
DEFINE_OUTPUT( m_OnResumed, "OnResumed" ),
DEFINE_OUTPUT( m_OnWarned, "OnWarned" ),
DEFINE_OUTPUT( m_OnTick, "OnTick" ),
DEFINE_OUTPUT( m_OnGetTimeRemaining, "OnGetTimeRemaining" ),
DEFINE_THINKFUNC( TimerThink ),
END_DATADESC();
#endif
#ifdef CLIENT_DLL
IMPLEMENT_AUTO_LIST( IGameTimerAutoList );
#else
#define TIMER_THINK "GameTimerThink"
#endif
//-----------------------------------------------------------------------------
// Purpose: constructor
//-----------------------------------------------------------------------------
CGameTimer::CGameTimer( void )
{
m_bIsDisabled = true;
m_bTimerPaused = true;
m_flTimeRemaining = 0;
m_flTimerEndTime = 0;
m_flWarnTime = -1.0f;
m_bStartPaused = false;
m_bShowTimeRemaining = true;
m_flTimerInitialLength = 0;
m_flTimerMaxLength = 0;
m_nProgressBarMaxSegments = -1;
m_nProgressBarOverride = -1;
m_flOverrideX = m_flOverrideY = -1.0f;
#ifndef CLIENT_DLL
m_bDisableOnFinish = true;
m_bShowInHUD = true;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: destructor
//-----------------------------------------------------------------------------
CGameTimer::~CGameTimer( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::Spawn( void )
{
#ifndef CLIENT_DLL
if ( IsDisabled() ) // we need to get the data initialized before actually become disabled
{
m_bIsDisabled = false;
SetTimeRemaining( m_flTimerInitialLength );
m_bIsDisabled = true;
}
else
{
SetTimeRemaining( m_flTimerInitialLength );
if ( !m_bStartPaused )
ResumeTimer();
}
if ( m_iszPlayerFilterName != NULL_STRING )
{
m_hPlayerFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iszPlayerFilterName, this ));
}
#endif
BaseClass::Spawn();
}
#ifndef CLIENT_DLL
bool CGameTimer::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "timer_caption" ) )
{
Q_strncpy( m_szTimerCaption.GetForModify(), szValue, MAX_GAME_TIMER_CAPTION );
}
else
{
return BaseClass::KeyValue( szKeyName, szValue );
}
return true;
}
bool CGameTimer::GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen )
{
if ( FStrEq( szKeyName, "timer_caption" ) )
{
Q_snprintf( szValue, iMaxLen, "%s", m_szTimerCaption.Get() );
return true;
}
return BaseClass::GetKeyValue( szKeyName, szValue, iMaxLen );
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Gets the seconds left on the timer, paused or not.
//-----------------------------------------------------------------------------
float CGameTimer::GetTimeRemaining( void )
{
float flSecondsRemaining;
if ( m_bTimerPaused )
{
flSecondsRemaining = m_flTimeRemaining;
}
else
{
flSecondsRemaining = m_flTimerEndTime - gpGlobals->curtime;
}
if ( flSecondsRemaining < 0 )
{
flSecondsRemaining = 0.0f;
}
return flSecondsRemaining;
}
//-----------------------------------------------------------------------------
// Purpose: Gets the timer's warning time
//-----------------------------------------------------------------------------
float CGameTimer::GetWarnTime( void )
{
if ( m_flWarnTime < 0 )
{
// TODO: All of the default warning stuff is on the client!!!
return GetTimerMaxLength() * sv_game_menu_default_warn_frac.GetFloat();
}
return m_flWarnTime;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CGameTimer::GetTimerMaxLength( void )
{
if ( m_flTimerMaxLength )
return m_flTimerMaxLength;
return m_flTimerInitialLength;
}
#ifdef CLIENT_DLL
bool g_bAnyGameTimerActive = false;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_GameTimer::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( !m_bIsDisabled )
{
g_bAnyGameTimerActive = true;
}
else if ( !m_bOldDisabled )
{
// Go through all of the timers and mark when one is active
g_bAnyGameTimerActive = false;
for ( int i = 0; i < IGameTimerAutoList::AutoList().Count(); i++ )
{
C_GameTimer *pTimer = static_cast<C_GameTimer *>( IGameTimerAutoList::AutoList()[i] );
if ( !pTimer->IsDisabled() && !pTimer->IsMarkedForDeletion() )
{
g_bAnyGameTimerActive = true;
break;
}
}
}
m_bOldDisabled = m_bIsDisabled;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_GameTimer::UpdateOnRemove( void )
{
BaseClass::UpdateOnRemove();
// Update timer presence state
g_bAnyGameTimerActive = false;
for ( int i = 0; i < IGameTimerAutoList::AutoList().Count(); i++ )
{
C_GameTimer *pTimer = static_cast<C_GameTimer *>( IGameTimerAutoList::AutoList()[i] );
if ( pTimer != this && !pTimer->IsDisabled() && !pTimer->IsMarkedForDeletion() )
{
g_bAnyGameTimerActive = true;
break;
}
}
}
#else
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::TimerThink( void )
{
if ( IsDisabled() /*|| IsInCommentaryMode() || gpGlobals->eLoadType == MapLoad_Background*/ )
{
SetContextThink( &CGameTimer::TimerThink, gpGlobals->curtime + 0.05, TIMER_THINK );
return;
}
float flTime = GetTimeRemaining();
int nTick = (int)floorf( flTime );
if (nTick != m_OnTick.Get())
{
m_OnTick.Set( nTick, this, this );
}
if ( flTime <= 0.0f )
{
OnTimerFinished();
PauseTimer();
if (m_bDisableOnFinish)
m_bIsDisabled = true;
return;
}
else if ( flTime <= GetWarnTime() && !m_bStartedWarn)
{
OnTimerWarned();
m_bStartedWarn = true;
}
SetContextThink( &CGameTimer::TimerThink, gpGlobals->curtime + 0.05, TIMER_THINK );
}
//-----------------------------------------------------------------------------
// Purpose: To set the initial timer duration
//-----------------------------------------------------------------------------
void CGameTimer::SetTimeRemaining( float flTime )
{
// make sure we don't go over our max length
flTime = m_flTimerMaxLength > 0 ? MIN( flTime, m_flTimerMaxLength ) : flTime;
m_flTimeRemaining = flTime;
m_flTimerEndTime = gpGlobals->curtime + m_flTimeRemaining;
if ( m_flTimeRemaining > m_flWarnTime )
{
m_bStartedWarn = false;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::OnTimerFinished()
{
m_OnFinished.FireOutput( this, this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::OnTimerWarned()
{
m_OnWarned.FireOutput( this, this );
}
//-----------------------------------------------------------------------------
// Purpose: Timer is paused at round end, stops the countdown
//-----------------------------------------------------------------------------
void CGameTimer::PauseTimer( CBaseEntity *pActivator )
{
if ( IsDisabled() )
return;
if ( m_bTimerPaused == false )
{
m_bTimerPaused = true;
m_flTimeRemaining = m_flTimerEndTime - gpGlobals->curtime;
m_OnPaused.FireOutput( pActivator ? pActivator : this, this );
SetContextThink( NULL, TICK_NEVER_THINK, TIMER_THINK );
}
}
//-----------------------------------------------------------------------------
// Purpose: To start or re-start the timer after a pause
//-----------------------------------------------------------------------------
void CGameTimer::ResumeTimer( CBaseEntity *pActivator )
{
if ( IsDisabled() )
return;
if ( m_bTimerPaused == true )
{
m_bTimerPaused = false;
m_flTimerEndTime = gpGlobals->curtime + m_flTimeRemaining;
m_OnResumed.FireOutput( pActivator ? pActivator : this, this );
TimerThink();
SetContextThink( &CGameTimer::TimerThink, gpGlobals->curtime + 0.05, TIMER_THINK );
}
}
//-----------------------------------------------------------------------------
// Purpose: Add seconds to the timer while it is running or paused
//-----------------------------------------------------------------------------
void CGameTimer::AddTimerSeconds( float flTimeToAdd )
{
if ( IsDisabled() )
return;
if ( m_flTimerMaxLength > 0 )
{
// will adding this many seconds push us over our max length?
if ( GetTimeRemaining() + flTimeToAdd > m_flTimerMaxLength)
{
// adjust to only add up to our max length
flTimeToAdd = m_flTimerMaxLength - GetTimeRemaining();
}
}
if ( m_bTimerPaused )
{
m_flTimeRemaining += flTimeToAdd;
}
else
{
m_flTimerEndTime += flTimeToAdd;
}
}
//-----------------------------------------------------------------------------
// Purpose: Should we transmit it to the client?
//-----------------------------------------------------------------------------
int CGameTimer::UpdateTransmitState()
{
if ( !m_bShowInHUD )
{
return SetTransmitState( FL_EDICT_DONTSEND );
}
if ( m_hPlayerFilter || GetTeamNumber() > TEAM_UNASSIGNED )
{
return SetTransmitState( FL_EDICT_FULLCHECK );
}
return SetTransmitState( FL_EDICT_ALWAYS );
}
//-----------------------------------------------------------------------------
// Purpose: Which clients should we be transmitting to?
//-----------------------------------------------------------------------------
int CGameTimer::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
int result = BaseClass::ShouldTransmit( pInfo );
if ( result != FL_EDICT_DONTSEND )
{
CBaseEntity *pClient = (CBaseEntity *)(pInfo->m_pClientEnt->GetUnknown());
if ( pClient )
{
if ( m_hPlayerFilter )
{
// Don't send to players who don't pass our filter
if ( !m_hPlayerFilter->PassesFilter( this, pClient ) )
return FL_EDICT_DONTSEND;
}
else if ( GetTeamNumber() > TEAM_UNASSIGNED )
{
// If we don't have an explicit filter, then just check if it's on the same team as us
if ( pClient->GetTeamNumber() != GetTeamNumber() )
return FL_EDICT_DONTSEND;
}
return FL_EDICT_ALWAYS;
}
}
return result;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputPause( inputdata_t &input )
{
PauseTimer( input.pActivator );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputResume( inputdata_t &input )
{
ResumeTimer( input.pActivator );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputSetTime( inputdata_t &input )
{
float flTime = input.value.Float();
SetTimeRemaining( flTime );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputAddTime( inputdata_t &input )
{
float flTime = input.value.Float();
AddTimerSeconds( flTime );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputRemoveTime( inputdata_t &input )
{
float flTime = input.value.Float();
AddTimerSeconds( -flTime );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputSetMaxTime( inputdata_t &input )
{
float flTime = input.value.Float();
m_flTimerMaxLength = flTime;
if (m_flTimerMaxLength > 0)
{
// make sure our current time is not above the max length
if (GetTimeRemaining() > m_flTimerMaxLength)
{
SetTimeRemaining( m_flTimerMaxLength );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputSetTimerCaption( inputdata_t &input )
{
Q_strncpy( m_szTimerCaption.GetForModify(), input.value.String(), MAX_GAME_TIMER_CAPTION );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputSetProgressBarMaxSegments( inputdata_t &input )
{
m_nProgressBarMaxSegments = input.value.Int();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputSetProgressBarOverride( inputdata_t &input )
{
m_nProgressBarOverride = input.value.Int();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputSetX( inputdata_t &input )
{
m_flOverrideX = input.value.Float();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputSetY( inputdata_t &input )
{
m_flOverrideY = input.value.Float();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputRestart( inputdata_t &input )
{
SetTimeRemaining( m_flTimerInitialLength );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputGetTimeRemaining( inputdata_t &input )
{
m_OnGetTimeRemaining.Set( GetTimeRemaining(), input.pActivator, this);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputEnable( inputdata_t &input )
{
if (GetTimeRemaining() == 0.0f)
SetTimeRemaining( m_flTimerInitialLength );
m_bIsDisabled = false;
if ( !m_bStartPaused )
ResumeTimer( input.pActivator );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputDisable( inputdata_t &input )
{
PauseTimer( input.pActivator );
m_bIsDisabled = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameTimer::InputSetPlayerFilter( inputdata_t &inputdata )
{
m_iszPlayerFilterName = inputdata.value.StringID();
if ( m_iszPlayerFilterName != NULL_STRING )
{
m_hPlayerFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iszPlayerFilterName, this ));
}
else
{
m_hPlayerFilter = NULL;
}
}
#endif

View File

@ -0,0 +1,145 @@
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
//
// Purpose: Generic custom timer entity
//
// Author: Blixibon
//
//=============================================================================//
#include "cbase.h"
#ifdef CLIENT_DLL
#include "c_baseentity.h"
#else
#include "filters.h"
#endif
#ifdef CLIENT_DLL
DECLARE_AUTO_LIST( IGameTimerAutoList );
#define CGameTimer C_GameTimer
#endif
#define MAX_GAME_TIMER_CAPTION 32
//-----------------------------------------------------------------------------
// Purpose: Displays a custom timer
//-----------------------------------------------------------------------------
class CGameTimer : public CBaseEntity
#ifdef CLIENT_DLL
, public IGameTimerAutoList
#endif
{
public:
DECLARE_CLASS( CGameTimer, CBaseEntity );
DECLARE_NETWORKCLASS();
#ifndef CLIENT_DLL
DECLARE_DATADESC();
#endif
CGameTimer();
~CGameTimer();
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
void Spawn();
#ifndef CLIENT_DLL
bool KeyValue( const char *szKeyName, const char *szValue );
virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen );
#endif
// Based on teamplay_round_timer
virtual float GetTimeRemaining( void );
virtual float GetTimerMaxLength( void );
virtual bool StartPaused( void ) { return m_bStartPaused; }
bool ShowTimeRemaining( void ) { return m_bShowTimeRemaining; }
float GetWarnTime( void );
const char *GetTimerCaption( void ) { return m_szTimerCaption.Get(); }
int GetProgressBarMaxSegments( void ) { return m_nProgressBarMaxSegments; }
int GetProgressBarOverride( void ) { return m_nProgressBarOverride; }
bool OverridesPosition( void ) { return m_flOverrideX != -1.0f || m_flOverrideY != -1.0f; }
void GetPositionOverride( float &flX, float &flY ) { flX = m_flOverrideX; flY = m_flOverrideY; }
bool IsDisabled( void ) { return m_bIsDisabled; }
bool IsTimerPaused( void ) { return m_bTimerPaused; }
#ifndef CLIENT_DLL
virtual void SetTimeRemaining( float flTime ); // Set the initial length of the timer
virtual void AddTimerSeconds( float flTimeToAdd ); // Add time to an already running ( or paused ) timer
virtual void OnTimerFinished();
virtual void OnTimerWarned();
virtual void PauseTimer( CBaseEntity *pActivator = NULL );
virtual void ResumeTimer( CBaseEntity *pActivator = NULL );
void SetProgressBarMaxSegments( int nSegments ) { m_nProgressBarMaxSegments = nSegments; }
void SetProgressBarOverride( int nSegments ) { m_nProgressBarOverride = nSegments; }
int UpdateTransmitState();
// Inputs
void InputEnable( inputdata_t &input );
void InputDisable( inputdata_t &input );
void InputPause( inputdata_t &input );
void InputResume( inputdata_t &input );
void InputSetTime( inputdata_t &input );
void InputAddTime( inputdata_t &input );
void InputRemoveTime( inputdata_t &input );
void InputRestart( inputdata_t &input );
void InputSetMaxTime( inputdata_t &input );
void InputSetTimerCaption( inputdata_t &input );
void InputSetProgressBarMaxSegments( inputdata_t &input );
void InputSetProgressBarOverride( inputdata_t &input );
void InputSetX( inputdata_t &input );
void InputSetY( inputdata_t &input );
void InputGetTimeRemaining( inputdata_t &input );
void InputSetPlayerFilter( inputdata_t &inputdata );
#endif
private:
#ifdef CLIENT_DLL
void OnDataChanged( DataUpdateType_t updateType );
void UpdateOnRemove( void );
#else
int ShouldTransmit( const CCheckTransmitInfo *pInfo );
void TimerThink( void );
#endif
private:
CNetworkVar( bool, m_bIsDisabled );
CNetworkVar( float, m_flTimerInitialLength );
CNetworkVar( float, m_flTimerMaxLength );
CNetworkVar( float, m_flTimerEndTime );
CNetworkVar( float, m_flTimeRemaining );
CNetworkVar( float, m_flWarnTime ); // Time at which timer turns red, starts ticking loudly, etc.
CNetworkVar( int, m_nProgressBarMaxSegments ); // Overrides maximum segments in progress bar if greater than -1
CNetworkVar( int, m_nProgressBarOverride ); // Overrides progress bar value if greater than -1
CNetworkVar( float, m_flOverrideX );
CNetworkVar( float, m_flOverrideY );
CNetworkVar( bool, m_bTimerPaused );
CNetworkVar( bool, m_bStartPaused );
CNetworkVar( bool, m_bShowTimeRemaining );
CNetworkString( m_szTimerCaption, MAX_GAME_TIMER_CAPTION );
#ifdef CLIENT_DLL
bool m_bOldDisabled;
#else
bool m_bStartedWarn;
bool m_bDisableOnFinish;
bool m_bShowInHUD; // TODO: ShowInHUD input? Would require client to know it shouldn't show the timer anymore
string_t m_iszPlayerFilterName;
CHandle<CBaseFilter> m_hPlayerFilter;
// Outputs
COutputEvent m_OnFinished;
COutputEvent m_OnPaused;
COutputEvent m_OnResumed;
COutputEvent m_OnWarned;
COutputInt m_OnTick;
COutputFloat m_OnGetTimeRemaining;
#endif
};

View File

@ -27,6 +27,9 @@
#include "datacache/imdlcache.h"
#ifdef CLIENT_DLL
#include "input.h"
#ifdef HL2MP
#include "c_hl2mp_player.h"
#endif
#endif
extern ConVar mp_facefronttime, mp_feetyawrate;
@ -76,6 +79,13 @@ extern ConVar mp_facefronttime;
CMapbasePlayerAnimState::CMapbasePlayerAnimState( CBasePlayer *pPlayer ): m_pPlayer( pPlayer )
{
if (pPlayer)
{
m_nPoseAimYaw = pPlayer->LookupPoseParameter( "aim_yaw" );
m_nPoseAimPitch = pPlayer->LookupPoseParameter( "aim_pitch" );
m_nPoseHeadPitch = pPlayer->LookupPoseParameter( "head_pitch" );
m_nPoseWeaponLower = pPlayer->LookupPoseParameter( "weapon_lower" );
}
};
//-----------------------------------------------------------------------------
@ -288,6 +298,14 @@ void CMapbasePlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr )
ComputeReloadSequence();
ComputeWeaponSwitchSequence();
ComputeRelaxSequence();
#if defined(HL2MP) && defined(CLIENT_DLL)
C_HL2MP_Player *pHL2MPPlayer = static_cast<C_HL2MP_Player*>(GetOuter());
if (pHL2MPPlayer)
{
pHL2MPPlayer->UpdateLookAt();
}
#endif
}
//-----------------------------------------------------------------------------
@ -343,6 +361,7 @@ void CMapbasePlayerAnimState::ClearAnimationState()
m_bReloading = false;
m_bWeaponSwitching = false;
m_bWeaponRelaxing = false;
m_flWeaponRelaxAmount = 0.0f;
m_bPlayingMisc = false;
m_flReloadBlendIn = 0.0f;
m_flReloadBlendOut = 0.0f;
@ -527,7 +546,7 @@ void CMapbasePlayerAnimState::ComputeRelaxSequence()
m_flWeaponRelaxAmount = clamp( m_flWeaponRelaxAmount, 0.0f, 1.0f );
GetOuter()->SetPoseParameter( GetOuter()->LookupPoseParameter( "weapon_lower" ), m_flWeaponRelaxAmount );
GetOuter()->SetPoseParameter( m_nPoseWeaponLower, m_flWeaponRelaxAmount );
/*int nPose = GetOuter()->LookupPoseParameter( "weapon_lower" );
if (nPose != -1)
@ -548,7 +567,7 @@ void CMapbasePlayerAnimState::ComputeRelaxSequence()
}
else if (bRelaxing)
{
GetOuter()->SetPoseParameter( GetOuter()->LookupPoseParameter( "weapon_lower" ), 1.0f );
GetOuter()->SetPoseParameter( m_nPoseWeaponLower, 1.0f );
}
/*bool bEnabled = m_bWeaponRelaxing;
@ -646,7 +665,7 @@ float CMapbasePlayerAnimState::SetOuterBodyYaw( float flValue )
{
float flAimPoseBlend = GetAimPoseBlend();
GetOuter()->SetPoseParameter( GetOuter()->LookupPoseParameter( "aim_yaw" ), flValue * flAimPoseBlend );
GetOuter()->SetPoseParameter( m_nPoseAimYaw, flValue * flAimPoseBlend );
return CBasePlayerAnimState::SetOuterBodyYaw( flValue * (1.0f - flAimPoseBlend) );
}
@ -667,7 +686,7 @@ void CMapbasePlayerAnimState::ComputePoseParam_BodyYaw( void )
void CMapbasePlayerAnimState::ComputePoseParam_BodyLookYaw( void )
{
// See if we even have a blender for pitch
int upper_body_yaw = GetOuter()->LookupPoseParameter( "aim_yaw" );
int upper_body_yaw = m_nPoseAimYaw;
if ( upper_body_yaw < 0 )
{
return;
@ -815,8 +834,10 @@ void CMapbasePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr
//float flAimPoseBlend = GetAimPoseBlend();
// See if we have a blender for pitch
GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch );
GetOuter()->SetPoseParameter( pStudioHdr, "head_pitch", flPitch );
if (m_nPoseAimPitch >= 0)
GetOuter()->SetPoseParameter( pStudioHdr, m_nPoseAimPitch, flPitch );
if (m_nPoseHeadPitch >= 0)
GetOuter()->SetPoseParameter( pStudioHdr, m_nPoseHeadPitch, flPitch );
//ComputePoseParam_HeadPitch( pStudioHdr );
}
@ -826,9 +847,6 @@ void CMapbasePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr
//-----------------------------------------------------------------------------
void CMapbasePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr )
{
// Get pitch from v_angle
int iHeadPitch = GetOuter()->LookupPoseParameter("head_pitch");
float flPitch = m_flEyePitch;
if ( flPitch > 180.0f )
@ -837,5 +855,5 @@ void CMapbasePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr
}
flPitch = clamp( flPitch, -90, 90 );
GetOuter()->SetPoseParameter( pStudioHdr, iHeadPitch, flPitch );
GetOuter()->SetPoseParameter( pStudioHdr, m_nPoseHeadPitch, flPitch );
}

View File

@ -119,6 +119,8 @@ private:
// until it completes.
int m_iFireSequence; // (For any sequences in the fire layer, including grenade throw).
float m_flFireCycle;
int m_nPoseAimYaw, m_nPoseAimPitch, m_nPoseHeadPitch, m_nPoseWeaponLower;
};
CMapbasePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer );

View File

@ -20,6 +20,8 @@ void HookMapbaseUserMessages( void )
{
// VScript
//HOOK_MESSAGE( ScriptMsg ); // Hooked in CNetMsgScriptHelper
//HOOK_MESSAGE( ShowMenuComplex ); // Hooked in CHudMenu
}
#endif
@ -28,6 +30,8 @@ void RegisterMapbaseUserMessages( void )
// VScript
usermessages->Register( "ScriptMsg", -1 ); // CNetMsgScriptHelper
usermessages->Register( "ShowMenuComplex", -1 ); // CHudMenu
#ifdef CLIENT_DLL
// TODO: Better placement?
HookMapbaseUserMessages();

View File

@ -176,11 +176,11 @@ void CProtagonistSystem::LoadProtagonistFile( const char *pszFile )
else if (FStrEq( pszSubKeyName, "team" ))
{
#ifdef HL2MP
if (FStrEq( pszSubKeyName, "combine" ))
if (FStrEq( pSubKey->GetString(), "combine" ))
{
pProtag->nTeam = TEAM_COMBINE;
}
else if (FStrEq( pszSubKeyName, "rebels" ))
else if (FStrEq( pSubKey->GetString(), "rebels" ))
{
pProtag->nTeam = TEAM_REBELS;
}
@ -188,7 +188,7 @@ void CProtagonistSystem::LoadProtagonistFile( const char *pszFile )
#endif
{
// Try to get a direct integer
pProtag->nTeam = atoi( pszSubKeyName );
pProtag->nTeam = atoi( pSubKey->GetString() );
}
}
#endif
@ -335,6 +335,12 @@ void CProtagonistSystem::PrecacheProtagonist( CBaseEntity *pSource, int nIdx )
ProtagonistData_t &pProtag = m_Protagonists[nIdx];
// Don't if it's already precached
if (pProtag.bPrecached)
return;
CBaseEntity::SetAllowPrecache( true );
// Playermodel
if (pProtag.pszPlayerModel)
{
@ -358,6 +364,16 @@ void CProtagonistSystem::PrecacheProtagonist( CBaseEntity *pSource, int nIdx )
pSource->PrecacheModel( pProtag.dictWpnData[i].pszVM );
}
}
CBaseEntity::SetAllowPrecache( false );
// Precache parents
FOR_EACH_VEC( pProtag.vecParents, i )
{
PrecacheProtagonist( pSource, pProtag.vecParents[i] );
}
pProtag.bPrecached = true;
#endif
}
@ -416,7 +432,6 @@ GetProtagParamBody( ResponseContexts, bool, GetProtagParamInner( ResponseConte
int nLast = V_strlen( pszContexts )-1;
if (pszContexts[nLast] == ',')
{
Msg( "Removing trailing comma from \"%s\"\n", pszContexts );
pszContexts[nLast] = '\0';
}
}
@ -681,6 +696,11 @@ void CProtagonistSystem::PrintProtagonistData()
if (pProtag.pszPlayerModel)
Msg( "\t\tPlayer model: \"%s\" (%i, %i)\n", pProtag.pszPlayerModel, pProtag.nPlayerSkin, pProtag.nPlayerBody );
#ifdef HL2MP
if ( pProtag.nTeam != TEAM_ANY )
Msg( "\t\tTeam: %i\n", pProtag.nTeam );
#endif
for (int j = 0; j < NUM_HAND_RIG_TYPES; j++)
{
extern const char *pHandRigs[NUM_HAND_RIG_TYPES];

View File

@ -61,6 +61,9 @@ private:
// Multiplayer
int nTeam = TEAM_ANY;
// Precached (used by system, not actual data)
bool bPrecached = false;
#endif
// Weapon Data

View File

@ -1244,17 +1244,20 @@ public:
return -1;
}
if ( pInfo->datatype == types::_VEC3 )
index /= 3;
unsigned int arraysize = pInfo->arraysize;
if ( index < 0 || (unsigned int)index >= pInfo->arraysize )
if ( pInfo->datatype == types::_VEC3 )
arraysize *= 3;
if ( index < 0 || (unsigned int)index >= arraysize )
return -1;
switch ( pInfo->datatype )
{
case types::_VEC3:
case types::_FLOAT:
return *(float*)((char*)pEnt + pInfo->GetOffset( index ));
case types::_VEC3:
return ((float*)((char*)pEnt + pInfo->GetOffset( index / 3 )))[ index % 3 ];
#ifdef GAME_DLL
case types::_DAR_FLOAT:
{
@ -1286,19 +1289,24 @@ public:
return;
}
if ( pInfo->datatype == types::_VEC3 )
index /= 3;
unsigned int arraysize = pInfo->arraysize;
if ( index < 0 || (unsigned int)index >= pInfo->arraysize )
if ( pInfo->datatype == types::_VEC3 )
arraysize *= 3;
if ( index < 0 || (unsigned int)index >= arraysize )
return;
switch ( pInfo->datatype )
{
case types::_VEC3:
case types::_FLOAT:
*(float*)((char*)pEnt + pInfo->GetOffset( index )) = value;
NetworkStateChanged( pEnt, pInfo->GetOffset( index ) );
break;
case types::_VEC3:
((float*)((char*)pEnt + pInfo->GetOffset( index / 3 )))[ index % 3 ] = value;
NetworkStateChanged( pEnt, pInfo->GetOffset( index / 3 ) );
break;
#ifdef GAME_DLL
case types::_DAR_FLOAT:
{
@ -5138,6 +5146,11 @@ bool CScriptConvarAccessor::Init()
AddBlockedConVar( "cl_allowdownload" );
AddBlockedConVar( "cl_allowupload" );
AddBlockedConVar( "cl_downloadfilter" );
#ifdef GAME_DLL
AddBlockedConVar( "script_connect_debugger_on_mapspawn" );
#else
AddBlockedConVar( "script_connect_debugger_on_mapspawn_client" );
#endif
return true;
}

View File

@ -64,7 +64,6 @@ private:
#ifdef MAPBASE_VSCRIPT
// This is to ensure a dependency exists between the vscript library and the game DLLs
extern int vscript_token;
extern int vscript_debugger_port;
int vscript_token_hack = vscript_token;
#endif
@ -454,27 +453,14 @@ CON_COMMAND( script_debug, "Connect the vscript VM to the script debugger" )
if ( !IsCommandIssuedByServerAdmin() )
return;
#ifdef MAPBASE_VSCRIPT
#ifdef GAME_DLL
int port = 1212;
#else
int port = 1213;
#endif
#endif
if ( !g_pScriptVM )
{
#ifdef MAPBASE_VSCRIPT
vscript_debugger_port = port;
CGMsg( 0, CON_GROUP_VSCRIPT, "VScript VM is not running, waiting for it to attach the debugger to port %d...\n", port );
#else
Log_Warning( LOG_VScript, "Scripting disabled or no server running\n" );
#endif
return;
}
#ifdef MAPBASE_VSCRIPT
g_pScriptVM->ConnectDebugger( port );
g_pScriptVM->ConnectDebugger( vscript_debugger_port );
#else
g_pScriptVM->ConnectDebugger();
#endif

View File

@ -191,6 +191,12 @@ class CBaseEntityScriptInstanceHelper : public IScriptInstanceHelper
extern CBaseEntityScriptInstanceHelper g_BaseEntityScriptInstanceHelper;
#ifdef MAPBASE_VSCRIPT
#ifdef GAME_DLL
const int vscript_debugger_port = 1212;
#else
const int vscript_debugger_port = 1213;
#endif
void RegisterSharedScriptConstants();
void RegisterSharedScriptFunctions();

View File

@ -811,8 +811,8 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar**
(params[info.m_nBlendModulateTexture]->IsTexture() );
bool hasNormalMapAlphaEnvmapMask = IS_FLAG_SET( MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK );
#ifdef PARALLAX_CORRECTED_CUBEMAPS
// Parallax cubemaps
bool hasParallaxCorrection = params[info.m_nEnvmapParallax]->GetIntValue() > 0;
// Parallax cubemaps. Check for envmap because if we don't, white splotchs can appear at certain viewing angles when mat_specular is 0.
bool hasParallaxCorrection = params[info.m_nEnvmap]->IsDefined() && params[info.m_nEnvmapParallax]->GetIntValue() > 0;
#endif
if ( hasFlashlight && !IsX360() )

View File

@ -229,6 +229,8 @@ union ScriptVariantTemporaryStorage_t
//---------------------------------------------------------
struct ScriptClassDesc_t;
struct ScriptFuncDescriptor_t
{
ScriptFuncDescriptor_t()
@ -237,11 +239,13 @@ struct ScriptFuncDescriptor_t
m_pszFunction = NULL;
m_ReturnType = FIELD_TYPEUNKNOWN;
m_pszDescription = NULL;
m_pScriptClassDesc = NULL;
}
const char *m_pszScriptName;
const char *m_pszFunction;
const char *m_pszDescription;
ScriptClassDesc_t *m_pScriptClassDesc;
ScriptDataType_t m_ReturnType;
CUtlVector<ScriptDataType_t> m_Parameters;
};
@ -751,7 +755,7 @@ public:
virtual void Shutdown() = 0;
#ifdef MAPBASE_VSCRIPT
virtual bool ConnectDebugger( int port = 0 ) = 0;
virtual bool ConnectDebugger( int port = 0, float timeout = 0.0f ) = 0;
#else
virtual bool ConnectDebugger() = 0;
#endif

View File

@ -61,7 +61,7 @@ FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNC_TYPE_DEDUCER );
FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNC_TYPE_DEDUCER );
#define ScriptInitMemberFuncDescriptor_( pDesc, class, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, (class *)(0), &class::func ); }
#define ScriptInitMemberFuncDescriptor_( pDesc, class, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, (class *)(0), &class::func ); (pDesc)->m_pScriptClassDesc = GetScriptDesc<class>(nullptr); }
#define ScriptInitFuncDescriptorNamed( pDesc, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, &func ); }
#define ScriptInitFuncDescriptor( pDesc, func ) ScriptInitFuncDescriptorNamed( pDesc, func, #func )

View File

@ -112,7 +112,11 @@ WIN32
===================================================================
*/
#ifdef MAPBASE
int numthreads = -(MAX_TOOL_THREADS + 1);
#else
int numthreads = -1;
#endif
CRITICAL_SECTION crit;
static int enter;
@ -133,19 +137,37 @@ void SetLowPriority()
SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS );
}
//Threads can be negative; if so, they will be subtracted from the total thread count.
void ThreadSetDefault (void)
{
SYSTEM_INFO info;
#ifdef MAPBASE
if (numthreads == -(MAX_TOOL_THREADS + 1)) // not set manually
#else
if (numthreads == -1) // not set manually
#endif
{
GetSystemInfo (&info);
numthreads = info.dwNumberOfProcessors;
if (numthreads < 1 || numthreads > 32)
#ifdef MAPBASE
if (numthreads > 32)
#else
if (numthreads < 1 ||numthreads > 32)
#endif
numthreads = 1;
}
#ifdef MAPBASE
if (numthreads <= 0)
{
GetSystemInfo(&info);
numthreads = info.dwNumberOfProcessors + numthreads;
if (numthreads <= 0)
Error("\nIncrease the number of threads! Threads: %i, they cannot be negative or 0.\n", numthreads);
}
#endif
Msg ("%i threads\n", numthreads);
}

View File

@ -16,7 +16,7 @@
#include "fgdlib/fgdlib.h"
#include "manifest.h"
#ifdef PARALLAX_CORRECTED_CUBEMAPS
#include "matrixinvert.h"
#include "mathlib/vmatrix.h"
#endif
#ifdef MAPBASE_VSCRIPT
#include "vscript_vbsp.h"
@ -1657,9 +1657,11 @@ ChunkFileResult_t CMapFile::LoadEntityCallback(CChunkFile *pFile, int nParam)
//
if (!strcmp("parallax_obb", pClassName))
{
matrix3x4_t obbMatrix, invObbMatrix;
SetIdentityMatrix(obbMatrix);
SetIdentityMatrix(invObbMatrix);
//Originally was matrix3x2. Now we use built-in functions to the engine instead of a custom invert matrix
VMatrix obbMatrix, invObbMatrix;
MatrixSetIdentity(obbMatrix);
MatrixSetIdentity(invObbMatrix);
// Get corner and its 3 edges (scaled, local x, y, and z axes)
mapbrush_t *brush = &mapbrushes[mapent->firstbrush];
@ -1714,13 +1716,15 @@ ChunkFileResult_t CMapFile::LoadEntityCallback(CChunkFile *pFile, int nParam)
x *= abs(DotProduct(diag, x));
// Build transformation matrix (what is needed to turn a [0,0,0] - [1,1,1] cube into this brush)
MatrixSetColumn(x, 0, obbMatrix);
MatrixSetColumn(y, 1, obbMatrix);
MatrixSetColumn(z, 2, obbMatrix);
MatrixSetColumn(corner, 3, obbMatrix);
//Originally was MatrixSetColum. Since we use VMatrix now, changed to obbMatrix
obbMatrix.SetForward(x);
obbMatrix.SetLeft(y);
obbMatrix.SetUp(z);
obbMatrix.SetTranslation(corner);
//find inverse (we need the world to local matrix, "transformationmatrix" is kind of a misnomer)
MatrixInversion(obbMatrix, invObbMatrix);
//Originally was MatrixInversion. This is now using the built in functions, not relying on MatrixInversion and matrixinvert.h anymore
MatrixInverseGeneral(obbMatrix, invObbMatrix);
break;
}

View File

@ -1,117 +0,0 @@
// By Jason Yu-Tseh Chi
// From http://chi3x10.wordpress.com/2008/05/28/calculate-matrix-inversion-in-c/
// Modified to work with valve's matrix_3x4_t
#include "mathlib\mathlib.h"
// Calculate the cofactor of element (row,col)
int GetMatrixMinor(float **src, float **dest, int row, int col, int order)
{
// Indicate which col and row is being copied to dest
int colCount = 0, rowCount = 0;
for (int i = 0; i < order; i++)
{
if (i != row)
{
colCount = 0;
for (int j = 0; j < order; j++)
{
// When j is not the element
if (j != col)
{
dest[rowCount][colCount] = src[i][j];
colCount++;
}
}
rowCount++;
}
}
return 1;
}
// Calculate the determinant recursively.
double CalcMatrixDeterminant(float **mat, int order)
{
// Order must be >= 0
// Stop the recursion when matrix is a single element
if (order == 1)
return mat[0][0];
// The determinant value
float det = 0;
// Allocate the cofactor matrix
float **minor;
minor = new float*[order - 1];
for (int i = 0; i<order - 1; i++)
minor[i] = new float[order - 1];
for (int i = 0; i < order; i++)
{
// Get minor of element (0,i)
GetMatrixMinor(mat, minor, 0, i, order);
// The recusion is here!
det += (i % 2 == 1 ? -1.0 : 1.0) * mat[0][i] * CalcMatrixDeterminant(minor, order - 1);
//det += pow( -1.0, i ) * mat[0][i] * CalcMatrixDeterminant( minor,order-1 );
}
// Release memory
for (int i = 0; i<order - 1; i++)
delete[] minor[i];
delete[] minor;
return det;
}
// Matrix inversion
void MatrixInversion(matrix3x4_t &in, matrix3x4_t &out)
{
float **A;
A = new float*[4];
for (int i = 0; i < 4; i++)
A[i] = new float[4];
int order = 4;
// Load in into A
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
A[i][j] = in[i][j];
}
}
A[3][0] = A[3][1] = A[3][2] = 0;
A[3][3] = 1;
// Get the determinant of a
double det = 1.0 / CalcMatrixDeterminant((float**)A, order);
// Memory allocation
float *temp = new float[(order - 1)*(order - 1)];
float **minor = new float*[order - 1];
for (int i = 0; i<order - 1; i++)
minor[i] = temp + (i*(order - 1));
for (int j = 0; j<order; j++)
{
for (int i = 0; i<order; i++)
{
// Get the co-factor (matrix) of A(j,i)
GetMatrixMinor((float**)A, minor, j, i, order);
out[i][j] = det*CalcMatrixDeterminant(minor, order - 1);
if ((i + j) % 2 == 1)
out[i][j] = -out[i][j];
}
}
// Release memory
for (int i = 0; i < 4; i++)
delete A[i];
delete A;
//delete [] minor[0];
delete[] temp;
delete[] minor;
}

View File

@ -65,6 +65,7 @@ bool g_NodrawTriggers = false;
bool g_DisableWaterLighting = false;
bool g_bAllowDetailCracks = false;
bool g_bNoVirtualMesh = false;
bool g_bNoHiddenManifestMaps = false;
#ifdef MAPBASE
bool g_bNoDefaultCubemaps = true;
bool g_bSkyboxCubemaps = false;
@ -1175,6 +1176,10 @@ int RunVBSP( int argc, char **argv )
{
EnableFullMinidumps( true );
}
else if ( !Q_stricmp( argv[i], "-nohiddenmaps" ) )
{
g_bNoHiddenManifestMaps = true;
}
else if ( !Q_stricmp( argv[i], "-embed" ) && i < argc - 1 )
{
V_MakeAbsolutePath( g_szEmbedDir, sizeof( g_szEmbedDir ), argv[++i], "." );
@ -1285,6 +1290,7 @@ int RunVBSP( int argc, char **argv )
CmdLib_Cleanup();
CmdLib_Exit( 1 );
}
#endif
else if (argv[i][0] == '-')
{
Warning("VBSP: Unknown option \"%s\"\n\n", argv[i]);
@ -1331,8 +1337,9 @@ int RunVBSP( int argc, char **argv )
Warning(
"Other options :\n"
" -novconfig : Don't bring up graphical UI on vproject errors.\n"
" -threads : Control the number of threads vbsp uses (defaults to the # of\n"
" processors on your machine).\n"
" -threads # : Control the number of threads vbsp uses (defaults to the #\n"
" or processors on your machine).\n"
" Threads can be negative; if so, they will be subtracted from the total thread count.\n"
" -verboseentities: If -v is on, this disables verbose output for submodels.\n"
" -noweld : Don't join face vertices together.\n"
" -nocsg : Don't chop out intersecting brush areas.\n"

View File

@ -2467,11 +2467,13 @@ int ParseCommandLine( int argc, char **argv, bool *onlydetail )
if ( ++i < argc )
{
numthreads = atoi (argv[i]);
#ifndef MAPBASE //Mapbase allows threads to be negative, go to ThreadSetDefault(void) in threads.cpp for a explanation.
if ( numthreads <= 0 )
{
Warning("Error: expected positive value after '-threads'\n" );
return -1;
}
#endif
}
else
{
@ -2871,8 +2873,9 @@ void PrintUsage( int argc, char **argv )
" -dump : Write debugging .txt files.\n"
" -dumpnormals : Write normals to debug files.\n"
" -dumptrace : Write ray-tracing environment to debug files.\n"
" -threads : Control the number of threads vbsp uses (defaults to the #\n"
" -threads # : Control the number of threads vrad uses (defaults to the #\n"
" or processors on your machine).\n"
" Threads can be negative; if so, they will be subtracted from the total thread count.\n"
" -lights <file> : Load a lights file in addition to lights.rad and the\n"
" level lights file.\n"
" -noextra : Disable supersampling.\n"

View File

@ -703,9 +703,13 @@ public:
if ( pVMT->LoadFromBuffer( pMaterialName, buf ) )
{
bFound = true;
if ( pVMT->FindKey("$translucent") || pVMT->FindKey("$alphatest") )
KeyValues *pBaseTexture = pVMT->FindKey("%alphatexture");
if ( pBaseTexture || pVMT->FindKey("$alphatest") || pVMT->FindKey("$translucent") )
{
KeyValues *pBaseTexture = pVMT->FindKey("$basetexture");
if ( !pBaseTexture )
{
pBaseTexture = pVMT->FindKey("$basetexture");
}
if ( pBaseTexture )
{
const char *pBaseTextureName = pBaseTexture->GetString();

View File

@ -1039,8 +1039,9 @@ void PrintUsage( int argc, char **argv )
#ifdef MPI
" -mpi_pw <pw> : Use a password to choose a specific set of VMPI workers.\n"
#endif
" -threads : Control the number of threads vbsp uses (defaults to the #\n"
" -threads # : Control the number of threads vvis uses (defaults to the #\n"
" or processors on your machine).\n"
" Threads can be negative; if so, they will be subtracted from the total thread count.\n"
" -nosort : Don't sort portals (sorting is an optimization).\n"
" -tmpin : Make portals come from \\tmp\\<mapname>.\n"
" -tmpout : Make portals come from \\tmp\\<mapname>.\n"

19
src/vscript/sqdbg/LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) samisalreadytaken
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -60,9 +60,14 @@ SQDBG_API int sqdbg_listen_socket( HSQDEBUGSERVER dbg, unsigned short port );
SQDBG_API void sqdbg_frame( HSQDEBUGSERVER dbg );
// Copies the script to be able to source it to debugger clients
SQDBG_API void sqdbg_on_script_compile( HSQDEBUGSERVER dbg, const SQChar *script, SQInteger size,
SQDBG_API void sqdbg_on_script_compile( HSQDEBUGSERVER dbg,
const SQChar *script, SQInteger scriptlen,
const SQChar *sourcename, SQInteger sourcenamelen );
// Check if a client is connected to the debugger
// Returns 0 if there is no client connected
SQDBG_API int sqdbg_is_client_connected( HSQDEBUGSERVER dbg );
#ifdef __cplusplus
}
#endif

View File

@ -106,6 +106,7 @@
} while(0)
#endif
#define Verify( x ) Assert(x)
#define STATIC_ASSERT( x ) static_assert( x, #x )
#else
#define DebuggerBreak() ((void)0)
#define Assert( x ) ((void)0)
@ -113,12 +114,15 @@
#define AssertMsg1( x, msg, a1 ) ((void)0)
#define AssertMsg2( x, msg, a1, a2 ) ((void)0)
#define Verify( x ) x
#define STATIC_ASSERT( x )
#endif // _DEBUG
#endif
#include <tier0/dbg.h>
#define STATIC_ASSERT COMPILE_TIME_ASSERT
// Misdefined for GCC in platform.h
#undef UNREACHABLE

View File

@ -62,12 +62,12 @@ class json_array_t
{
public:
const char *m_pBase;
CScratch< JSON_SCRATCH_CHUNK_SIZE > *m_Allocator;
CScratch< true, JSON_SCRATCH_CHUNK_SIZE > *m_Allocator;
int *m_Elements;
unsigned short m_nElementCount;
unsigned short m_nElementsSize;
void Init( const char *base, CScratch< JSON_SCRATCH_CHUNK_SIZE > *allocator )
void Init( const char *base, CScratch< true, JSON_SCRATCH_CHUNK_SIZE > *allocator )
{
m_pBase = base;
m_Allocator = allocator;
@ -96,7 +96,7 @@ public:
return ret;
}
int size() const
int Size() const
{
return m_nElementCount;
}
@ -138,12 +138,12 @@ class json_table_t
{
public:
const char *m_pBase;
CScratch< JSON_SCRATCH_CHUNK_SIZE > *m_Allocator;
CScratch< true, JSON_SCRATCH_CHUNK_SIZE > *m_Allocator;
int *m_Elements;
unsigned short m_nElementCount;
unsigned short m_nElementsSize;
void Init( const char *base, CScratch< JSON_SCRATCH_CHUNK_SIZE > *allocator )
void Init( const char *base, CScratch< true, JSON_SCRATCH_CHUNK_SIZE > *allocator )
{
m_pBase = base;
m_Allocator = allocator;
@ -266,11 +266,24 @@ public:
bool Get( const string_t &key, json_array_t **out ) const { return GetArray( key, out ); }
};
static inline void PutStrL( CBuffer *buffer, const string_t &str )
static inline void PutStr( CBuffer *buffer, const string_t &str )
{
buffer->_base.Ensure( buffer->size() + str.len );
memcpy( buffer->base() + buffer->size(), str.ptr, str.len );
buffer->_size += str.len;
buffer->base.Ensure( buffer->Size() + str.len );
memcpy( buffer->Base() + buffer->Size(), str.ptr, str.len );
buffer->size += str.len;
#ifdef SQDBG_VALIDATE_SENT_MSG
for ( unsigned int i = 0; i < str.len; i++ )
{
if ( str.ptr[i] == '\\' && ( str.ptr[i+1] == '\\' || str.ptr[i+1] == '\"' ) )
{
i++;
continue;
}
AssertMsg( str.ptr[i] != '\\' && IN_RANGE_CHAR( str.ptr[i], 0x20, 0x7E ), "control char in json string" );
}
#endif
}
static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
@ -278,7 +291,7 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
const char *c = str.ptr;
unsigned int i = str.len;
unsigned int len = 2 + i;
unsigned int len = i;
if ( quote )
len += 4;
@ -287,18 +300,19 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
{
switch ( *c )
{
case '\"': case '\\': case '\b':
case '\f': case '\n': case '\r': case '\t':
case '\\': case '\"':
case '\a': case '\b': case '\f':
case '\n': case '\r': case '\t': case '\v':
len++;
if ( quote )
{
len++;
if ( *c == '\"' || *c == '\\' )
if ( *c == '\\' || *c == '\"' )
len++;
}
break;
default:
if ( !IN_RANGE_CHAR( *(unsigned char*)c, 0x20, 0x7E ) )
if ( !IN_RANGE_CHAR( *c, 0x20, 0x7E ) )
{
int ret = IsValidUTF8( (unsigned char*)c, i + 1 );
if ( ret != 0 )
@ -321,16 +335,14 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
}
}
buffer->_base.Ensure( buffer->size() + len );
buffer->base.Ensure( buffer->Size() + len );
char *mem = buffer->base();
unsigned int idx = buffer->size();
char *mem = buffer->Base();
unsigned int idx = buffer->Size();
c = str.ptr;
i = str.len;
mem[idx++] = '\"';
if ( quote )
{
mem[idx++] = '\\';
@ -343,6 +355,7 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
switch ( *c )
{
case '\\':
case '\"':
mem[idx-1] = '\\';
if ( quote )
@ -350,15 +363,13 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
mem[idx++] = '\\';
mem[idx++] = '\\';
}
mem[idx++] = '\"';
mem[idx++] = *c;
break;
case '\\':
case '\a':
mem[idx-1] = '\\';
if ( quote )
{
mem[idx++] = '\\';
mem[idx++] = '\\';
}
mem[idx++] = '\\';
mem[idx++] = 'a';
break;
case '\b':
mem[idx-1] = '\\';
@ -390,8 +401,14 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
mem[idx++] = '\\';
mem[idx++] = 't';
break;
case '\v':
mem[idx-1] = '\\';
if ( quote )
mem[idx++] = '\\';
mem[idx++] = 'v';
break;
default:
if ( !IN_RANGE_CHAR( *(unsigned char*)c, 0x20, 0x7E ) )
if ( !IN_RANGE_CHAR( *c, 0x20, 0x7E ) )
{
int ret = IsValidUTF8( (unsigned char*)c, i + 1 );
if ( ret != 0 )
@ -410,7 +427,7 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
mem[idx++] = 'u';
idx += printhex< true, false >(
mem + idx,
buffer->capacity() - idx,
buffer->Capacity() - idx,
(uint16_t)*(unsigned char*)c );
}
else
@ -419,8 +436,8 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
mem[idx++] = 'x';
idx += printhex< true, false >(
mem + idx,
buffer->capacity() - idx,
(SQChar)*(unsigned char*)c );
buffer->Capacity() - idx,
(SQUnsignedChar)*(unsigned char*)c );
}
}
}
@ -433,9 +450,7 @@ static inline void PutStr( CBuffer *buffer, const string_t &str, bool quote )
mem[idx++] = '\"';
}
mem[idx++] = '\"';
buffer->_size = idx;
buffer->size = idx;
}
#ifdef SQUNICODE
@ -445,64 +460,127 @@ static inline void PutStr( CBuffer *buffer, const sqstring_t &str, bool quote )
if ( !quote )
{
len = 2 + UTF8Length< kUTFEscapeJSON >( str.ptr, str.len );
len = UTF8Length< kUTFEscapeJSON >( str.ptr, str.len );
}
else
{
len = 2 + UTF8Length< kUTFEscapeQuoted >( str.ptr, str.len );
len = UTF8Length< kUTFEscapeQuoted >( str.ptr, str.len );
}
buffer->_base.Ensure( buffer->size() + len );
buffer->base()[buffer->_size++] = '\"';
buffer->base.Ensure( buffer->Size() + len );
if ( !quote )
{
len = SQUnicodeToUTF8< kUTFEscapeJSON >(
buffer->base() + buffer->size(),
buffer->capacity() - buffer->size(),
buffer->Base() + buffer->Size(),
buffer->Capacity() - buffer->Size(),
str.ptr,
str.len );
}
else
{
len = SQUnicodeToUTF8< kUTFEscapeQuoted >(
buffer->base() + buffer->size(),
buffer->capacity() - buffer->size(),
buffer->Base() + buffer->Size(),
buffer->Capacity() - buffer->Size(),
str.ptr,
str.len );
}
buffer->_size += len;
buffer->base()[buffer->_size++] = '\"';
buffer->size += len;
}
#endif
static inline void PutChar( CBuffer *buffer, char c )
{
buffer->_base.Ensure( buffer->size() + 1 );
buffer->base()[buffer->_size++] = c;
buffer->base.Ensure( buffer->Size() + 1 );
buffer->Base()[buffer->size++] = c;
}
template < typename I >
static inline void PutInt( CBuffer *buffer, I val, bool hex = false )
static inline void PutInt( CBuffer *buffer, I val )
{
int len;
buffer->_base.Ensure( buffer->size() + countdigits( val ) + 1 );
if ( !hex )
{
len = printint( buffer->base() + buffer->size(), buffer->capacity() - buffer->size(), val );
}
else
{
len = printhex< false >( buffer->base() + buffer->size(), buffer->capacity() - buffer->size(), val );
}
buffer->_size += len;
buffer->base.Ensure( buffer->Size() + countdigits( val ) + 1 );
int len = printint( buffer->Base() + buffer->Size(), buffer->Capacity() - buffer->Size(), val );
buffer->size += len;
}
class wjson_table_t;
class wjson_array_t;
template < bool padding, typename I >
static inline void PutHex( CBuffer *buffer, I val )
{
STATIC_ASSERT( IS_UNSIGNED( I ) );
buffer->base.Ensure( buffer->Size() + countdigits<16>( val ) + 1 );
int len = printhex< padding >( buffer->Base() + buffer->Size(), buffer->Capacity() - buffer->Size(), val );
buffer->size += len;
}
struct jstringbuf_t
{
CBuffer *m_pBuffer;
jstringbuf_t( CBuffer *b ) : m_pBuffer(b)
{
::PutChar( m_pBuffer, '\"' );
}
~jstringbuf_t()
{
::PutChar( m_pBuffer, '\"' );
}
jstringbuf_t( const jstringbuf_t &src );
void Seek( int i )
{
m_pBuffer->size += i;
}
template < int SIZE >
void Puts( const char (&str)[SIZE] )
{
::PutStr( m_pBuffer, str );
}
void Puts( const conststring_t &str )
{
::PutStr( m_pBuffer, str );
}
void Puts( const string_t &str, bool quote = false )
{
::PutStr( m_pBuffer, str, quote );
}
#ifdef SQUNICODE
void Puts( const sqstring_t &str, bool quote = false )
{
::PutStr( m_pBuffer, str, quote );
}
#endif
void Put( char c )
{
::PutChar( m_pBuffer, c );
}
template < typename I >
void PutInt( I val )
{
::PutInt( m_pBuffer, val );
}
template < typename I >
void PutHex( I val, bool padding = true )
{
if ( padding )
{
::PutHex< true >( m_pBuffer, val );
}
else
{
::PutHex< false >( m_pBuffer, val );
}
}
};
class wjson_t
{
@ -542,7 +620,7 @@ public:
PutChar( m_pBuffer, ',' );
PutChar( m_pBuffer, '\"' );
PutStrL( m_pBuffer, key );
PutStr( m_pBuffer, key );
PutChar( m_pBuffer, '\"' );
PutChar( m_pBuffer, ':' );
}
@ -556,26 +634,53 @@ public:
void SetNull( const string_t &key )
{
PutKey( key );
PutStrL( m_pBuffer, "null" );
PutStr( m_pBuffer, "null" );
}
void SetBool( const string_t &key, bool val )
{
PutKey( key );
PutStrL( m_pBuffer, val ? string_t("true") : string_t("false") );
PutStr( m_pBuffer, val ? string_t("true") : string_t("false") );
}
jstringbuf_t SetStringAsBuf( const string_t &key )
{
PutKey( key );
return { m_pBuffer };
}
template < int SIZE >
void SetString( const string_t &key, const char (&val)[SIZE] )
{
PutKey( key );
PutChar( m_pBuffer, '\"' );
PutStr( m_pBuffer, val );
PutChar( m_pBuffer, '\"' );
}
void SetString( const string_t &key, const conststring_t &val )
{
PutKey( key );
PutChar( m_pBuffer, '\"' );
PutStr( m_pBuffer, val );
PutChar( m_pBuffer, '\"' );
}
void SetString( const string_t &key, const string_t &val, bool quote = false )
{
PutKey( key );
PutChar( m_pBuffer, '\"' );
PutStr( m_pBuffer, val, quote );
PutChar( m_pBuffer, '\"' );
}
#ifdef SQUNICODE
void SetString( const string_t &key, const sqstring_t &val, bool quote = false )
{
PutKey( key );
PutChar( m_pBuffer, '\"' );
PutStr( m_pBuffer, val, quote );
PutChar( m_pBuffer, '\"' );
}
#endif
@ -593,7 +698,14 @@ public:
PutKey( key );
PutChar( m_pBuffer, '\"' );
PutChar( m_pBuffer, '[' );
PutInt( m_pBuffer, val, hex );
if ( !hex )
{
PutInt( m_pBuffer, val );
}
else
{
PutHex< false >( m_pBuffer, cast_unsigned( I, val ) );
}
PutChar( m_pBuffer, ']' );
PutChar( m_pBuffer, '\"' );
}
@ -637,7 +749,7 @@ public:
wjson_array_t( const wjson_array_t &src );
int size()
int Size()
{
return m_nElementCount;
}
@ -665,7 +777,7 @@ public:
PutChar( m_pBuffer, ',' );
PutChar( m_pBuffer, '\"' );
PutStrL( m_pBuffer, val );
PutStr( m_pBuffer, val );
PutChar( m_pBuffer, '\"' );
}
};
@ -676,7 +788,7 @@ private:
char *m_cur;
char *m_end;
char *m_start;
CScratch< JSON_SCRATCH_CHUNK_SIZE > *m_Allocator;
CScratch< true, JSON_SCRATCH_CHUNK_SIZE > *m_Allocator;
char *m_error;
enum
@ -693,7 +805,7 @@ private:
};
public:
JSONParser( CScratch< JSON_SCRATCH_CHUNK_SIZE > *allocator, char *ptr, int len, json_table_t *pTable ) :
JSONParser( CScratch< true, JSON_SCRATCH_CHUNK_SIZE > *allocator, char *ptr, int len, json_table_t *pTable ) :
m_cur( ptr ),
m_end( ptr + len + 1 ),
m_start( ptr ),
@ -710,7 +822,7 @@ public:
}
else
{
SetError( "expected '%c', got '0x%02x' @ %i", '{', Char(type), Index() );
SetError( "expected '%c', got %s @ %i", '{', Char(type), Index() );
}
}
@ -725,12 +837,30 @@ private:
return m_cur - m_start;
}
unsigned char Char( char token )
char *Char( char token )
{
if ( token != Token_Error )
return (unsigned char)token;
char *buf;
return *(unsigned char*)m_cur;
if ( token == Token_Error )
token = *m_cur;
if ( IN_RANGE_CHAR( token, 0x20, 0x7E ) )
{
buf = m_Allocator->Alloc(4);
buf[0] = '\'';
buf[1] = token;
buf[2] = '\'';
buf[3] = 0;
}
else
{
buf = m_Allocator->Alloc(5);
int i = printhex< true, true, false >( buf, 5, (unsigned char)token );
Assert( i == 4 );
buf[i] = 0;
}
return buf;
}
void SetError( const char *fmt, ... )
@ -752,6 +882,24 @@ private:
m_error[len] = 0;
}
bool IsValue( char token )
{
switch ( token )
{
case Token_String:
case Token_Integer:
case Token_Float:
case Token_False:
case Token_True:
case Token_Null:
case Token_Table:
case Token_Array:
return true;
default:
return false;
}
}
char NextToken( string_t &token )
{
while ( m_cur < m_end )
@ -776,37 +924,37 @@ private:
return *m_cur++;
case 't':
if ( m_cur + 4 >= m_end ||
m_cur[1] != 'r' || m_cur[2] != 'u' || m_cur[3] != 'e' )
if ( m_cur + 4 < m_end &&
m_cur[1] == 'r' && m_cur[2] == 'u' && m_cur[3] == 'e' )
{
SetError( "expected %s @ %i", "\"true\"", Index() );
return Token_Error;
m_cur += 4;
return Token_True;
}
m_cur += 4;
return Token_True;
SetError( "expected %s @ %i", "\"true\"", Index() );
return Token_Error;
case 'f':
if ( m_cur + 5 >= m_end ||
m_cur[1] != 'a' || m_cur[2] != 'l' || m_cur[3] != 's' || m_cur[4] != 'e' )
if ( m_cur + 5 < m_end &&
m_cur[1] == 'a' && m_cur[2] == 'l' && m_cur[3] == 's' && m_cur[4] == 'e' )
{
SetError( "expected %s @ %i", "\"false\"", Index() );
return Token_Error;
m_cur += 5;
return Token_False;
}
m_cur += 5;
return Token_False;
SetError( "expected %s @ %i", "\"false\"", Index() );
return Token_Error;
case 'n':
if ( m_cur + 4 >= m_end ||
m_cur[1] != 'u' || m_cur[2] != 'l' || m_cur[3] != 'l' )
if ( m_cur + 4 < m_end &&
m_cur[1] == 'u' && m_cur[2] == 'l' && m_cur[3] == 'l' )
{
SetError( "expected %s @ %i", "\"null\"", Index() );
return Token_Error;
m_cur += 4;
return Token_Null;
}
m_cur += 4;
return Token_Null;
SetError( "expected %s @ %i", "\"null\"", Index() );
return Token_Error;
default:
return Token_Error;
@ -829,12 +977,10 @@ private:
return Token_Error;
}
// end
if ( *m_cur == '\"' )
{
*m_cur = 0;
token.Assign( pStart, m_cur - pStart );
m_cur++;
*m_cur++ = 0;
break;
}
@ -857,7 +1003,7 @@ private:
// Defer unescape until the end of the string is found
switch ( *m_cur )
{
case '\"': case '\\': case '/':
case '\\': case '\"': case '/':
case 'b': case 'f':
case 'n': case 'r': case 't':
m_cur++;
@ -876,7 +1022,7 @@ private:
break;
default:
SetError( "invalid escape char '0x%02x' @ %i", *(unsigned char*)m_cur, Index() );
SetError( "invalid escape char 0x%02x @ %i", *(unsigned char*)m_cur, Index() );
return Token_Error;
}
}
@ -895,6 +1041,7 @@ private:
}
#define _shift( bytesWritten, bytesRead ) \
Assert( (bytesWritten) < (bytesRead) ); \
memmove( cur + (bytesWritten), cur + (bytesRead), end - ( cur + (bytesRead) ) ); \
cur += (bytesWritten); \
end -= (bytesRead) - (bytesWritten);
@ -903,22 +1050,21 @@ private:
{
case '\\':
shift_one:
_shift( 0, 1 );
cur++;
_shift( 1, 2 );
break;
case '\"': goto shift_one;
case '/': goto shift_one;
case 'b': cur[1] = '\b'; goto shift_one;
case 'f': cur[1] = '\f'; goto shift_one;
case 'n': cur[1] = '\n'; goto shift_one;
case 'r': cur[1] = '\r'; goto shift_one;
case 't': cur[1] = '\t'; goto shift_one;
case '\"': cur[0] = '\"'; goto shift_one;
case '/': cur[0] = '/'; goto shift_one;
case 'b': cur[0] = '\b'; goto shift_one;
case 'f': cur[0] = '\f'; goto shift_one;
case 'n': cur[0] = '\n'; goto shift_one;
case 'r': cur[0] = '\r'; goto shift_one;
case 't': cur[0] = '\t'; goto shift_one;
case 'u':
{
unsigned int val;
Verify( atox( { cur + 2, 4 }, &val ) );
if ( val <= 0xFF )
if ( val <= 0x7F )
{
cur[0] = (char)val;
@ -993,7 +1139,7 @@ shift_one:
if ( m_cur >= m_end )
goto err_eof;
}
else if ( IN_RANGE_CHAR( *(unsigned char*)m_cur, '1', '9' ) )
else if ( IN_RANGE_CHAR( *m_cur, '1', '9' ) )
{
do
{
@ -1001,11 +1147,11 @@ shift_one:
if ( m_cur >= m_end )
goto err_eof;
}
while ( IN_RANGE_CHAR( *(unsigned char*)m_cur, '0', '9' ) );
while ( IN_RANGE_CHAR( *m_cur, '0', '9' ) );
}
else
{
SetError( "unexpected char '0x%02x' in number @ %i", *(unsigned char*)m_cur, Index() );
SetError( "unexpected char 0x%02x in number @ %i", *(unsigned char*)m_cur, Index() );
return Token_Error;
}
@ -1016,7 +1162,7 @@ shift_one:
type = Token_Float;
m_cur++;
while ( m_cur < m_end && IN_RANGE_CHAR( *(unsigned char*)m_cur, '0', '9' ) )
while ( m_cur < m_end && IN_RANGE_CHAR( *m_cur, '0', '9' ) )
m_cur++;
if ( m_cur >= m_end )
@ -1039,7 +1185,7 @@ shift_one:
goto err_eof;
}
while ( m_cur < m_end && IN_RANGE_CHAR( *(unsigned char*)m_cur, '0', '9' ) )
while ( m_cur < m_end && IN_RANGE_CHAR( *m_cur, '0', '9' ) )
m_cur++;
}
@ -1062,7 +1208,7 @@ err_eof:
{
if ( type != Token_String )
{
SetError( "expected %s, got '0x%02x' @ %i", "string", Char(type), Index() );
SetError( "expected '%c', got %s @ %i", '\"', Char(type), Index() );
return Token_Error;
}
@ -1070,7 +1216,7 @@ err_eof:
if ( type != ':' )
{
SetError( "expected '%c', got '0x%02x' @ %i", ':', Char(type), Index() );
SetError( "expected '%c', got %s @ %i", ':', Char(type), Index() );
return Token_Error;
}
@ -1083,9 +1229,9 @@ err_eof:
type = NextToken( token );
type = ParseValue( type, token, &kv->val );
if ( type == Token_Error )
if ( !IsValue( type ) )
{
SetError( "invalid token '0x%02x' @ %i", Char(type), Index() );
SetError( "invalid token %s @ %i", Char(type), Index() );
return Token_Error;
}
@ -1101,7 +1247,7 @@ err_eof:
}
else
{
SetError( "expected '%c', got '0x%02x' @ %i", '}', Char(type), Index() );
SetError( "expected '%c', got %s @ %i", '}', Char(type), Index() );
return Token_Error;
}
}
@ -1116,9 +1262,9 @@ err_eof:
for (;;)
{
if ( type == Token_Error )
if ( !IsValue( type ) )
{
SetError( "expected '%c', got '0x%02x' @ %i", ']', Char(type), Index() );
SetError( "expected '%c', got %s @ %i", ']', Char(type), Index() );
return Token_Error;
}
@ -1127,7 +1273,7 @@ err_eof:
if ( type == Token_Error )
{
SetError( "invalid token '0x%02x' @ %i", Char(type), Index() );
SetError( "invalid token %s @ %i", Char(type), Index() );
return Token_Error;
}
@ -1143,7 +1289,7 @@ err_eof:
}
else
{
SetError( "expected '%c', got '0x%02x' @ %i", ']', Char(type), Index() );
SetError( "expected '%c', got %s @ %i", ']', Char(type), Index() );
return Token_Error;
}
}
@ -1154,7 +1300,7 @@ err_eof:
switch ( type )
{
case Token_Integer:
if ( token.len > FMT_INT_LEN )
if ( token.len > FMT_UINT32_LEN + 1 )
{
SetError( "invalid integer literal @ %i", Index() );
return Token_Error;
@ -1192,7 +1338,7 @@ err_eof:
value->type = JSON_NULL;
return type;
default:
return type;
return Token_Error;
}
}
};

View File

@ -602,6 +602,9 @@ public:
bool Listen()
{
if ( m_ServerSocket == INVALID_SOCKET )
return false;
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
@ -839,7 +842,7 @@ public:
m_pRecvBufPtr( m_pRecvBuf ),
m_bWSAInit( false )
{
Assert( sizeof(m_pRecvBuf) <= ( 1 << ( sizeof(CMessagePool::message_t::len) * 8 ) ) );
STATIC_ASSERT( sizeof(m_pRecvBuf) <= ( 1 << ( sizeof(CMessagePool::message_t::len) * 8 ) ) );
}
};

View File

@ -12,10 +12,10 @@
inline void DAP_Serialise( CBuffer *buffer )
{
Assert( buffer->size() > 0 && buffer->size() < INT_MAX );
Assert( buffer->Size() > 0 && buffer->Size() < INT_MAX );
char *mem = buffer->base();
int contentSize = buffer->size() - DAP_HEADER_MAXSIZE;
char *mem = buffer->Base();
int contentSize = buffer->Size() - DAP_HEADER_MAXSIZE;
int digits = countdigits( contentSize );
int padding = FMT_UINT32_LEN - digits;
@ -31,8 +31,8 @@ inline void DAP_Serialise( CBuffer *buffer )
// add padding in the end to match
padding--;
digits++;
buffer->_base.Ensure( buffer->size() + 1 );
mem[buffer->_size++] = ' ';
buffer->base.Ensure( buffer->Size() + 1 );
mem[buffer->size++] = ' ';
}
memcpy( mem, DAP_HEADER_CONTENTLENGTH ": ", STRLEN(DAP_HEADER_CONTENTLENGTH ": ") );
@ -53,10 +53,10 @@ inline void DAP_Serialise( CBuffer *buffer )
inline void DAP_Free( CBuffer *buffer )
{
buffer->_size = 0;
buffer->size = 0;
}
static inline void ParseFieldName( const char *pMemEnd, char *pStart, int *len )
static inline int ParseFieldName( const char *pMemEnd, char *pStart )
{
char *c = pStart;
@ -65,56 +65,39 @@ static inline void ParseFieldName( const char *pMemEnd, char *pStart, int *len )
if ( IN_RANGE_CHAR( ((unsigned char*)c)[0], 0x20, 0x7E ) )
{
if ( c + 1 >= pMemEnd )
{
*len = -1;
return;
}
return -1;
if ( c[0] == ':' )
{
if ( c[1] == ' ' )
{
*len = c - pStart;
return;
}
return c - pStart;
*len = 0;
return;
return 0;
}
c++;
}
else
{
*len = 0;
return;
return 0;
}
}
}
static inline void ParseFieldValue( const char *pMemEnd, char *pStart, int *len )
static inline int ParseFieldValue( const char *pMemEnd, char *pStart )
{
char *c = pStart;
for (;;)
{
if ( c + 1 >= pMemEnd )
{
*len = -1;
return;
}
return -1;
if ( c[0] == '\n' )
{
*len = 0;
return;
}
return 0;
if ( c[0] == '\r' && c[1] == '\n' )
{
*len = c - pStart;
return;
}
return c - pStart;
c++;
}
@ -128,8 +111,7 @@ inline bool DAP_ReadHeader( char **ppMsg, int *pLength )
for (;;)
{
int len;
ParseFieldName( pMemEnd, pMsg, &len );
int len = ParseFieldName( pMemEnd, pMsg );
if ( len == 0 )
goto invalid;
@ -151,7 +133,7 @@ inline bool DAP_ReadHeader( char **ppMsg, int *pLength )
if ( pMsg >= pMemEnd )
return false;
if ( IN_RANGE_CHAR( *(unsigned char*)pMsg, '0', '9' ) )
if ( IN_RANGE_CHAR( *pMsg, '0', '9' ) )
{
nContentLength = nContentLength * 10 + *pMsg - '0';
pMsg++;
@ -187,7 +169,7 @@ inline bool DAP_ReadHeader( char **ppMsg, int *pLength )
ignore:
pMsg += len + 2;
ParseFieldValue( pMemEnd, pMsg, &len );
len = ParseFieldValue( pMemEnd, pMsg );
if ( len == 0 )
goto invalid;
@ -216,13 +198,13 @@ invalid:
}
#ifdef SQDBG_VALIDATE_SENT_MSG
inline void DAP_Test( CScratch< JSON_SCRATCH_CHUNK_SIZE > *scratch, CBuffer *buffer )
inline void DAP_Test( CScratch< true, JSON_SCRATCH_CHUNK_SIZE > *scratch, CBuffer *buffer )
{
char *pMsg = buffer->base();
int nLength = buffer->size();
char *pMsg = buffer->Base();
int nLength = buffer->Size();
bool res = DAP_ReadHeader( &pMsg, &nLength );
Assert( res && nLength < buffer->size() );
Assert( res && nLength < buffer->Size() );
if ( res )
{
@ -238,7 +220,7 @@ inline void DAP_Test( CScratch< JSON_SCRATCH_CHUNK_SIZE > *scratch, CBuffer *buf
#define _DAP_INIT_BUF( _buf ) \
CBufTmpCache _bufcache( (_buf) ); \
(_buf)->_size = DAP_HEADER_MAXSIZE; \
(_buf)->size = DAP_HEADER_MAXSIZE; \
(void)0
#define DAP_START_REQUEST( _seq, _cmd ) \
@ -262,10 +244,10 @@ if ( IsClientConnected() ) \
packet.SetBool( "success", _suc );
#define DAP_START_RESPONSE( _seq, _cmd ) \
_DAP_START_RESPONSE( _seq, _cmd, true );
_DAP_START_RESPONSE( _seq, _cmd, true )
#define DAP_ERROR_RESPONSE( _seq, _cmd ) \
_DAP_START_RESPONSE( _seq, _cmd, false );
_DAP_START_RESPONSE( _seq, _cmd, false )
#define DAP_ERROR_BODY( _id, _fmt ) \
wjson_table_t body = packet.SetTable( "body" ); \
@ -292,7 +274,7 @@ if ( IsClientConnected() ) \
} \
\
DAP_Serialise( &m_SendBuf ); \
Send( m_SendBuf.base(), m_SendBuf.size() ); \
Send( m_SendBuf.Base(), m_SendBuf.Size() ); \
DAP_Test( &m_ReadBuf, &m_SendBuf ); \
DAP_Free( &m_SendBuf ); \
}

File diff suppressed because it is too large Load Diff

View File

@ -75,13 +75,35 @@ bool atox( string_t str, I *out );
template < typename I >
bool atoo( string_t str, I *out );
template < typename I >
struct _as_unsigned { typedef I T; };
#ifdef SQUNICODE
void CopyString( const string_t &src, sqstring_t *dst );
void CopyString( const sqstring_t &src, string_t *dst );
template <>
struct _as_unsigned< int > { typedef unsigned int T; };
#ifdef _SQ64
template <>
struct _as_unsigned< SQInteger > { typedef SQUnsignedInteger T; };
#endif
template < typename T > void CopyString( const T &src, T *dst );
template < typename T > void FreeString( T *dst );
#define as_unsigned_type( I ) typename _as_unsigned<I>::T
#define cast_unsigned( I, v ) (as_unsigned_type(I)(v))
#define IS_UNSIGNED( I ) ((I)0 < (I)-1)
#define _isdigit( c ) \
IN_RANGE_CHAR( c, '0', '9' )
#define _isxdigit( c ) \
( IN_RANGE_CHAR( c, '0', '9' ) || \
IN_RANGE_CHAR( c, 'A', 'F' ) || \
IN_RANGE_CHAR( c, 'a', 'f' ) )
#define _isalpha( c ) \
( IN_RANGE_CHAR( c, 'A', 'Z' ) || IN_RANGE_CHAR( c, 'a', 'z' ) )
#define _isalnum( c ) \
( _isalpha(c) || _isdigit(c) )
#define IN_RANGE(c, min, max) \
((uint32_t)((uint32_t)(c) - (uint32_t)(min)) <= (uint32_t)((max)-(min)))
@ -249,51 +271,21 @@ struct string_t
}
#endif
template < int size >
string_t( const char (&src)[size] ) :
template < int SIZE >
string_t( const char (&src)[SIZE] ) :
ptr((char*)src),
len(size-1)
len(SIZE-1)
{
// input wasn't a string literal,
// call ( src, size ) constructor instead
Assert( strlen(src) == len );
}
void Strip()
template < int SIZE >
bool StartsWith( const char (&other)[SIZE] ) const
{
char *end = ptr + len;
for ( char *c = ptr; c < end; c++ )
{
if ( *c == ' ' || *c == '\t' || *c == '\n' )
{
ptr++;
len--;
}
else
{
break;
}
}
for ( char *c = end - 1; c >= ptr; c-- )
{
if ( *c == ' ' || *c == '\t' || *c == '\n' )
{
len--;
}
else
{
break;
}
}
}
template < int size >
bool StartsWith( const char (&other)[size] ) const
{
if ( size-1 <= len && *ptr == *other )
return !memcmp( ptr, other, size-1 );
if ( SIZE-1 <= len && *ptr == *other )
return !memcmp( ptr, other, SIZE-1 );
return false;
}
@ -306,11 +298,11 @@ struct string_t
return false;
}
template < int size >
bool IsEqualTo( const char (&other)[size] ) const
template < int SIZE >
bool IsEqualTo( const char (&other)[SIZE] ) const
{
if ( size-1 == len && *ptr == *other )
return !memcmp( ptr, other, size-1 );
if ( SIZE-1 == len && *ptr == *other )
return !memcmp( ptr, other, SIZE-1 );
return false;
}
@ -333,6 +325,14 @@ struct string_t
#ifdef SQUNICODE
bool IsEqualTo( const sqstring_t &other ) const;
#else
bool IsEqualTo( const SQString *other ) const
{
if ( (SQUnsignedInteger)len == (SQUnsignedInteger)other->_len && *ptr == *other->_val )
return !memcmp( ptr, other->_val, sq_rsl(len) );
return false;
}
#endif
bool IsEmpty() const
@ -345,11 +345,11 @@ struct string_t
return ( memchr( ptr, ch, len ) != NULL );
}
template < int size >
void Assign( const char (&src)[size] )
template < int SIZE >
void Assign( const char (&src)[SIZE] )
{
ptr = (char*)src;
len = size - 1;
len = SIZE - 1;
Assert( strlen(src) == len );
}
@ -373,6 +373,14 @@ private:
string_t &operator=( const char *src );
};
struct conststring_t : string_t
{
template < int SIZE >
conststring_t( const char (&src)[SIZE] ) : string_t(src) {}
conststring_t() {}
};
#ifdef SQUNICODE
struct sqstring_t
{
@ -393,10 +401,10 @@ struct sqstring_t
{
}
template < int size >
sqstring_t( const SQChar (&src)[size] ) :
template < int SIZE >
sqstring_t( const SQChar (&src)[SIZE] ) :
ptr((SQChar*)src),
len(size-1)
len(SIZE-1)
{
Assert( scstrlen(src) == len );
}
@ -410,9 +418,10 @@ struct sqstring_t
unsigned int i = 0;
do
{
if ( ptr[i] > 0x7E || other.ptr[i] != (char)ptr[i] )
if ( (SQUnsignedChar)ptr[i] > 0x7E || other.ptr[i] != (char)ptr[i] )
{
AssertMsg( ptr[i] <= 0x7E, "not implemented" );
// > 0x7E can be reached through completions request
// unicode identifiers are not supported, ignore them
return false;
}
}
@ -434,7 +443,7 @@ struct sqstring_t
bool IsEqualTo( const SQString *other ) const
{
if ( len == other->_len && *ptr == *other->_val )
if ( (SQUnsignedInteger)len == (SQUnsignedInteger)other->_len && *ptr == *other->_val )
return !memcmp( ptr, other->_val, sq_rsl(len) );
return false;
@ -445,11 +454,11 @@ struct sqstring_t
return !len;
}
template < int size >
void Assign( const SQChar (&src)[size] )
template < int SIZE >
void Assign( const SQChar (&src)[SIZE] )
{
ptr = (SQChar*)src;
len = size - 1;
len = SIZE - 1;
Assert( scstrlen(src) == len );
}
@ -471,12 +480,12 @@ struct stringbufbase_t
{
char *ptr;
unsigned int len;
const int size;
const unsigned int size;
stringbufbase_t( char *src, unsigned int size ) :
stringbufbase_t( char *src, unsigned int nSize ) :
ptr(src),
len(0),
size(size)
size(nSize)
{
}
@ -563,6 +572,8 @@ struct stringbufbase_t
template < typename I >
void PutHex( I value, bool padding = true )
{
STATIC_ASSERT( IS_UNSIGNED( I ) );
int space = BytesLeft();
if ( space < 3 )
@ -597,9 +608,9 @@ bool string_t::IsEqualTo( const sqstring_t &other ) const
{
// Used for comparing against locals and outers,
// implement unicode conversion if locals can have unicode characters
if ( other.ptr[i] > 0x7E || (char)other.ptr[i] != ptr[i] )
if ( (SQUnsignedChar)other.ptr[i] > 0x7E || (char)other.ptr[i] != ptr[i] )
{
AssertMsg( other.ptr[i] <= 0x7E, "not implemented" );
AssertMsg( (SQUnsignedChar)other.ptr[i] <= 0x7E, "not implemented" );
return false;
}
}
@ -622,20 +633,6 @@ struct stringbuf_t : stringbufbase_t
}
};
#define _isdigit( c ) \
IN_RANGE_CHAR(c, '0', '9')
#define _isxdigit( c ) \
( IN_RANGE_CHAR(c, '0', '9') || \
IN_RANGE_CHAR(c, 'A', 'F') || \
IN_RANGE_CHAR(c, 'a', 'f') )
#define _isalpha( c ) \
( IN_RANGE_CHAR(c, 'A', 'Z') || IN_RANGE_CHAR(c, 'a', 'z') )
#define _isalnum( c ) \
( _isalpha(c) || _isdigit(c) )
template < int BASE = 10, typename I >
inline int countdigits( I input )
{
@ -696,7 +693,7 @@ inline int printint( C *buf, int size, I value )
value /= 10;
buf[i--] = !neg ? ( '0' + c ) : ( '0' - c );
}
while ( value && i >= 0 );
while ( value );
return len;
}
@ -704,10 +701,11 @@ inline int printint( C *buf, int size, I value )
template < bool padding, bool prefix, bool uppercase, typename C, typename I >
inline int printhex( C *buf, int size, I value )
{
STATIC_ASSERT( IS_UNSIGNED( as_unsigned_type( I ) ) );
Assert( buf );
Assert( size > 0 );
int len = ( prefix ? 2 : 0 ) + ( padding ? sizeof(I) * 2 : countdigits<16>( value ) );
int len = ( prefix ? 2 : 0 ) + ( padding ? sizeof(I) * 2 : countdigits<16>( cast_unsigned( I, value ) ) );
if ( len > size )
len = size;
@ -716,11 +714,11 @@ inline int printhex( C *buf, int size, I value )
do
{
C c = value & 0xf;
value >>= 4;
C c = cast_unsigned( I, value ) & 0xf;
*(as_unsigned_type(I)*)&value >>= 4;
buf[i--] = c + ( ( c < 10 ) ? '0' : ( ( uppercase ? 'A' : 'a' ) - 10 ) );
}
while ( value && i >= 0 );
while ( value );
if ( padding )
{
@ -746,6 +744,7 @@ inline int printhex( C *buf, int size, I value )
template < typename C, typename I >
inline int printoct( C *buf, int size, I value )
{
STATIC_ASSERT( IS_UNSIGNED( I ) );
Assert( buf );
Assert( size > 0 );
@ -762,7 +761,7 @@ inline int printoct( C *buf, int size, I value )
value >>= 3;
buf[i--] = '0' + c;
}
while ( value && i >= 0 );
while ( value );
if ( i >= 0 )
buf[i--] = '0';
@ -789,7 +788,7 @@ inline bool atoi( string_t str, I *out )
{
unsigned char ch = *str.ptr;
if ( IN_RANGE_CHAR(ch, '0', '9') )
if ( IN_RANGE_CHAR( ch, '0', '9' ) )
{
val *= 10;
val += ch - '0';
@ -820,17 +819,17 @@ inline bool atox( string_t str, I *out )
{
unsigned char ch = *str.ptr;
if ( IN_RANGE_CHAR(ch, '0', '9') )
if ( IN_RANGE_CHAR( ch, '0', '9' ) )
{
val <<= 4;
val += ch - '0';
}
else if ( IN_RANGE_CHAR(ch, 'A', 'F') )
else if ( IN_RANGE_CHAR( ch, 'A', 'F' ) )
{
val <<= 4;
val += ch - 'A' + 10;
}
else if ( IN_RANGE_CHAR(ch, 'a', 'f') )
else if ( IN_RANGE_CHAR( ch, 'a', 'f' ) )
{
val <<= 4;
val += ch - 'a' + 10;
@ -855,7 +854,7 @@ inline bool atoo( string_t str, I *out )
{
unsigned char ch = *str.ptr;
if ( IN_RANGE_CHAR(ch, '0', '7') )
if ( IN_RANGE_CHAR( ch, '0', '7' ) )
{
val <<= 3;
val += ch - '0';
@ -898,7 +897,7 @@ inline int IsValidUTF8( unsigned char *src, unsigned int srclen )
return 0;
}
else if ( IN_RANGE_CHAR(cp, 0xC2, 0xF4) )
else if ( IN_RANGE_CHAR( cp, 0xC2, 0xF4 ) )
{
if ( UTF8_2_LEAD(cp) )
{
@ -938,7 +937,7 @@ inline int IsValidUTF8( unsigned char *src, unsigned int srclen )
if ( !UTF8_TRAIL(cp) )
{
if ( IN_RANGE_CHAR(cp, 0xC2, 0xF4) )
if ( IN_RANGE_CHAR( cp, 0xC2, 0xF4 ) )
goto check;
return 0;
@ -967,34 +966,8 @@ inline int IsValidUnicode( const SQChar *src, unsigned int srclen )
return 0;
}
else if ( cp <= 0xFF )
else if ( cp < 0xA0 )
{
if ( IN_RANGE(cp, 0xC2, 0xF4) )
{
if ( UTF8_2_LEAD(cp) )
{
if ( UTF8_2( srclen, cp, src ) )
{
return 2;
}
}
else if ( UTF8_3_LEAD(cp) )
{
if ( UTF8_3( srclen, cp, src ) )
{
return 3;
}
}
else if ( UTF8_4_LEAD(cp) )
{
if ( UTF8_4( srclen, cp, src ) )
{
return 4;
}
}
}
// else [0x7F, 0xC2) & (0xF4, 0xFF]
return 0;
}
@ -1041,18 +1014,21 @@ inline unsigned int UTF8ToSQUnicode( SQChar *dst, unsigned int destSize, const c
{
switch ( ((unsigned char*)src)[1] )
{
case '\"': cp = '\"'; src++; break;
case '\\': src++; break;
case '\"': cp = '\"'; src++; break;
case '\'': cp = '\''; src++; break;
case 'a': cp = '\a'; src++; break;
case 'b': cp = '\b'; src++; break;
case 'f': cp = '\f'; src++; break;
case 'n': cp = '\n'; src++; break;
case 'r': cp = '\r'; src++; break;
case 't': cp = '\t'; src++; break;
case 'v': cp = '\v'; src++; break;
case 'x':
{
if ( src + sizeof(SQChar) * 2 + 1 < end )
{
Verify( atox( { src + 2, sizeof(SQChar) * 2 }, &cp ) );
atox( { src + 2, sizeof(SQChar) * 2 }, &cp );
src += sizeof(SQChar) * 2 + 1;
}
@ -1062,7 +1038,7 @@ inline unsigned int UTF8ToSQUnicode( SQChar *dst, unsigned int destSize, const c
{
if ( src + sizeof(uint16_t) * 2 + 1 < end )
{
Verify( atox( { src + 2, sizeof(uint16_t) * 2 }, &cp ) );
atox( { src + 2, sizeof(uint16_t) * 2 }, &cp );
src += sizeof(uint16_t) * 2 + 1;
}
@ -1074,7 +1050,7 @@ inline unsigned int UTF8ToSQUnicode( SQChar *dst, unsigned int destSize, const c
goto xffff;
}
else if ( IN_RANGE(cp, 0xC2, 0xF4) )
else if ( IN_RANGE( cp, 0xC2, 0xF4 ) )
{
if ( UTF8_2_LEAD(cp) )
{
@ -1111,34 +1087,13 @@ inline unsigned int UTF8ToSQUnicode( SQChar *dst, unsigned int destSize, const c
goto xffff;
}
xffff:
#if WCHAR_SIZE == 4
xffff:
supplementary:
#endif
if ( dst )
{
if ( destSize >= sizeof(SQChar) )
{
*dst++ = cp;
destSize -= sizeof(SQChar);
count += 1;
}
else
{
// out of space
break;
}
}
else
{
count += 1;
}
continue;
#else // WCHAR_SIZE == 2
xffff:
if ( dst )
{
if ( destSize >= sizeof(SQChar) )
if ( sizeof(SQChar) <= destSize )
{
*dst++ = (SQChar)cp;
destSize -= sizeof(SQChar);
@ -1157,14 +1112,15 @@ xffff:
continue;
#if WCHAR_SIZE == 2
supplementary:
if ( dst )
{
if ( destSize > sizeof(SQChar) )
if ( sizeof(SQChar) * 2 <= destSize )
{
UTF16_SURROGATE_FROM_UTF32( dst, cp );
dst += 2;
destSize -= 2 * sizeof(SQChar);
destSize -= sizeof(SQChar) * 2;
count += 2;
}
else
@ -1241,6 +1197,7 @@ inline unsigned int SQUnicodeToUTF8( char *dst, unsigned int destSize, const SQC
switch ( cp )
{
case '\\':
case '\"':
if ( escape == kUTFEscapeQuoted )
{
@ -1248,16 +1205,15 @@ inline unsigned int SQUnicodeToUTF8( char *dst, unsigned int destSize, const SQC
mbc[bytes++] = '\\';
}
mbc[bytes++] = '\\';
mbc[bytes++] = '\"';
mbc[bytes++] = (unsigned char)cp;
goto write;
case '\\':
case '\a':
if ( escape == kUTFEscapeJSON )
goto doescape;
if ( escape == kUTFEscapeQuoted )
{
mbc[bytes++] = '\\';
mbc[bytes++] = '\\';
}
mbc[bytes++] = '\\';
mbc[bytes++] = '\\';
mbc[bytes++] = 'a';
goto write;
case '\b':
if ( escape == kUTFEscapeQuoted )
@ -1289,15 +1245,25 @@ inline unsigned int SQUnicodeToUTF8( char *dst, unsigned int destSize, const SQC
mbc[bytes++] = '\\';
mbc[bytes++] = 't';
goto write;
case '\v':
if ( escape == kUTFEscapeJSON )
goto doescape;
if ( escape == kUTFEscapeQuoted )
mbc[bytes++] = '\\';
mbc[bytes++] = '\\';
mbc[bytes++] = 'v';
goto write;
default:
if ( !IN_RANGE_CHAR(cp, 0x20, 0x7E) )
if ( !IN_RANGE_CHAR( cp, 0x20, 0x7E ) )
{
// While UTF8 bytes are valid UTF16, converting them will
// make distinct SQ strings indistinguishable to the client
#ifndef SQDBG_ESCAPE_UTF8_BYTES_IN_UTF16
if ( IN_RANGE(cp, 0xC2, 0xF4) )
// Convert UTF8 bytes in UTF16 by default with the assumption of
// most editors using UTF8 without BOM,
// and files being likely read plain (no conversion/ISO 8859-1)
// However, this will make certain distinct SQ strings (e.g. "\xC3\xBC", "\xFC")
// indistinguishable to the client
#ifndef SQDBG_DONT_CONVERT_UTF8_BYTES_IN_UTF16
if ( IN_RANGE( cp, 0xC2, 0xF4 ) )
{
if ( UTF8_2_LEAD(cp) )
{
@ -1337,7 +1303,12 @@ inline unsigned int SQUnicodeToUTF8( char *dst, unsigned int destSize, const SQC
}
}
#endif
// [0x7F, 0xC2) & (0xF4, 0xFF]
if ( cp >= 0xA0 ) // [0xA0, 0xFF]
goto x7ff;
doescape:
// [0x00, 0x20) & (0x7E, 0xA0)
if ( escape == kUTFEscapeQuoted )
mbc[bytes++] = '\\';
@ -1351,7 +1322,7 @@ inline unsigned int SQUnicodeToUTF8( char *dst, unsigned int destSize, const SQC
else
{
mbc[bytes++] = 'x';
bytes += printhex< true, false >( mbc + bytes, sizeof(mbc) - bytes, (SQChar)cp );
bytes += printhex< true, false >( mbc + bytes, sizeof(mbc) - bytes, (SQUnsignedChar)cp );
}
goto write;
@ -1364,6 +1335,7 @@ inline unsigned int SQUnicodeToUTF8( char *dst, unsigned int destSize, const SQC
}
else if ( cp <= 0x7FF )
{
x7ff:
UTF8_2_FROM_UTF32( mbc, cp );
bytes = 2;
}
@ -1387,7 +1359,7 @@ inline unsigned int SQUnicodeToUTF8( char *dst, unsigned int destSize, const SQC
mbc[bytes++] = '\\';
mbc[bytes++] = 'x';
bytes = bytes + printhex< true, false >( mbc + bytes, sizeof(mbc) - bytes, (SQChar)cp );
bytes = bytes + printhex< true, false >( mbc + bytes, sizeof(mbc) - bytes, (SQUnsignedChar)cp );
goto write;
}
}
@ -1478,4 +1450,33 @@ write:
}
#endif
#if defined(SQUNICODE) && !defined(_WIN32)
// Do case insensitive comparison for ASCII characters, ignore the rest
inline int sqdbg_wcsicmp( const SQChar *s1, const SQChar *s2 )
{
for (;;)
{
SQChar c1 = *s1++;
SQChar c2 = *s2++;
if ( !c1 || !c2 )
return c1 - c2;
if ( c1 == c2 )
continue;
if ( c1 >= 'A' && c1 <= 'Z' )
c1 |= 0x20;
if ( c2 >= 'A' && c2 <= 'Z' )
c2 |= 0x20;
if ( c1 == c2 )
continue;
return c1 - c2;
}
}
#endif
#endif // SQDBG_STRING_H

View File

@ -111,7 +111,44 @@ public:
}
};
template< int MEM_CACHE_CHUNKS_ALIGN = 2048 >
// GCC requires this to be outside of the class
template < bool S >
struct _CScratch_members;
template <>
struct _CScratch_members< true >
{
int m_LastFreeChunk;
int m_LastFreeIndex;
int m_PrevChunk;
int m_PrevIndex;
int LastFreeChunk() { return m_LastFreeChunk; }
int LastFreeIndex() { return m_LastFreeIndex; }
int PrevChunk() { return m_PrevChunk; }
int PrevIndex() { return m_PrevIndex; }
void SetLastFreeChunk( int i ) { m_LastFreeChunk = i; }
void SetLastFreeIndex( int i ) { m_LastFreeIndex = i; }
void SetPrevChunk( int i ) { m_PrevChunk = i; }
void SetPrevIndex( int i ) { m_PrevIndex = i; }
};
template <>
struct _CScratch_members< false >
{
int LastFreeChunk() { return 0; }
int LastFreeIndex() { return 0; }
int PrevChunk() { return 0; }
int PrevIndex() { return 0; }
void SetLastFreeChunk( int ) {}
void SetLastFreeIndex( int ) {}
void SetPrevChunk( int ) {}
void SetPrevIndex( int ) {}
};
template< bool SEQUENTIAL, int MEM_CACHE_CHUNKS_ALIGN = 2048 >
class CScratch
{
public:
@ -126,8 +163,7 @@ public:
chunk_t *m_Memory;
int m_MemChunkCount;
int m_LastFreeChunk;
int m_LastFreeIndex;
_CScratch_members< SEQUENTIAL > m;
char *Get( int index )
{
@ -145,7 +181,7 @@ public:
return &chunk->ptr[ msgIdx * MEM_CACHE_CHUNKSIZE ];
}
char *Alloc( int size, int *index = NULL, bool sequential = true )
char *Alloc( int size, int *index = NULL )
{
if ( !m_Memory )
{
@ -166,11 +202,11 @@ public:
int chunkIdx;
int matchedChunks = 0;
if ( sequential )
if ( SEQUENTIAL )
{
requiredChunks = ( size - 1 ) / MEM_CACHE_CHUNKSIZE + 1;
msgIdx = m_LastFreeIndex;
chunkIdx = m_LastFreeChunk;
msgIdx = m.LastFreeIndex();
chunkIdx = m.LastFreeChunk();
}
else
{
@ -184,14 +220,17 @@ public:
chunk_t *chunk = &m_Memory[ chunkIdx ];
Assert( chunk->count && chunk->ptr );
if ( sequential )
if ( SEQUENTIAL )
{
int remainingChunks = chunk->count - msgIdx;
if ( remainingChunks >= requiredChunks )
{
m_LastFreeIndex = msgIdx + requiredChunks;
m_LastFreeChunk = chunkIdx;
m.SetPrevChunk( m.LastFreeChunk() );
m.SetPrevIndex( m.LastFreeIndex() );
m.SetLastFreeIndex( msgIdx + requiredChunks );
m.SetLastFreeChunk( chunkIdx );
if ( index )
{
@ -267,6 +306,7 @@ public:
void Free( void *ptr )
{
STATIC_ASSERT( !SEQUENTIAL );
Assert( m_Memory );
Assert( ptr );
@ -290,7 +330,8 @@ public:
Assert( found );
(*(unsigned char**)&ptr)[ *(int*)ptr + sizeof(int) - 1 ] = 0xdd;
if ( *(int*)ptr )
(*(unsigned char**)&ptr)[ *(int*)ptr + sizeof(int) - 1 ] = 0xdd;
#endif
memset( (char*)ptr, 0, *(int*)ptr + sizeof(int) );
@ -315,12 +356,16 @@ public:
m_Memory = NULL;
m_MemChunkCount = 4;
m_LastFreeChunk = 0;
m_LastFreeIndex = 0;
m.SetLastFreeChunk( 0 );
m.SetLastFreeIndex( 0 );
m.SetPrevChunk( 0 );
m.SetPrevIndex( 0 );
}
void ReleaseShrink()
{
STATIC_ASSERT( SEQUENTIAL );
if ( !m_Memory )
return;
@ -359,13 +404,17 @@ public:
AssertOOM( m_Memory, m_MemChunkCount * sizeof(chunk_t) );
}
m_LastFreeChunk = 0;
m_LastFreeIndex = 0;
m.SetLastFreeChunk( 0 );
m.SetLastFreeIndex( 0 );
m.SetPrevChunk( 0 );
m.SetPrevIndex( 0 );
}
void Release()
{
if ( !m_Memory || ( !m_LastFreeChunk && !m_LastFreeIndex ) )
STATIC_ASSERT( SEQUENTIAL );
if ( !m_Memory || ( !m.LastFreeChunk() && !m.LastFreeIndex() ) )
return;
#ifdef _DEBUG
@ -380,8 +429,18 @@ public:
}
#endif
m_LastFreeChunk = 0;
m_LastFreeIndex = 0;
m.SetLastFreeChunk( 0 );
m.SetLastFreeIndex( 0 );
m.SetPrevChunk( 0 );
m.SetPrevIndex( 0 );
}
void ReleaseTop()
{
STATIC_ASSERT( SEQUENTIAL );
m.SetLastFreeChunk( m.PrevChunk() );
m.SetLastFreeIndex( m.PrevIndex() );
}
};
@ -391,212 +450,212 @@ class vector
public:
typedef unsigned int I;
CAllocator _base;
I _size;
CAllocator base;
I size;
vector() : _base(), _size(0)
vector() : base(), size(0)
{
Assert( !bExternalMem );
STATIC_ASSERT( !bExternalMem );
}
vector( CAllocator &a ) : _base(a), _size(0)
vector( CAllocator &a ) : base(a), size(0)
{
Assert( bExternalMem );
STATIC_ASSERT( bExternalMem );
}
vector( I count ) : _base(), _size(0)
vector( I count ) : base(), size(0)
{
Assert( !bExternalMem );
_base.Alloc( count * sizeof(T) );
STATIC_ASSERT( !bExternalMem );
base.Alloc( count * sizeof(T) );
}
vector( const vector< T > &src ) : _base()
vector( const vector< T > &src ) : base()
{
Assert( !bExternalMem );
_base.Alloc( src._base.Size() );
_size = src._size;
STATIC_ASSERT( !bExternalMem );
base.Alloc( src.base.Size() );
size = src.size;
for ( I i = 0; i < _size; i++ )
new( &_base[ i * sizeof(T) ] ) T( (T&)src._base[ i * sizeof(T) ] );
for ( I i = 0; i < size; i++ )
new( &base[ i * sizeof(T) ] ) T( (T&)src.base[ i * sizeof(T) ] );
}
~vector()
{
Assert( (unsigned int)_size <= _base.Size() );
Assert( (unsigned int)size <= base.Size() );
for ( I i = 0; i < _size; i++ )
((T&)(_base[ i * sizeof(T) ])).~T();
for ( I i = 0; i < size; i++ )
((T&)(base[ i * sizeof(T) ])).~T();
if ( !bExternalMem )
_base.Free();
base.Free();
}
T &operator[]( I i ) const
{
Assert( _size > 0 );
Assert( i >= 0 && i < _size );
Assert( _size * sizeof(T) <= _base.Size() );
return (T&)_base[ i * sizeof(T) ];
Assert( size > 0 );
Assert( i >= 0 && i < size );
Assert( size * sizeof(T) <= base.Size() );
return (T&)base[ i * sizeof(T) ];
}
T *base()
T *Base()
{
return _base.Base();
return base.Base();
}
I size() const
I Size() const
{
return _size;
return size;
}
I capacity() const
I Capacity() const
{
return _base.Size() / sizeof(T);
return base.Size() / sizeof(T);
}
T &top() const
T &Top() const
{
Assert( _size > 0 );
return (T&)_base[ ( _size - 1 ) * sizeof(T) ];
Assert( size > 0 );
return (T&)base[ ( size - 1 ) * sizeof(T) ];
}
void pop()
void Pop()
{
Assert( _size > 0 );
((T&)_base[ --_size * sizeof(T) ]).~T();
Assert( size > 0 );
((T&)base[ --size * sizeof(T) ]).~T();
}
T &append()
T &Append()
{
_base.Ensure( ++_size * sizeof(T) );
Assert( _size * sizeof(T) <= _base.Size() );
return *( new( &_base[ ( _size - 1 ) * sizeof(T) ] ) T() );
base.Ensure( ++size * sizeof(T) );
Assert( size * sizeof(T) <= base.Size() );
return *( new( &base[ ( size - 1 ) * sizeof(T) ] ) T() );
}
void append( const T &src )
void Append( const T &src )
{
_base.Ensure( ++_size * sizeof(T) );
Assert( _size * sizeof(T) <= _base.Size() );
new( &_base[ ( _size - 1 ) * sizeof(T) ] ) T( src );
base.Ensure( ++size * sizeof(T) );
Assert( size * sizeof(T) <= base.Size() );
new( &base[ ( size - 1 ) * sizeof(T) ] ) T( src );
}
T &insert( I i )
T &Insert( I i )
{
Assert( i >= 0 && i <= _size );
Assert( i >= 0 && i <= size );
_base.Ensure( ++_size * sizeof(T) );
Assert( _size * sizeof(T) <= _base.Size() );
base.Ensure( ++size * sizeof(T) );
Assert( size * sizeof(T) <= base.Size() );
if ( i != _size - 1 )
if ( i != size - 1 )
{
memmove( &_base[ ( i + 1 ) * sizeof(T) ],
&_base[ i * sizeof(T) ],
( _size - ( i + 1 ) ) * sizeof(T) );
memmove( &base[ ( i + 1 ) * sizeof(T) ],
&base[ i * sizeof(T) ],
( size - ( i + 1 ) ) * sizeof(T) );
}
return *( new( &_base[ i * sizeof(T) ] ) T() );
return *( new( &base[ i * sizeof(T) ] ) T() );
}
void remove( I i )
void Remove( I i )
{
Assert( _size > 0 );
Assert( i >= 0 && i < _size );
Assert( size > 0 );
Assert( i >= 0 && i < size );
((T&)_base[ i * sizeof(T) ]).~T();
((T&)base[ i * sizeof(T) ]).~T();
if ( i != _size - 1 )
if ( i != size - 1 )
{
memmove( &_base[ i * sizeof(T) ],
&_base[ ( i + 1 ) * sizeof(T) ],
( _size - ( i + 1 ) ) * sizeof(T) );
memmove( &base[ i * sizeof(T) ],
&base[ ( i + 1 ) * sizeof(T) ],
( size - ( i + 1 ) ) * sizeof(T) );
}
_size--;
size--;
}
void clear()
void Clear()
{
for ( I i = 0; i < _size; i++ )
((T&)_base[ i * sizeof(T) ]).~T();
for ( I i = 0; i < size; i++ )
((T&)base[ i * sizeof(T) ]).~T();
_size = 0;
size = 0;
}
void sort( int (*fn)(const T *, const T *) )
void Sort( int (*fn)(const T *, const T *) )
{
Assert( _size * sizeof(T) <= _base.Size() );
Assert( size * sizeof(T) <= base.Size() );
if ( _size > 1 )
if ( size > 1 )
{
qsort( _base.Base(), _size, sizeof(T), (int (*)(const void *, const void *))fn );
qsort( base.Base(), size, sizeof(T), (int (*)(const void *, const void *))fn );
}
}
void reserve( I count )
void Reserve( I count )
{
Assert( (unsigned int)_size <= _base.Size() );
Assert( (unsigned int)size <= base.Size() );
if ( count == 0 )
count = 4;
if ( (unsigned int)count == _base.Size() )
if ( (unsigned int)count == base.Size() )
return;
for ( I i = count; i < _size; i++ )
((T&)_base[ i * sizeof(T) ]).~T();
for ( I i = count; i < size; i++ )
((T&)base[ i * sizeof(T) ]).~T();
_base.Alloc( count * sizeof(T) );
base.Alloc( count * sizeof(T) );
}
void purge()
void Purge()
{
Assert( _size * sizeof(T) <= _base.Size() );
Assert( size * sizeof(T) <= base.Size() );
for ( I i = 0; i < _size; i++ )
((T&)_base[ i * sizeof(T) ]).~T();
for ( I i = 0; i < size; i++ )
((T&)base[ i * sizeof(T) ]).~T();
_base.Free();
_size = 0;
base.Free();
size = 0;
}
};
class CBuffer
{
public:
CMemory _base;
int _size;
int _offset;
CMemory base;
int size;
int offset;
char *base()
char *Base()
{
return _base.Base() + _offset;
return base.Base() + offset;
}
int size() const
int Size() const
{
return _size;
return size;
}
int capacity() const
int Capacity() const
{
return _base.Size();
return base.Size();
}
void reserve( int count )
void Reserve( int count )
{
Assert( (unsigned int)_size <= _base.Size() );
Assert( (unsigned int)size <= base.Size() );
if ( (unsigned int)count == _base.Size() )
if ( (unsigned int)count == base.Size() )
return;
_base.Alloc( count );
base.Alloc( count );
}
void purge()
void Purge()
{
_base.Free();
_size = 0;
_offset = 0;
base.Free();
size = 0;
offset = 0;
}
};
@ -608,16 +667,16 @@ public:
CBufTmpCache( CBuffer *b ) :
buffer(b),
size(buffer->_size)
size(buffer->size)
{
buffer->_offset += buffer->_size;
buffer->_size = 0;
buffer->offset += buffer->size;
buffer->size = 0;
}
~CBufTmpCache()
{
buffer->_offset -= size;
buffer->_size = size;
buffer->offset -= size;
buffer->size = size;
}
};

View File

@ -17,7 +17,6 @@
IScriptVM* makeSquirrelVM();
int vscript_token = 0;
int vscript_debugger_port = 0;
class CScriptManager : public CTier1AppSystem<IScriptManager>
{

View File

@ -115,7 +115,7 @@ public:
virtual bool Init() override;
virtual void Shutdown() override;
virtual bool ConnectDebugger( int port = 0 ) override;
virtual bool ConnectDebugger( int port = 0, float timeout = 0.0f ) override;
virtual void DisconnectDebugger() override;
virtual ScriptLanguage_t GetLanguage() override;
@ -284,6 +284,14 @@ public:
WriteObject( (const SQObjectPtr&)obj, pBuffer, writeState );
}
void WriteObject( SQGenerator *pObj, CUtlBuffer* pBuffer, WriteStateMap& writeState )
{
SQObject obj;
obj._type = OT_GENERATOR;
obj._unVal.pUserPointer = pObj;
WriteObject( (const SQObjectPtr&)obj, pBuffer, writeState );
}
void ReadObject( SQObjectPtr &obj, CUtlBuffer* pBuffer, ReadStateMap& readState );
// Do not implicity add/remove ref
@ -327,7 +335,16 @@ namespace SQVector
}
SQUserPointer p;
sq_getinstanceup(vm, 1, &p, 0);
if (SQ_FAILED(sq_getinstanceup(vm, 1, &p, 0)))
{
return SQ_ERROR;
}
if (!p)
{
return sq_throwerror(vm, "Accessed null instance");
}
new (p) Vector(x, y, z);
return 0;
@ -343,7 +360,7 @@ namespace SQVector
return sq_throwerror(vm, "Expected Vector._get(string)");
}
if (key[0] < 'x' || key['0'] > 'z' || key[1] != '\0')
if (key[0] < 'x' || key[0] > 'z' || key[1] != '\0')
{
return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
}
@ -369,7 +386,7 @@ namespace SQVector
return sq_throwerror(vm, "Expected Vector._set(string)");
}
if (key[0] < 'x' || key['0'] > 'z' || key[1] != '\0')
if (key[0] < 'x' || key[0] > 'z' || key[1] != '\0')
{
return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
}
@ -1315,10 +1332,7 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
case OT_INSTANCE:
{
Vector* v = nullptr;
SQUserPointer tag;
if (SQ_SUCCEEDED(sq_gettypetag(vm, idx, &tag)) &&
tag == TYPETAG_VECTOR &&
SQ_SUCCEEDED(sq_getinstanceup(vm, idx, (SQUserPointer*)&v, TYPETAG_VECTOR)))
if (SQ_SUCCEEDED(sq_getinstanceup(vm, idx, (SQUserPointer*)&v, TYPETAG_VECTOR)))
{
variant.Free();
variant = (Vector*)malloc(sizeof(Vector));
@ -1347,12 +1361,10 @@ SQInteger function_stub(HSQUIRRELVM vm)
{
SQInteger top = sq_gettop(vm);
SQUserPointer userptr = nullptr;
sq_getuserpointer(vm, top, &userptr);
ScriptFunctionBinding_t* pFunc = nullptr;
sq_getuserpointer(vm, top, (SQUserPointer*)&pFunc);
Assert(userptr);
ScriptFunctionBinding_t* pFunc = (ScriptFunctionBinding_t*)userptr;
Assert(pFunc);
int nargs = pFunc->m_desc.m_Parameters.Count();
int nLastHScriptIdx = -1;
@ -1449,15 +1461,30 @@ SQInteger function_stub(HSQUIRRELVM vm)
if (pFunc->m_flags & SF_MEMBER_FUNC)
{
SQUserPointer self;
sq_getinstanceup(vm, 1, &self, nullptr);
ClassInstanceData* classInstanceData;
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
{
return SQ_ERROR;
}
if (!self)
if (!classInstanceData)
{
return sq_throwerror(vm, "Accessed null instance");
}
instance = ((ClassInstanceData*)self)->instance;
// check that the type of self, or any basetype, matches the function description
ScriptClassDesc_t *selfType = classInstanceData->desc;
while (selfType != pFunc->m_desc.m_pScriptClassDesc)
{
if (!selfType)
{
return sq_throwerror(vm, "Mismatched instance type");
}
selfType = selfType->m_pBaseDesc;
Assert(selfType != classInstanceData->desc); // there should be no infinite loop
}
instance = classInstanceData->instance;
}
ScriptVariant_t script_retval;
@ -1466,8 +1493,6 @@ SQInteger function_stub(HSQUIRRELVM vm)
SquirrelVM* pSquirrelVM = (SquirrelVM*)sq_getsharedforeignptr(vm);
Assert(pSquirrelVM);
sq_resetobject(&pSquirrelVM->lastError_);
bool call_success = (*pFunc->m_pfnBinding)(pFunc->m_pFunction, instance, params.Base(), nargs,
pFunc->m_desc.m_ReturnType == FIELD_VOID ? nullptr : &script_retval, script_retval_storage);
Assert(call_success);
@ -1477,6 +1502,7 @@ SQInteger function_stub(HSQUIRRELVM vm)
if (!sq_isnull(pSquirrelVM->lastError_))
{
sq_pushobject(vm, pSquirrelVM->lastError_);
sq_release(vm, &pSquirrelVM->lastError_);
sq_resetobject(&pSquirrelVM->lastError_);
sq_retval = sq_throwobject(vm);
}
@ -1546,28 +1572,42 @@ SQInteger destructor_stub_instance(SQUserPointer p, SQInteger size)
SQInteger constructor_stub(HSQUIRRELVM vm)
{
ScriptClassDesc_t* pClassDesc = nullptr;
sq_gettypetag(vm, 1, (SQUserPointer*)&pClassDesc);
if (SQ_FAILED(sq_gettypetag(vm, 1, (SQUserPointer*)&pClassDesc)))
{
return sq_throwerror(vm, "Expected native class");
}
if (!pClassDesc || (void*)pClassDesc == TYPETAG_VECTOR)
{
return sq_throwerror(vm, "Unable to obtain native class description");
}
if (!pClassDesc->m_pfnConstruct)
{
return sqstd_throwerrorf(vm, "Unable to construct instances of %s", pClassDesc->m_pszScriptName);
}
SquirrelVM* pSquirrelVM = (SquirrelVM*)sq_getsharedforeignptr(vm);
Assert(pSquirrelVM);
SQUserPointer p;
if (SQ_FAILED(sq_getinstanceup(vm, 1, &p, 0)))
{
return SQ_ERROR;
}
sq_resetobject(&pSquirrelVM->lastError_);
if (!p)
{
return sq_throwerror(vm, "Accessed null instance");
}
void* instance = pClassDesc->m_pfnConstruct();
#ifdef DBGFLAG_ASSERT
SquirrelVM* pSquirrelVM = (SquirrelVM*)sq_getsharedforeignptr(vm);
Assert(pSquirrelVM);
// expect construction to always succeed
Assert(sq_isnull(pSquirrelVM->lastError_));
#endif
{
SQUserPointer p;
sq_getinstanceup(vm, 1, &p, 0);
new(p) ClassInstanceData(instance, pClassDesc, nullptr, true);
}
new(p) ClassInstanceData(instance, pClassDesc, nullptr, true);
sq_setreleasehook(vm, 1, &destructor_stub);
@ -1577,7 +1617,10 @@ SQInteger constructor_stub(HSQUIRRELVM vm)
SQInteger tostring_stub(HSQUIRRELVM vm)
{
ClassInstanceData* classInstanceData = nullptr;
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
{
return SQ_ERROR;
}
char buffer[128] = "";
@ -1607,7 +1650,10 @@ SQInteger tostring_stub(HSQUIRRELVM vm)
SQInteger get_stub(HSQUIRRELVM vm)
{
ClassInstanceData* classInstanceData = nullptr;
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
{
return SQ_ERROR;
}
const char* key = nullptr;
sq_getstring(vm, 2, &key);
@ -1629,7 +1675,19 @@ SQInteger get_stub(HSQUIRRELVM vm)
}
else
{
sq_retval = sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
// Fallback
// Extra stack variables don't need to be popped, they are cleaned up on exit
sq_pushroottable(vm);
sq_push(vm, -2);
if ( SQ_SUCCEEDED( sq_rawget(vm, -2) ) )
{
sq_retval = 1;
}
else
{
sq_retval = sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
}
}
var.Free();
@ -1639,7 +1697,10 @@ SQInteger get_stub(HSQUIRRELVM vm)
SQInteger set_stub(HSQUIRRELVM vm)
{
ClassInstanceData* classInstanceData = nullptr;
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
{
return SQ_ERROR;
}
const char* key = nullptr;
sq_getstring(vm, 2, &key);
@ -1660,11 +1721,24 @@ SQInteger set_stub(HSQUIRRELVM vm)
classInstanceData->desc->pHelper->Set(classInstanceData->instance, key, var)
))
{
sq_retval = sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
// Fallback
sq_pushroottable(vm);
sq_push(vm, -3);
sq_push(vm, -3);
if ( SQ_SUCCEEDED( sq_rawset(vm, -3) ) )
{
// rawset doesn't return correctly, pop env to return val
sq_pop(vm, 1);
sq_retval = 1;
}
else
{
sq_retval = sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
}
}
var.Free();
sq_pop(vm, 1);
return sq_retval;
}
@ -2058,17 +2132,26 @@ void SquirrelVM::Shutdown()
bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing );
bool SquirrelVM::ConnectDebugger( int port )
bool SquirrelVM::ConnectDebugger( int port, float timeout )
{
if ( !debugger_ )
{
debugger_ = sqdbg_attach_debugger( vm_ );
if ( sqdbg_listen_socket( debugger_, port ) != 0 )
if ( sqdbg_listen_socket( debugger_, port ) == 0 && timeout )
{
sqdbg_destroy_debugger( vm_ );
debugger_ = nullptr;
return false;
float startTime = Plat_FloatTime();
while ( !sqdbg_is_client_connected( debugger_ ) )
{
float time = Plat_FloatTime();
if ( time - startTime > timeout )
break;
ThreadSleep( 50 );
sqdbg_frame( debugger_ );
}
}
}
else
@ -2514,13 +2597,16 @@ bool SquirrelVM::RegisterClass(ScriptClassDesc_t* pClassDesc)
sq_newclosure(vm_, tostring_stub, 0);
sq_newslot(vm_, -3, SQFalse);
sq_pushstring(vm_, "_get", -1);
sq_newclosure(vm_, get_stub, 0);
sq_newslot(vm_, -3, SQFalse);
if ( pClassDesc->pHelper )
{
sq_pushstring(vm_, "_get", -1);
sq_newclosure(vm_, get_stub, 0);
sq_newslot(vm_, -3, SQFalse);
sq_pushstring(vm_, "_set", -1);
sq_newclosure(vm_, set_stub, 0);
sq_newslot(vm_, -3, SQFalse);
sq_pushstring(vm_, "_set", -1);
sq_newclosure(vm_, set_stub, 0);
sq_newslot(vm_, -3, SQFalse);
}
sq_pushstring(vm_, "IsValid", -1);
sq_newclosure(vm_, IsValid_stub, 0);
@ -2709,10 +2795,8 @@ void SquirrelVM::SetInstanceUniqeId(HSCRIPT hInstance, const char* pszId)
HSQOBJECT* obj = (HSQOBJECT*)hInstance;
sq_pushobject(vm_, *obj);
SQUserPointer self;
sq_getinstanceup(vm_, -1, &self, nullptr);
auto classInstanceData = (ClassInstanceData*)self;
ClassInstanceData* classInstanceData;
sq_getinstanceup(vm_, -1, (SQUserPointer*)&classInstanceData, nullptr);
classInstanceData->instanceId = pszId;
@ -2770,11 +2854,10 @@ void* SquirrelVM::GetInstanceValue(HSCRIPT hInstance, ScriptClassDesc_t* pExpect
}
sq_pushobject(vm_, *obj);
SQUserPointer self;
sq_getinstanceup(vm_, -1, &self, nullptr);
ClassInstanceData* classInstanceData;
sq_getinstanceup(vm_, -1, (SQUserPointer*)&classInstanceData, nullptr);
sq_pop(vm_, 1);
auto classInstanceData = (ClassInstanceData*)self;
if (!classInstanceData)
{
@ -3366,7 +3449,8 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
#ifdef _DEBUG
bool bAsserted = false;
if ( pThis->_noutervalues && pThis->_name._type == OT_STRING && pThis->_name._unVal.pString )
if ( pThis->_noutervalues && pThis->_name._type == OT_STRING && pThis->_name._unVal.pString &&
pThis->_outervalues[0]._type == OT_USERPOINTER )
{
Assert( pThis->_noutervalues == 1 );
Assert( pThis->_outervalues[0]._type == OT_USERPOINTER );
@ -3669,23 +3753,25 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
if ( pThis->_callsstacksize )
{
int stackidx = -1;
for ( int i = pThis->_callsstacksize; i--; )
for ( int i = 0; i < pThis->_callsstacksize; i++ )
{
const SQVM::CallInfo *ci = &pThis->_callsstack[i];
if ( pThis->ci == ci )
stackidx = i;
Assert( !ci->_generator );
Assert( ci->_ip && ci->_ip >= ci->_closure._unVal.pClosure->_function->_instructions );
Assert( ci->_ip >= ci->_closure._unVal.pClosure->_function->_instructions &&
ci->_ip < ci->_closure._unVal.pClosure->_function->_instructions +
ci->_closure._unVal.pClosure->_function->_ninstructions );
Assert( pThis->_etraps.size() >= (SQUnsignedInteger)ci->_etraps );
Assert( ci->_closure._type == OT_CLOSURE && ci->_closure._unVal.pClosure );
WriteObject( ci->_closure, pBuffer, writeState );
int offset = (intp)ci->_ip - (intp)ci->_closure._unVal.pClosure->_function->_instructions;
Assert( ci->_ip - ci->_closure._unVal.pClosure->_function->_instructions <= INT_MAX );
pBuffer->PutChar( ci->_generator != 0 );
if ( ci->_generator )
WriteObject( ci->_generator, pBuffer, writeState );
int offset = ci->_ip - ci->_closure._unVal.pClosure->_function->_instructions;
pBuffer->PutInt( offset );
pBuffer->PutInt( ci->_etraps );
pBuffer->PutInt( ci->_prevstkbase );
@ -3694,16 +3780,18 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
pBuffer->PutInt( ci->_ncalls );
pBuffer->PutChar( ci->_root );
for ( int j = ci->_etraps; j--; )
for ( int j = 0; j < ci->_etraps; j++ )
{
const SQExceptionTrap &et = pThis->_etraps[j];
pBuffer->PutInt( et._extarget );
pBuffer->PutInt( et._stackbase );
pBuffer->PutInt( et._stacksize );
Assert( et._ip == ci->_ip );
pBuffer->PutInt( et._stackbase );
Assert( et._ip - ci->_ip <= INT_MAX );
pBuffer->PutInt( et._ip - ci->_ip );
pBuffer->PutInt( et._extarget );
}
}
int stackidx = pThis->ci - pThis->_callsstack;
Assert( stackidx >= 0 && stackidx < pThis->_callsstacksize );
pBuffer->PutInt( stackidx );
}
@ -3734,29 +3822,37 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
WriteObject( pThis->_closure, pBuffer, writeState );
const SQVM::CallInfo &ci = pThis->_ci;
const SQVM::CallInfo *ci = &pThis->_ci;
Assert( !ci._generator );
Assert( pThis->_closure._unVal.pClosure == ci._closure._unVal.pClosure );
Assert( ci._ip && ci._ip >= ci._closure._unVal.pClosure->_function->_instructions );
Assert( pThis->_etraps.size() >= (SQUnsignedInteger)ci._etraps );
Assert( pThis->_closure._unVal.pClosure == ci->_closure._unVal.pClosure );
Assert( ci->_ip >= ci->_closure._unVal.pClosure->_function->_instructions &&
ci->_ip < ci->_closure._unVal.pClosure->_function->_instructions +
ci->_closure._unVal.pClosure->_function->_ninstructions );
Assert( pThis->_etraps.size() >= (SQUnsignedInteger)ci->_etraps );
int offset = (intp)ci._ip - (intp)ci._closure._unVal.pClosure->_function->_instructions;
Assert( ci->_ip - ci->_closure._unVal.pClosure->_function->_instructions <= INT_MAX );
pBuffer->PutChar( ci->_generator != 0 );
if ( ci->_generator )
WriteObject( ci->_generator, pBuffer, writeState );
int offset = ci->_ip - ci->_closure._unVal.pClosure->_function->_instructions;
pBuffer->PutInt( offset );
pBuffer->PutInt( ci._etraps );
pBuffer->PutInt( ci._prevstkbase );
pBuffer->PutInt( ci._prevtop );
pBuffer->PutInt( ci._target );
pBuffer->PutInt( ci._ncalls );
pBuffer->PutChar( ci._root );
pBuffer->PutInt( ci->_etraps );
pBuffer->PutInt( ci->_prevstkbase );
pBuffer->PutInt( ci->_prevtop );
pBuffer->PutInt( ci->_target );
pBuffer->PutInt( ci->_ncalls );
pBuffer->PutChar( ci->_root );
for ( int j = ci._etraps; j--; )
for ( int j = 0; j < ci->_etraps; j++ )
{
const SQExceptionTrap &et = pThis->_etraps[j];
pBuffer->PutInt( et._extarget );
pBuffer->PutInt( et._stackbase );
pBuffer->PutInt( et._stacksize );
Assert( et._ip == ci._ip );
pBuffer->PutInt( et._stackbase );
Assert( et._ip - ci->_ip <= INT_MAX );
pBuffer->PutInt( et._ip - ci->_ip );
pBuffer->PutInt( et._extarget );
}
int stacksize = pThis->_stack.size();
@ -3770,7 +3866,6 @@ void SquirrelVM::WriteObject( const SQObjectPtr &obj, CUtlBuffer* pBuffer, Write
}
case OT_USERDATA:
case OT_USERPOINTER:
Assert(0);
break;
default:
AssertMsgAlways( 0, "SquirrelVM::WriteObject: unknown type" );
@ -3814,26 +3909,10 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
case OT_STRING:
{
int len = pBuffer->GetInt();
char *psz;
if ( len < 1024 )
{
psz = (char*)stackalloc( len );
}
else
{
psz = (char*)malloc( len );
}
pBuffer->Get( psz, len );
char *psz = (char*)pBuffer->PeekGet( 0 );
pBuffer->SeekGet( CUtlBuffer::SEEK_CURRENT, len );
Assert( pBuffer->IsValid() );
obj._unVal.pString = SQString::Create( _ss(vm_), psz, len );
if ( len >= 1024 )
{
free( psz );
}
break;
}
case OT_TABLE:
@ -4319,10 +4398,10 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
if ( pThis->_callsstacksize )
{
if ( pThis->_callsstacksize >= pThis->_alloccallsstacksize )
while ( pThis->_callsstacksize >= pThis->_alloccallsstacksize )
pThis->GrowCallStack();
for ( int i = pThis->_callsstacksize; i--; )
for ( int i = 0; i < pThis->_callsstacksize; i++ )
{
SQVM::CallInfo *ci = &pThis->_callsstack[i];
@ -4330,23 +4409,31 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
ReadObject( closure, pBuffer, readState );
Assert( closure._type == OT_CLOSURE && closure._unVal.pClosure );
int offset = pBuffer->GetInt();
int funcsize = sizeof(SQInstruction) * closure._unVal.pClosure->_function->_ninstructions;
int start = (intp)(closure._unVal.pClosure->_function->_instructions);
int pos = start + offset;
ci->_ip = (SQInstruction*)pos;
Assert( pos < (start + funcsize) );
// don't read past boundary
if ( pos >= (start + funcsize) )
if ( pBuffer->GetChar() )
{
ci->_ip = (SQInstruction*)start;
SQObject generator;
ReadObject( generator, pBuffer, readState );
Assert( generator._type == OT_GENERATOR && generator._unVal.pGenerator );
ci->_generator = generator._unVal.pGenerator;
}
else
{
ci->_generator = NULL;
}
int offset = pBuffer->GetInt();
SQInstruction *start = closure._unVal.pClosure->_function->_instructions;
SQInstruction *end = start + closure._unVal.pClosure->_function->_ninstructions;
SQInstruction *pos = start + offset;
Assert( pos >= start && pos < end );
if ( pos < start || pos >= end )
pos = start;
ci->_ip = pos;
ci->_literals = closure._unVal.pClosure->_function->_literals;
ci->_closure = closure;
ci->_generator = NULL;
ci->_etraps = pBuffer->GetInt();
ci->_prevstkbase = pBuffer->GetInt();
ci->_prevtop = pBuffer->GetInt();
@ -4356,13 +4443,13 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
pThis->_etraps.resize( ci->_etraps );
for ( int j = ci->_etraps; j--; )
for ( int j = 0; j < ci->_etraps; j++ )
{
SQExceptionTrap &et = pThis->_etraps[j];
et._extarget = pBuffer->GetInt();
et._stackbase = pBuffer->GetInt();
et._stacksize = pBuffer->GetInt();
et._ip = ci->_ip;
et._stackbase = pBuffer->GetInt();
et._ip = ci->_ip + pBuffer->GetInt();
et._extarget = pBuffer->GetInt();
}
}
@ -4409,41 +4496,49 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
pThis->_state = (SQGenerator::SQGeneratorState)state;
SQVM::CallInfo &ci = pThis->_ci;
SQVM::CallInfo *ci = &pThis->_ci;
int offset = pBuffer->GetInt();
int funcsize = sizeof(SQInstruction) * closure._unVal.pClosure->_function->_ninstructions;
int start = (intp)(closure._unVal.pClosure->_function->_instructions);
int pos = start + offset;
ci._ip = (SQInstruction*)pos;
Assert( pos < (start + funcsize) );
// don't read past boundary
if ( pos >= (start + funcsize) )
if ( pBuffer->GetChar() )
{
ci._ip = (SQInstruction*)start;
SQObject generator;
ReadObject( generator, pBuffer, readState );
Assert( generator._type == OT_GENERATOR && generator._unVal.pGenerator );
ci->_generator = generator._unVal.pGenerator;
}
else
{
ci->_generator = NULL;
}
ci._literals = closure._unVal.pClosure->_function->_literals;
ci._closure = closure;
ci._generator = NULL;
ci._etraps = pBuffer->GetInt();
ci._prevstkbase = pBuffer->GetInt();
ci._prevtop = pBuffer->GetInt();
ci._target = pBuffer->GetInt();
ci._ncalls = pBuffer->GetInt();
ci._root = pBuffer->GetChar();
int offset = pBuffer->GetInt();
SQInstruction *start = closure._unVal.pClosure->_function->_instructions;
SQInstruction *end = start + closure._unVal.pClosure->_function->_ninstructions;
SQInstruction *pos = start + offset;
pThis->_etraps.resize( ci._etraps );
Assert( pos >= start && pos < end );
for ( int j = ci._etraps; j--; )
if ( pos < start || pos >= end )
pos = start;
ci->_ip = pos;
ci->_literals = closure._unVal.pClosure->_function->_literals;
ci->_closure = closure;
ci->_etraps = pBuffer->GetInt();
ci->_prevstkbase = pBuffer->GetInt();
ci->_prevtop = pBuffer->GetInt();
ci->_target = pBuffer->GetInt();
ci->_ncalls = pBuffer->GetInt();
ci->_root = pBuffer->GetChar();
pThis->_etraps.resize( ci->_etraps );
for ( int j = 0; j < ci->_etraps; j++ )
{
SQExceptionTrap &et = pThis->_etraps[j];
et._extarget = pBuffer->GetInt();
et._stackbase = pBuffer->GetInt();
et._stacksize = pBuffer->GetInt();
et._ip = ci._ip;
et._stackbase = pBuffer->GetInt();
et._ip = ci->_ip + pBuffer->GetInt();
et._extarget = pBuffer->GetInt();
}
int stacksize = pBuffer->GetInt();
@ -4457,10 +4552,7 @@ void SquirrelVM::ReadObject( SQObjectPtr &pObj, CUtlBuffer* pBuffer, ReadStateMa
}
case OT_USERDATA:
case OT_USERPOINTER:
{
Assert(0);
break;
}
default:
AssertMsgAlways( 0, "SquirrelVM::ReadObject: serialisation error" );
}