mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2024-12-25 14:25:32 +03:00
Added an entity factory manager for custom weapons
This commit is contained in:
parent
f8a8d49be7
commit
5a0c406dbf
178
sp/src/game/server/mapbase/custom_weapon_factory.cpp
Normal file
178
sp/src/game/server/mapbase/custom_weapon_factory.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
#include "cbase.h"
|
||||
#include "custom_weapon_factory.h"
|
||||
|
||||
#define GENERIC_MANIFEST_FILE "scripts/mapbase_default_manifest.txt"
|
||||
#define AUTOLOADED_MANIFEST_FILE UTIL_VarArgs("maps/%s_manifest.txt", MapName())
|
||||
|
||||
extern ConVar mapbase_load_default_manifest;
|
||||
|
||||
|
||||
|
||||
CCustomWeaponSystem::CCustomWeaponSystem() : CAutoGameSystem("CustomWeaponFactorySystem")
|
||||
{
|
||||
}
|
||||
|
||||
void CCustomWeaponSystem::LevelInitPreEntity()
|
||||
{
|
||||
// Check for a generic "mapname_manifest.txt" file and load it.
|
||||
if (filesystem->FileExists(AUTOLOADED_MANIFEST_FILE, "GAME"))
|
||||
{
|
||||
AddManifestFile(AUTOLOADED_MANIFEST_FILE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load the generic script instead.
|
||||
ParseGenericManifest();
|
||||
}
|
||||
}
|
||||
|
||||
// Get a generic, hardcoded manifest with hardcoded names.
|
||||
void CCustomWeaponSystem::ParseGenericManifest()
|
||||
{
|
||||
if (!mapbase_load_default_manifest.GetBool())
|
||||
return;
|
||||
|
||||
KeyValues* pKV = new KeyValues("DefaultManifest");
|
||||
pKV->LoadFromFile(filesystem, GENERIC_MANIFEST_FILE);
|
||||
|
||||
AddManifestFile(pKV/*, true*/);
|
||||
|
||||
pKV->deleteThis();
|
||||
}
|
||||
|
||||
void CCustomWeaponSystem::AddManifestFile(const char* file)
|
||||
{
|
||||
KeyValues* pKV = new KeyValues(file);
|
||||
if (!pKV->LoadFromFile(filesystem, file))
|
||||
{
|
||||
Warning("Mapbase Manifest: \"%s\" is unreadable or missing (can't load KV, check for syntax errors)\n", file);
|
||||
pKV->deleteThis();
|
||||
return;
|
||||
}
|
||||
|
||||
CGMsg(1, CON_GROUP_MAPBASE_MISC, "===== Mapbase Manifest: Loading manifest file %s =====\n", file);
|
||||
|
||||
AddManifestFile(pKV, false);
|
||||
|
||||
CGMsg(1, CON_GROUP_MAPBASE_MISC, "==============================================================================\n");
|
||||
|
||||
pKV->deleteThis();
|
||||
}
|
||||
|
||||
void CCustomWeaponSystem::AddManifestFile(KeyValues* pKV, bool bDontWarn)
|
||||
{
|
||||
KeyValues* pKey = pKV->FindKey("weapons");
|
||||
|
||||
if (pKey)
|
||||
{
|
||||
char value[MAX_PATH];
|
||||
// Parse %mapname%, etc.
|
||||
bool inparam = false;
|
||||
CUtlStringList outStrings;
|
||||
V_SplitString(pKey->GetString(), "%", outStrings);
|
||||
for (int i = 0; i < outStrings.Count(); i++)
|
||||
{
|
||||
if (inparam)
|
||||
{
|
||||
if (FStrEq(outStrings[i], "mapname"))
|
||||
{
|
||||
Q_strncat(value, MapName(), sizeof(value));
|
||||
}
|
||||
else if (FStrEq(outStrings[i], "language"))
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
char uilanguage[64];
|
||||
engine->GetUILanguage(uilanguage, sizeof(uilanguage));
|
||||
Q_strncat(value, uilanguage, sizeof(value));
|
||||
#else
|
||||
// Give up, use English
|
||||
Q_strncat(value, "english", sizeof(value));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncat(value, outStrings[i], sizeof(value));
|
||||
}
|
||||
|
||||
inparam = !inparam;
|
||||
}
|
||||
|
||||
outStrings.PurgeAndDeleteElements();
|
||||
bDontWarn = pKV->GetBool("NoErrors", bDontWarn);
|
||||
|
||||
LoadCustomWeaponsManifest(value, bDontWarn);
|
||||
}
|
||||
}
|
||||
|
||||
#define Factory CustomWeaponsFactoryDictionary()
|
||||
void CCustomWeaponSystem::LoadCustomWeaponsManifest(const char* file, bool bDontWarn)
|
||||
{
|
||||
KeyValuesAD pKV("weapons_manifest");
|
||||
if (pKV->LoadFromFile(filesystem, file, "GAME"))
|
||||
{
|
||||
for (KeyValues *pkvWeapon = pKV->GetFirstValue(); pkvWeapon != nullptr; pkvWeapon = pkvWeapon->GetNextValue())
|
||||
{
|
||||
const char* pszClassname = pkvWeapon->GetName();
|
||||
KeyValuesAD pkvWeaponScript("WeaponData");
|
||||
if (pkvWeaponScript->LoadFromFile(filesystem, pkvWeapon->GetString(), "GAME"))
|
||||
{
|
||||
const char* pszFactory = pkvWeaponScript->GetString("custom_factory", nullptr);
|
||||
unsigned short FactoryIndex = Factory.Find(pszFactory);
|
||||
if (Factory.IsValidIndex(FactoryIndex))
|
||||
{
|
||||
unsigned short ClassIndex = m_ClassFactories.Find(pszClassname);
|
||||
if (!m_ClassFactories.IsValidIndex(ClassIndex))
|
||||
{
|
||||
ClassIndex = m_ClassFactories.Insert(pszClassname);
|
||||
m_ClassFactories[ClassIndex].pOldFactory = EntityFactoryDictionary()->FindFactory(pszClassname);
|
||||
}
|
||||
|
||||
m_ClassFactories[ClassIndex].sDataFile = file;
|
||||
m_ClassFactories[ClassIndex].pNewFactory = Factory.Element(FactoryIndex);
|
||||
EntityFactoryDictionary()->UninstallFactory(pszClassname);
|
||||
EntityFactoryDictionary()->InstallFactory(m_ClassFactories[ClassIndex].pNewFactory, pszClassname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef Factory
|
||||
|
||||
void CCustomWeaponSystem::LevelShutdownPostEntity()
|
||||
{
|
||||
for (int i = 0; i < m_ClassFactories.Count(); i++)
|
||||
{
|
||||
EntityFactoryDictionary()->UninstallFactory(m_ClassFactories.GetElementName(i));
|
||||
const CustomClassName_t& entry = m_ClassFactories.Element(i);
|
||||
if (entry.pOldFactory)
|
||||
EntityFactoryDictionary()->InstallFactory(entry.pOldFactory, m_ClassFactories.GetElementName(i));
|
||||
}
|
||||
|
||||
m_ClassFactories.Purge();
|
||||
}
|
||||
|
||||
void CCustomWeaponSystem::ParseWeapon(CBaseCombatWeapon* pWeapon, const char* pClassName)
|
||||
{
|
||||
ICustomWeapon* pCustom = dynamic_cast<ICustomWeapon*> (pWeapon);
|
||||
if (!pCustom)
|
||||
return;
|
||||
|
||||
unsigned short i = m_ClassFactories.Find(pClassName);
|
||||
if (!m_ClassFactories.IsValidIndex(i))
|
||||
return;
|
||||
|
||||
pCustom->ParseCustomFromWeaponFile(m_ClassFactories[i].sDataFile.String());
|
||||
}
|
||||
|
||||
CUtlDict<IEntityFactory*, unsigned short>& CustomWeaponsFactoryDictionary()
|
||||
{
|
||||
static CUtlDict<IEntityFactory*, unsigned short> dict;
|
||||
return dict;
|
||||
}
|
||||
|
||||
static CCustomWeaponSystem g_CustomWeaponsSystem;
|
||||
CCustomWeaponSystem* CustomWeaponSystem()
|
||||
{
|
||||
return &g_CustomWeaponsSystem;
|
||||
}
|
76
sp/src/game/server/mapbase/custom_weapon_factory.h
Normal file
76
sp/src/game/server/mapbase/custom_weapon_factory.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef CUSTOM_WEAPON_FACTORY_H
|
||||
#define CUSTOM_WEAPON_FACTORY_H
|
||||
#pragma once
|
||||
#include "utldict.h"
|
||||
#include "utlsymbol.h"
|
||||
|
||||
CUtlDict< IEntityFactory*, unsigned short >& CustomWeaponsFactoryDictionary();
|
||||
|
||||
class ICustomWeapon
|
||||
{
|
||||
public:
|
||||
virtual void ParseCustomFromWeaponFile(const char* pFileName) = 0;
|
||||
};
|
||||
|
||||
class CCustomWeaponSystem : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
CCustomWeaponSystem();
|
||||
|
||||
// Level init, shutdown
|
||||
virtual void LevelInitPreEntity();
|
||||
virtual void LevelShutdownPostEntity();
|
||||
|
||||
void ParseWeapon(CBaseCombatWeapon* pWeapon, const char* pClassName);
|
||||
|
||||
private:
|
||||
void ParseGenericManifest();
|
||||
void AddManifestFile(const char* file);
|
||||
void AddManifestFile(KeyValues* pKV, bool bDontWarn = false);
|
||||
void LoadCustomWeaponsManifest(const char* file, bool bDontWarn = false);
|
||||
|
||||
typedef struct CustomClassName_s
|
||||
{
|
||||
CUtlSymbol sDataFile;
|
||||
IEntityFactory* pNewFactory;
|
||||
IEntityFactory* pOldFactory;
|
||||
} CustomClassName_t;
|
||||
CUtlDict<CustomClassName_t, unsigned short> m_ClassFactories;
|
||||
};
|
||||
|
||||
CCustomWeaponSystem* CustomWeaponSystem();
|
||||
|
||||
template <class T>
|
||||
class CCustomWeaponEntityFactory : public IEntityFactory
|
||||
{
|
||||
public:
|
||||
CCustomWeaponEntityFactory(const char* pFactoryClass)
|
||||
{
|
||||
CustomWeaponsFactoryDictionary().Insert(pFactoryClass, this);
|
||||
}
|
||||
|
||||
IServerNetworkable* Create(const char* pClassName)
|
||||
{
|
||||
T* pEnt = _CreateEntityTemplate((T*)NULL, pClassName);
|
||||
CustomWeaponSystem()->ParseWeapon(pEnt, pClassName);
|
||||
return pEnt->NetworkProp();
|
||||
}
|
||||
|
||||
void Destroy(IServerNetworkable* pNetworkable)
|
||||
{
|
||||
if (pNetworkable)
|
||||
{
|
||||
pNetworkable->Release();
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t GetEntitySize()
|
||||
{
|
||||
return sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_CUSTOM_WEAPON_FACTORY(factoryName, DLLClassName) \
|
||||
static CCustomWeaponEntityFactory<DLLClassName> custom_weapon_##factoryName##_factory( #factoryName );
|
||||
|
||||
#endif // !CUSTOM_WEAPON_FACTORY_H
|
@ -63,6 +63,8 @@ $Project
|
||||
$File "mapbase\ai_grenade.h"
|
||||
$File "mapbase\ai_monitor.cpp"
|
||||
$File "mapbase\ai_weaponmodifier.cpp"
|
||||
$File "mapbase\custom_weapon_factory.cpp"
|
||||
$File "mapbase\custom_weapon_factory.h"
|
||||
$File "mapbase\closecaption_entity.cpp"
|
||||
$File "mapbase\datadesc_mod.cpp"
|
||||
$File "mapbase\datadesc_mod.h"
|
||||
|
@ -76,6 +76,10 @@ public:
|
||||
virtual const char *GetCannonicalName( const char *pClassName );
|
||||
void ReportEntitySizes();
|
||||
|
||||
#ifdef MAPBASE
|
||||
virtual void UninstallFactory(const char* pClassName);
|
||||
#endif // MAPBASE
|
||||
|
||||
private:
|
||||
IEntityFactory *FindFactory( const char *pClassName );
|
||||
public:
|
||||
@ -203,6 +207,11 @@ void CEntityFactoryDictionary::ReportEntitySizes()
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
void CEntityFactoryDictionary::UninstallFactory(const char* pClassName)
|
||||
{
|
||||
m_Factories.Remove(pClassName);
|
||||
}
|
||||
|
||||
int EntityFactory_AutoComplete( const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0 )
|
||||
{
|
||||
CEntityFactoryDictionary *pFactoryDict = (CEntityFactoryDictionary*)EntityFactoryDictionary();
|
||||
|
@ -100,6 +100,9 @@ public:
|
||||
virtual void Destroy( const char *pClassName, IServerNetworkable *pNetworkable ) = 0;
|
||||
virtual IEntityFactory *FindFactory( const char *pClassName ) = 0;
|
||||
virtual const char *GetCannonicalName( const char *pClassName ) = 0;
|
||||
#ifdef MAPBASE
|
||||
virtual void UninstallFactory(const char* pClassName) = 0;
|
||||
#endif // MAPBASE
|
||||
};
|
||||
|
||||
IEntityFactoryDictionary *EntityFactoryDictionary();
|
||||
|
@ -581,6 +581,12 @@ int CWeaponCustomScripted::WeaponMeleeAttack2Condition( float flDot, float flDis
|
||||
|
||||
return BaseClass::WeaponMeleeAttack2Condition( flDot, flDist );
|
||||
}
|
||||
|
||||
DEFINE_CUSTOM_WEAPON_FACTORY(vscript, CWeaponCustomScripted);
|
||||
void CWeaponCustomScripted::ParseCustomFromWeaponFile(const char* pFileName)
|
||||
{
|
||||
Q_FileBase(pFileName, m_iszWeaponScriptName.GetForModify(), 256);
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "basecombatweapon_shared.h"
|
||||
#ifdef CLIENT_DLL
|
||||
#include "vscript_client.h"
|
||||
#else
|
||||
#include "mapbase/custom_weapon_factory.h"
|
||||
#endif
|
||||
|
||||
// The base class of the scripted weapon is game-specific.
|
||||
@ -32,6 +34,9 @@
|
||||
HSCRIPT m_Func_##name;
|
||||
|
||||
class CWeaponCustomScripted : public SCRIPTED_WEAPON_DERIVED_FROM
|
||||
#ifndef CLIENT_DLL
|
||||
, public ICustomWeapon
|
||||
#endif // !CLIENT_DLL
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CWeaponCustomScripted, SCRIPTED_WEAPON_DERIVED_FROM );
|
||||
@ -106,6 +111,9 @@ public:
|
||||
int WeaponRangeAttack2Condition( float flDot, float flDist );
|
||||
int WeaponMeleeAttack1Condition( float flDot, float flDist );
|
||||
int WeaponMeleeAttack2Condition( float flDot, float flDist );
|
||||
|
||||
// Inherited via ICustomWeapon
|
||||
virtual void ParseCustomFromWeaponFile(const char* pFileName) override;
|
||||
#endif
|
||||
|
||||
ALLOW_SCRIPT_ACCESS();
|
||||
|
Loading…
Reference in New Issue
Block a user