Changed model config to key/value format and improved model module features. Model access isn't tested yet, but base stuff works. Minior fixes.
Added more random model selection presets: public, admins, hidden and mother zombies. Simplified ClassFlagFilterMatch logic.
This commit is contained in:
parent
8c1a549239
commit
66ed43dd48
@ -3,28 +3,96 @@
|
|||||||
// ZOMBIE:RELOADED
|
// ZOMBIE:RELOADED
|
||||||
// Model configuration
|
// Model configuration
|
||||||
//
|
//
|
||||||
// Check the weapon configuration section in the manual for detailed info.
|
// See Model Configuration (3.5) section in the manual for detailed info.
|
||||||
//
|
//
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Format:
|
//
|
||||||
// ----------------------------------------------------------------------------
|
// SHORT DESCRIPTIONS
|
||||||
// the/path/to/the/model ;public/hidden/adminonly/etc
|
//
|
||||||
// * ;public - The model will be treated as a model that any client has access to.
|
// Attribute: Description:
|
||||||
// * ;hidden - The model can only be accessed through explicit use of a player class.
|
|
||||||
// E.g. If a class uses the "random" setting for model, then any non-public
|
|
||||||
// models will not be chosen.
|
|
||||||
// ============================================================================
|
|
||||||
// * Each uncommented line will be used as a model path for clients to download,
|
|
||||||
// and classes to utilize.
|
|
||||||
// * If no ;<string> is specified, the model will be assumed as public.
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Defaults:
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
// name Name of model file, without extension.
|
||||||
|
// path Path to model files. MUST end with "/".
|
||||||
|
// team Model type:
|
||||||
|
// "zombies"
|
||||||
|
// "humans"
|
||||||
|
// access Access type:
|
||||||
|
// "public" - Everyone can use the model.
|
||||||
|
// "admins" - Model can only be used by admins.
|
||||||
|
// "hidden" - Model is excluded from public random selections.
|
||||||
|
// "motherzombies" - Model can only be used by mother zombies.
|
||||||
|
// "group" - Use group authentication.
|
||||||
|
// group If access is "group": A SourceMod group name. Otherwise blank ("").
|
||||||
|
|
||||||
models/player/zh/zh_charple001 ;public
|
"models"
|
||||||
models/player/zh/zh_zombie003 ;public
|
{
|
||||||
models/player/zh/zh_corpse002 ;public
|
"zh_charple001"
|
||||||
models/player/ics/hellknight_red/t_guerilla ;public
|
{
|
||||||
// models/player/adminmodels/1337model ;adminonly // None of these models will be randomly chosen.
|
"name" "zh_charple001"
|
||||||
// models/player/donatormodels/donatormodel ;donator
|
"path" "models/player/zh/"
|
||||||
// models/player/hiddenmodels/myhiddenmodel ;non-public
|
"team" "zombies"
|
||||||
|
"access" "public"
|
||||||
|
"group" ""
|
||||||
|
}
|
||||||
|
|
||||||
|
"zh_zombie003"
|
||||||
|
{
|
||||||
|
"name" "zh_zombie003"
|
||||||
|
"path" "models/player/zh/"
|
||||||
|
"team" "zombies"
|
||||||
|
"access" "public"
|
||||||
|
"group" ""
|
||||||
|
}
|
||||||
|
|
||||||
|
"zh_corpse002"
|
||||||
|
{
|
||||||
|
"name" "zh_corpse002"
|
||||||
|
"path" "models/player/zh/"
|
||||||
|
"team" "zombies"
|
||||||
|
"access" "public"
|
||||||
|
"group" ""
|
||||||
|
}
|
||||||
|
|
||||||
|
"t_guerilla"
|
||||||
|
{
|
||||||
|
"name" "t_guerilla"
|
||||||
|
"path" "models/player/ics/hellknight_red/"
|
||||||
|
"team" "zombies"
|
||||||
|
"access" "public"
|
||||||
|
"group" ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special model examples:
|
||||||
|
// -----------------------
|
||||||
|
|
||||||
|
// Only admins can use this zombie model.
|
||||||
|
//"admin_zombie"
|
||||||
|
//{
|
||||||
|
// "name" "1337model"
|
||||||
|
// "path" "models/player/adminmodels/"
|
||||||
|
// "team" "zombies"
|
||||||
|
// "access" "admins"
|
||||||
|
// "group" ""
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Only members of the zr_vip group in SourceMod can use this human model.
|
||||||
|
//"vip_human"
|
||||||
|
//{
|
||||||
|
// "name" "vipmodel"
|
||||||
|
// "path" "models/player/vip/"
|
||||||
|
// "team" "humans"
|
||||||
|
// "access" "group"
|
||||||
|
// "group" "zr_vip"
|
||||||
|
//}
|
||||||
|
|
||||||
|
// This model will be excluded from public random selections. Only classes
|
||||||
|
// that use "randomhidden" or explicit specify this model will be able to use it.
|
||||||
|
//"hidden"
|
||||||
|
//{
|
||||||
|
// "name" "hiddenmodel"
|
||||||
|
// "path" "models/player/"
|
||||||
|
// "team" "humans"
|
||||||
|
// "access" "hidden"
|
||||||
|
// "group" ""
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<p class="headerinfo">Targets plugin version 3.0.0 Beta 2, (not released)<br />
|
<p class="headerinfo">Targets plugin version 3.0.0 Beta 2, (not released)<br />
|
||||||
Written by Richard Helgeby</p>
|
Written by Richard Helgeby</p>
|
||||||
<p class="headerinfo">Manual last modified: 2009.10.31</p>
|
<p class="headerinfo">Manual last modified: 2009.11.17</p>
|
||||||
|
|
||||||
<h2>Index</h2>
|
<h2>Index</h2>
|
||||||
|
|
||||||
@ -747,6 +747,9 @@ configuration files are optional.</p>
|
|||||||
certain maps. That could be scaling knockback, restricting certain weapons, changing class
|
certain maps. That could be scaling knockback, restricting certain weapons, changing class
|
||||||
attributes or changing ambience sound.</p>
|
attributes or changing ambience sound.</p>
|
||||||
|
|
||||||
|
<p>Other map configuration plugins should also work if certain features that doesn't exist in
|
||||||
|
Zombie:Reloaded map configurations is needed.</p>
|
||||||
|
|
||||||
<h4><a name="3.4.1" />1. Types</h4>
|
<h4><a name="3.4.1" />1. Types</h4>
|
||||||
<p>There are two kinds of map configs; pre and post. Pre map configuration files are executed
|
<p>There are two kinds of map configs; pre and post. Pre map configuration files are executed
|
||||||
before the modules and data is loaded. They're useful for changing configuration sets for certain
|
before the modules and data is loaded. They're useful for changing configuration sets for certain
|
||||||
@ -777,57 +780,96 @@ stuff have to be placed in this one to be effective, like changing class attribu
|
|||||||
|
|
||||||
<h3><a name="3.5" />3.5 Model Configuration</h3>
|
<h3><a name="3.5" />3.5 Model Configuration</h3>
|
||||||
|
|
||||||
<p><strong>Note:</strong> Work in progress. Model list data structure is about to be changed
|
<p>The model configuration file is a list of models used on the server stored in Valve's key/value
|
||||||
with support for human models and model restrictions. Currently, assume all models to be public
|
format.</p>
|
||||||
zombie models that everyone can use.</p>
|
|
||||||
|
|
||||||
<p>The model configuration file is a list of models used on the server. Each line contains the path
|
|
||||||
including the model name, but not the file extension.</p>
|
|
||||||
|
|
||||||
<p>The models listed in this file are also precached when the server starts. Custom models used,
|
<p>The models listed in this file are also precached when the server starts. Custom models used,
|
||||||
but not listed in this file will cause a "model not precached" error on the server, so they must be
|
but not listed in this file will cause a "model not precached" error on the server, so they must be
|
||||||
listed in this file.</p>
|
listed in this file.</p>
|
||||||
|
|
||||||
<p>In addition certain flags can be added to mark the model as special, such as only for
|
<p>In addition models can be restricted to certain groups using the "access" attribute.</p>
|
||||||
admins/donators, hidden from random selection or only for mother zombies.</p>
|
|
||||||
|
|
||||||
<p>Each line is separated into two fields with ";". The last field is optional.</p>
|
<p>List of available model attributes:</p>
|
||||||
|
|
||||||
<p>If no flag is specified it's treated as a regular public model.</p>
|
|
||||||
|
|
||||||
<p>Model line syntax:</p>
|
|
||||||
<blockquote><p><code><model path>[; flag]</code></p></blockquote>
|
|
||||||
|
|
||||||
<blockquote><table>
|
<blockquote><table>
|
||||||
<caption>Model Flags</caption>
|
<caption>Model Attributes</caption>
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valueoption">public</td>
|
<th class="namewidth">Attribute:</th>
|
||||||
<td>Everyone can use the model.</td>
|
<th class="mediumwidth">Value type:</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="commandheader">name</td>
|
||||||
|
<td class="commandheader">text</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valueoption">adminonly</td>
|
<td class="indent" colspan="2">
|
||||||
<td>(Incomplete) Can only be used by admins.</td>
|
<p>File name of model file, without extension.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="commandheader">path</td>
|
||||||
|
<td class="commandheader">text</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valueoption">donator</td>
|
<td class="indent" colspan="2">
|
||||||
<td>(Incomplete) Can only be used by donators.</td>
|
<p>Path to model files. <strong>Must</strong> end with "/". Windows servers can use "\"
|
||||||
|
in paths, but they also work with "/".</p>
|
||||||
|
<p>The path is relative to "cstrike".</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="commandheader">team</td>
|
||||||
|
<td class="commandheader">text</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valueoption">hidden</td>
|
<td class="indent" colspan="2">
|
||||||
<td>(Incomplete) Is not included in random selections.</td>
|
<p>What team the model belongs to.</p>
|
||||||
|
<p>Options:</p>
|
||||||
|
<blockquote><table>
|
||||||
|
<tr><td class="valueoption">zombies</td><td>Zombie players. Includes mother zombies.</td></tr>
|
||||||
|
<tr><td class="valueoption">humans</td><td>Human players.</td></tr>
|
||||||
|
</table></blockquote>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="commandheader">access</td>
|
||||||
|
<td class="commandheader">text</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valueoption">motherzombie</td>
|
<td class="indent" colspan="2">
|
||||||
<td>(Incomplete) Can only be used on mother zombies.</td>
|
<p>Access mode of the model.</p>
|
||||||
|
<p>Options:</p>
|
||||||
|
<blockquote><table>
|
||||||
|
<tr><td class="valueoption">public</td><td>Everyone can use the model. Included in
|
||||||
|
public random selections.</td></tr>
|
||||||
|
<tr><td class="valueoption">admins</td><td>Model can only be used by admins. Included
|
||||||
|
in public random selections but only applied to admins.</td></tr>
|
||||||
|
<tr><td class="valueoption">hidden</td><td>Model is excluded from public random selections.</td></tr>
|
||||||
|
<tr><td class="valueoption">motherzombies</td><td>Model can only be used by mother zombies.</td></tr>
|
||||||
|
<tr><td class="valueoption">group</td><td>Use group authentication. See "group" attribute.</td></tr>
|
||||||
|
</table></blockquote>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="commandheader">group</td>
|
||||||
|
<td class="commandheader">text</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="indent" colspan="2">
|
||||||
|
<p>Name of SourceMod group to use for model authentication if access is "group". If
|
||||||
|
access is anything else than "group" this setting is ignored and can be blank ("").</p>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table></blockquote>
|
</table></blockquote>
|
||||||
|
|
||||||
<p>Example usages:</p>
|
<p>For example usages see examples in default model configuration.</p>
|
||||||
|
|
||||||
<blockquote><p><code>models/player/zh/zh_charple001<br />
|
|
||||||
models/player/zh/zh_corpse002; adminonly<br />
|
|
||||||
models/player/zh/zh_zombie003; hidden<br />
|
|
||||||
models/player/ics/hellknight_red/t_guerilla; motherzombie</code></p></blockquote>
|
|
||||||
|
|
||||||
<p>Put the list of models in:</p>
|
<p>Put the list of models in:</p>
|
||||||
|
|
||||||
@ -837,7 +879,7 @@ admins/donators, hidden from random selection or only for mother zombies.</p>
|
|||||||
<h3><a name="3.6" />3.6 Download List</h3>
|
<h3><a name="3.6" />3.6 Download List</h3>
|
||||||
|
|
||||||
<p>Custom models, materials and overlays must be listed in the download list so clients will
|
<p>Custom models, materials and overlays must be listed in the download list so clients will
|
||||||
download them. Use one line per file with paths relative to the "cstrike" folder.</p>
|
download them. Use one line per file, with paths relative to the "cstrike" folder.</p>
|
||||||
|
|
||||||
<p>List files to be downloaded in the following file:</p>
|
<p>List files to be downloaded in the following file:</p>
|
||||||
|
|
||||||
@ -1011,8 +1053,8 @@ the admin-only flag in the <span class="code">flags</span> attribute.</p>
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="indent" colspan="3">
|
<td class="indent" colspan="3">
|
||||||
<p>The model file to use on the player, path is relative to the "cstrike" folder. There
|
<p>Model file path to use on the player, relative to the "cstrike" folder. There are a
|
||||||
are a few special values supported by this attribute:</p>
|
few presets supported by this attribute:</p>
|
||||||
<blockquote><table>
|
<blockquote><table>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valueoption">default</td>
|
<td class="valueoption">default</td>
|
||||||
@ -1020,12 +1062,31 @@ the admin-only flag in the <span class="code">flags</span> attribute.</p>
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valueoption">random</td>
|
<td class="valueoption">random</td>
|
||||||
<td>Selects a random model for the current team.</td>
|
<td>Selects a random public or admin model for the current team. Admin models
|
||||||
|
are only applied to admins.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valueoption">nochange</td>
|
<td class="valueoption">random_public</td>
|
||||||
<td>Don't change model. To be used in combination with other plugins that
|
<td>Selects a random public model for the current team.</td>
|
||||||
change model on players.</td>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="valueoption">random_admin</td>
|
||||||
|
<td>Selects a random admin model for the current team. Model permissions will
|
||||||
|
be ignored.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="valueoption">random_hidden</td>
|
||||||
|
<td>Selects a random hidden model for the current team.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="valueoption">random_mother_zombie</td>
|
||||||
|
<td><strong>Zombies only.</strong> Selects a random mother zombie model.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="valueoption">no_change</td>
|
||||||
|
<td>Don't change model. Use this setting to keep default Counter-Strike: Source
|
||||||
|
model, or to fix a compatibility issue with other plugins that change model on
|
||||||
|
players.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table></blockquote>
|
</table></blockquote>
|
||||||
</td>
|
</td>
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
|
|
||||||
// Header includes.
|
// Header includes.
|
||||||
#include "zr/log.h"
|
#include "zr/log.h"
|
||||||
|
#include "zr/models.h"
|
||||||
|
|
||||||
#if defined ADD_VERSION_INFO
|
#if defined ADD_VERSION_INFO
|
||||||
#include "zr/hgversion.h"
|
#include "zr/hgversion.h"
|
||||||
@ -79,10 +80,10 @@
|
|||||||
#include "zr/paramtools"
|
#include "zr/paramtools"
|
||||||
#include "zr/paramparser"
|
#include "zr/paramparser"
|
||||||
#include "zr/shoppinglist"
|
#include "zr/shoppinglist"
|
||||||
#include "zr/models"
|
|
||||||
#include "zr/downloads"
|
#include "zr/downloads"
|
||||||
#include "zr/overlays"
|
#include "zr/overlays"
|
||||||
#include "zr/playerclasses/playerclasses"
|
#include "zr/playerclasses/playerclasses"
|
||||||
|
#include "zr/models"
|
||||||
#include "zr/weapons/weapons"
|
#include "zr/weapons/weapons"
|
||||||
#include "zr/hitgroups"
|
#include "zr/hitgroups"
|
||||||
#include "zr/roundstart"
|
#include "zr/roundstart"
|
||||||
|
88
src/zr/models.h.inc
Normal file
88
src/zr/models.h.inc
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* ============================================================================
|
||||||
|
*
|
||||||
|
* Zombie:Reloaded
|
||||||
|
*
|
||||||
|
* File: models.h.inc
|
||||||
|
* Type: Core
|
||||||
|
* Description: Model data structures and constants.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Greyscale, Richard Helgeby
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* ============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of models.
|
||||||
|
*/
|
||||||
|
#define MODELS_MAX 48
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum folder depth a model file can be located.
|
||||||
|
*/
|
||||||
|
#define MODELS_PATH_MAX_DEPTH 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum string length of a folder a model file is located under.
|
||||||
|
*/
|
||||||
|
#define MODELS_PATH_DIR_MAX_LENGTH 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model access settings.
|
||||||
|
*/
|
||||||
|
enum ModelAccess
|
||||||
|
{
|
||||||
|
ModelAccess_Invalid = -1, /* Invalid access type. */
|
||||||
|
ModelAccess_Public = 0, /* Everyone can use the model. */
|
||||||
|
ModelAccess_Admins, /* Model can only be used by admins. */
|
||||||
|
ModelAccess_Hidden, /* Model is excluded from public random selections. */
|
||||||
|
ModelAccess_MotherZombies, /* Only mother zombies can use this model. */
|
||||||
|
ModelAccess_Group /* Enables group authentication. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @section Model access flags.
|
||||||
|
*/
|
||||||
|
#define MODEL_ACCESS_PUBLIC (1<<0)
|
||||||
|
#define MODEL_ACCESS_ADMINS (1<<1)
|
||||||
|
#define MODEL_ACCESS_HIDDEN (1<<2)
|
||||||
|
#define MODEL_ACCESS_MOTHER_ZOMBIES (1<<3)
|
||||||
|
#define MODEL_ACCESS_GROUP (1<<4)
|
||||||
|
/**
|
||||||
|
* @endsection
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Avaliable teams for models.
|
||||||
|
*/
|
||||||
|
enum ModelTeam
|
||||||
|
{
|
||||||
|
ModelTeam_Invalid = -1,
|
||||||
|
ModelTeam_Zombies = 0,
|
||||||
|
ModelTeam_Humans
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model settings structure.
|
||||||
|
*/
|
||||||
|
enum ModelAttributes
|
||||||
|
{
|
||||||
|
String:Model_Name[64], /* File name of model (no file extension). */
|
||||||
|
String:Model_Path[PLATFORM_MAX_PATH], /* Path to model files. */
|
||||||
|
ModelTeam:Model_Team, /* What team the model belongs to. */
|
||||||
|
ModelAccess:Model_Access, /* Access settings. */
|
||||||
|
String:Model_Group[64] /* Group authentication (if used). */
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* File: models.inc
|
* File: models.inc
|
||||||
* Type: Core
|
* Type: Core
|
||||||
* Description: Model validation.
|
* Description: Model manager.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009 Greyscale, Richard Helgeby
|
* Copyright (C) 2009 Greyscale, Richard Helgeby
|
||||||
*
|
*
|
||||||
@ -25,173 +25,208 @@
|
|||||||
* ============================================================================
|
* ============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Maximum folder depth a model file can be located.
|
* Note: Data structures and constants defined in models.h.inc.
|
||||||
*/
|
*/
|
||||||
#define MODELS_PATH_MAX_DEPTH 8
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum string length of a folder a model file is located under.
|
* Parsed model data.
|
||||||
*/
|
*/
|
||||||
#define MODELS_PATH_DIR_MAX_LENGTH 32
|
new ModelData[MODELS_MAX][ModelAttributes];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array that stores a list of validated models.
|
* Number of valid models.
|
||||||
*/
|
*/
|
||||||
new Handle:arrayModels = INVALID_HANDLE;
|
new ModelCount;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare all model/download data.
|
* Prepare all model/download data.
|
||||||
*/
|
*/
|
||||||
ModelsLoad()
|
ModelsLoad()
|
||||||
{
|
{
|
||||||
|
new Handle:kvModels = INVALID_HANDLE;
|
||||||
|
|
||||||
// Register config file.
|
// Register config file.
|
||||||
ConfigRegisterConfig(File_Models, Structure_List, CONFIG_FILE_ALIAS_MODELS);
|
ConfigRegisterConfig(File_Models, Structure_List, CONFIG_FILE_ALIAS_MODELS);
|
||||||
|
|
||||||
// Get models file path.
|
// Get models file path.
|
||||||
decl String:pathmodels[PLATFORM_MAX_PATH];
|
decl String:modelPath[PLATFORM_MAX_PATH];
|
||||||
new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_MODELS, pathmodels);
|
new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_MODELS, modelPath);
|
||||||
|
|
||||||
// If file doesn't exist, then log and stop.
|
// If file doesn't exist, then log and stop.
|
||||||
if (!exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
// Log failure and stop plugin.
|
// Log failure and stop plugin.
|
||||||
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Missing models file: \"%s\"", pathmodels);
|
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Missing model list: \"%s\"", modelPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the path to the config file.
|
// Set the path to the config file.
|
||||||
ConfigSetConfigPath(File_Models, pathmodels);
|
ConfigSetConfigPath(File_Models, modelPath);
|
||||||
|
|
||||||
// Load config from file and create array structure.
|
// Prepare key/value structure.
|
||||||
new bool:success = ConfigLoadConfig(File_Models, arrayModels, PLATFORM_MAX_PATH);
|
kvModels = CreateKeyValues(CONFIG_FILE_ALIAS_MODELS);
|
||||||
|
|
||||||
// Unexpected error, stop plugin.
|
// Log what models file that is loaded.
|
||||||
if (!success)
|
LogEvent(false, LogType_Normal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Loading models from file \"%s\".", modelPath);
|
||||||
|
|
||||||
|
// Load model data file.
|
||||||
|
FileToKeyValues(kvModels, modelPath);
|
||||||
|
|
||||||
|
// Try to find the first model.
|
||||||
|
KvRewind(kvModels);
|
||||||
|
if (!KvGotoFirstSubKey(kvModels))
|
||||||
{
|
{
|
||||||
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Unexpected error encountered loading: %s", pathmodels);
|
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Can't find any models in \"%s\"", modelPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
new modelcount;
|
decl String:buffer[256];
|
||||||
new modelpublicvalidcount;
|
decl String:name[64];
|
||||||
new modelnonpublicvalidcount;
|
decl String:path[PLATFORM_MAX_PATH];
|
||||||
new modelfilecount;
|
decl String:team[64];
|
||||||
|
decl String:access[64];
|
||||||
|
decl String:group[64];
|
||||||
|
|
||||||
decl String:modelbase[PLATFORM_MAX_PATH];
|
ModelCount = 0;
|
||||||
decl String:modelpath[PLATFORM_MAX_PATH];
|
new failedCount;
|
||||||
decl String:modelname[MODELS_PATH_DIR_MAX_LENGTH];
|
new publicCount;
|
||||||
decl String:modelfile[MODELS_PATH_DIR_MAX_LENGTH];
|
|
||||||
decl String:modeldiskname[MODELS_PATH_DIR_MAX_LENGTH];
|
|
||||||
decl String:modelfullpath[PLATFORM_MAX_PATH];
|
|
||||||
|
|
||||||
new String:baseexploded[MODELS_PATH_MAX_DEPTH][MODELS_PATH_DIR_MAX_LENGTH];
|
// Loop through all models and store attributes in ModelData array.
|
||||||
|
do
|
||||||
new FileType:type;
|
|
||||||
|
|
||||||
new models = modelcount = GetArraySize(arrayModels);
|
|
||||||
|
|
||||||
// x = model array index.
|
|
||||||
for (new x = 0; x < models; x++)
|
|
||||||
{
|
{
|
||||||
// Get base model path, excluding the public/non-public setting.
|
if (ModelCount > MODELS_MAX)
|
||||||
ModelReturnPath(x, modelbase, sizeof(modelbase));
|
|
||||||
|
|
||||||
// Explode path into pieces. (separated by "/")
|
|
||||||
new strings = ExplodeString(modelbase, "/", baseexploded, sizeof(baseexploded), sizeof(baseexploded[]));
|
|
||||||
|
|
||||||
// Get model file name.
|
|
||||||
strcopy(modelname, sizeof(modelname), baseexploded[strings - 1]);
|
|
||||||
|
|
||||||
// Get the path to the file.
|
|
||||||
// Works by truncating original path by the length of the file name.
|
|
||||||
strcopy(modelpath, strlen(modelbase) - strlen(modelname), modelbase);
|
|
||||||
|
|
||||||
// Open dir containing model files.
|
|
||||||
new Handle:modeldir = OpenDirectory(modelpath);
|
|
||||||
|
|
||||||
if (modeldir == INVALID_HANDLE)
|
|
||||||
{
|
{
|
||||||
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Error opening model path directory: %s", modelpath);
|
// Maximum number of models reached. Log a warning and exit the loop.
|
||||||
|
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Warning: Maximum number of models reached (%d). Skipping other models.", MODELS_MAX + 1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
KvGetString(kvModels, "name", name, sizeof(name));
|
||||||
|
strcopy(ModelData[ModelCount][Model_Name], 64, name);
|
||||||
|
|
||||||
|
KvGetString(kvModels, "path", path, sizeof(path));
|
||||||
|
strcopy(ModelData[ModelCount][Model_Path], 64, path);
|
||||||
|
|
||||||
|
KvGetString(kvModels, "team", team, sizeof(team));
|
||||||
|
ModelData[ModelCount][Model_Team] = ModelsStringToTeam(team);
|
||||||
|
|
||||||
|
KvGetString(kvModels, "access", access, sizeof(access));
|
||||||
|
ModelData[ModelCount][Model_Access] = ModelsStringToAccess(access);
|
||||||
|
|
||||||
|
KvGetString(kvModels, "group", group, sizeof(group));
|
||||||
|
strcopy(ModelData[ModelCount][Model_Group], 64, group);
|
||||||
|
|
||||||
|
|
||||||
|
// Validate model attributes.
|
||||||
|
|
||||||
|
// Build path and check if model file exist.
|
||||||
|
strcopy(buffer, sizeof(buffer), path);
|
||||||
|
StrCat(buffer, sizeof(buffer), name);
|
||||||
|
StrCat(buffer, sizeof(buffer), ".mdl");
|
||||||
|
if (!FileExists(buffer))
|
||||||
|
{
|
||||||
|
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Warning: Invalid model name/path setting at index %d. File not found: \"%s\".", ModelCount + failedCount, buffer);
|
||||||
|
failedCount++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset model file count.
|
// Validate team.
|
||||||
modelfilecount = 0;
|
if (ModelData[ModelCount][Model_Team] == ModelTeam_Invalid)
|
||||||
|
|
||||||
while (ReadDirEntry(modeldir, modelfile, sizeof(modelfile), type))
|
|
||||||
{
|
{
|
||||||
// If entry isn't a file, then stop.
|
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Warning: Invalid model team setting at index %d: \"%s\".", ModelCount + failedCount, team);
|
||||||
|
failedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate access.
|
||||||
|
if (ModelData[ModelCount][Model_Access] == ModelAccess_Invalid)
|
||||||
|
{
|
||||||
|
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Warning: Invalid model access setting at index %d: \"%s\".", ModelCount + failedCount, access);
|
||||||
|
failedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Increment public model counter.
|
||||||
|
if (ModelData[ModelCount][Model_Access] == ModelAccess_Public)
|
||||||
|
{
|
||||||
|
publicCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate group.
|
||||||
|
if (ModelData[ModelCount][Model_Access] == ModelAccess_Group &&
|
||||||
|
FindAdmGroup(group) == INVALID_GROUP_ID)
|
||||||
|
{
|
||||||
|
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Warning: Invalid model group setting at index %d. Couldn't find SourceMod group \"%s\".", ModelCount + failedCount, group);
|
||||||
|
failedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open directory with model files.
|
||||||
|
new Handle:dir = OpenDirectory(path);
|
||||||
|
|
||||||
|
// Check if failed.
|
||||||
|
if (dir == INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Error opening directory: %s", dir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
new FileType:type;
|
||||||
|
decl String:file[64];
|
||||||
|
decl String:fileShort[64];
|
||||||
|
|
||||||
|
// Search for model files with the specified name and add them to
|
||||||
|
// downloads table.
|
||||||
|
while (ReadDirEntry(dir, file, sizeof(file), type))
|
||||||
|
{
|
||||||
|
// Skip if entry isn't a file.
|
||||||
if (type != FileType_File)
|
if (type != FileType_File)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find break point index in the string to get model name.
|
// Find break point index in the string to get model name.
|
||||||
// Add one because it seems to break on the character before.
|
// Add one to make space for null terminator.
|
||||||
new breakpoint = FindCharInString(modelfile, '.') + 1;
|
new breakpoint = FindCharInString(file, '.') + 1;
|
||||||
strcopy(modeldiskname, breakpoint, modelfile);
|
strcopy(fileShort, breakpoint, file);
|
||||||
|
|
||||||
// If this file doesn't match, then stop.
|
// If this file doesn't match model name, then skip it.
|
||||||
if (!StrEqual(modelname, modeldiskname, false))
|
if (!StrEqual(name, fileShort, false))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format a full path string.
|
// Format a full path string.
|
||||||
strcopy(modelfullpath, sizeof(modelfullpath), modelpath);
|
strcopy(buffer, sizeof(buffer), path);
|
||||||
Format(modelfullpath, sizeof(modelfullpath), "%s/%s", modelfullpath, modelfile);
|
Format(buffer, sizeof(buffer), "%s%s", buffer, file);
|
||||||
|
|
||||||
// Precache model file and add to downloads table.
|
// Precache model file and add to downloads table.
|
||||||
PrecacheModel(modelfullpath);
|
PrecacheModel(buffer);
|
||||||
AddFileToDownloadsTable(modelfullpath);
|
AddFileToDownloadsTable(buffer);
|
||||||
|
|
||||||
// Increment modelfilecount
|
|
||||||
modelfilecount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(modeldir);
|
CloseHandle(dir);
|
||||||
|
|
||||||
// Increment variable if model files are valid.
|
ModelCount++;
|
||||||
if (modelfilecount)
|
} while (KvGotoNextKey(kvModels));
|
||||||
|
|
||||||
|
CloseHandle(kvModels);
|
||||||
|
|
||||||
|
// Check if there are no public models.
|
||||||
|
if (!publicCount)
|
||||||
{
|
{
|
||||||
// Increment proper variable.
|
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Couldn't find any public model in \"%s\". There must be at least one public model.", modelPath);
|
||||||
if (ModelIsPublic(x))
|
|
||||||
{
|
|
||||||
modelpublicvalidcount++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
modelnonpublicvalidcount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Remove client from array.
|
|
||||||
RemoveFromArray(arrayModels, x);
|
|
||||||
|
|
||||||
// Subtract one from count.
|
|
||||||
models--;
|
|
||||||
|
|
||||||
// Backtrack one index, because we deleted it out from under the loop.
|
|
||||||
x--;
|
|
||||||
|
|
||||||
// Log missing model files.
|
|
||||||
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Missing model files on server (%s)", modelbase);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log model validation info.
|
// Log model validation info.
|
||||||
LogEvent(false, LogType_Normal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Total: %d | Successful Public: %d | Successful Non-Public: %d | Unsuccessful: %d", modelcount, modelpublicvalidcount, modelnonpublicvalidcount, modelcount - (modelpublicvalidcount + modelnonpublicvalidcount));
|
LogEvent(false, LogType_Normal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Successful: %d | Unsuccessful: %d", ModelCount, failedCount);
|
||||||
|
|
||||||
// If none of the model paths are valid, then log and fail.
|
|
||||||
if (!modelpublicvalidcount)
|
|
||||||
{
|
|
||||||
LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "No usable (public) model paths in %s", pathmodels);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set config data.
|
// Set config data.
|
||||||
ConfigSetConfigLoaded(File_Models, true);
|
ConfigSetConfigLoaded(File_Models, true);
|
||||||
ConfigSetConfigReloadFunc(File_Models, GetFunctionByName(GetMyHandle(), "ModelsOnConfigReload"));
|
ConfigSetConfigReloadFunc(File_Models, GetFunctionByName(GetMyHandle(), "ModelsOnConfigReload"));
|
||||||
ConfigSetConfigHandle(File_Models, arrayModels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,120 +239,336 @@ public ModelsOnConfigReload(ConfigFile:config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a model is public.
|
* Returns a random model index according to the specified filter settings.
|
||||||
*
|
*
|
||||||
* @param modelindex The array index of the model to check.
|
* @param client Optional. Client index used to check for
|
||||||
* @return True if public, false if not.
|
* permissions in "group" or "admins" access mode.
|
||||||
|
* Use negative index to disable permission check
|
||||||
|
* (default).
|
||||||
|
* @param teamFilter Optional. Team filtering settings. Use
|
||||||
|
* ModelTeam_Invalid to disable filter. Default is
|
||||||
|
* ModelTeam_Zombies.
|
||||||
|
* @param accessRequireFlags Optional. One or more required access flags.
|
||||||
|
* Default is MODEL_ACCESS_PUBLIC.
|
||||||
|
* @return Random model index according to filter, or -1 on error.
|
||||||
*/
|
*/
|
||||||
stock bool:ModelIsPublic(modelindex)
|
ModelsGetRandomModel(client = -1, ModelTeam:teamFilter = ModelTeam_Zombies, accessRequireFlags = MODEL_ACCESS_PUBLIC)
|
||||||
{
|
{
|
||||||
// Get the entire model string to parse for what we need.
|
decl modelIndexes[MODELS_MAX];
|
||||||
decl String:modelsetting[PLATFORM_MAX_PATH + 16];
|
new listCount;
|
||||||
GetArrayString(arrayModels, modelindex, modelsetting, sizeof(modelsetting));
|
|
||||||
|
|
||||||
// We define this to use as little memory as possible, because the value won't be used.
|
// Loop through all models.
|
||||||
decl String:modelpath[1];
|
for (new index = 0; index < ModelCount; index++)
|
||||||
decl String:strpublic[32];
|
|
||||||
|
|
||||||
if (StrContains(modelsetting, ";") > -1)
|
|
||||||
{
|
{
|
||||||
// Get string index of where the public setting starts.
|
// Check team filtering. Skip if no match.
|
||||||
new strindex = SplitString(modelsetting, ";", modelpath, sizeof(modelpath));
|
if (teamFilter != ModelTeam_Invalid &&
|
||||||
|
ModelsGetTeam(index) != teamFilter)
|
||||||
// Copy setting to new string
|
{
|
||||||
strcopy(strpublic, sizeof(strpublic), modelsetting[strindex]);
|
continue;
|
||||||
|
|
||||||
// Trim the whitespace.
|
|
||||||
TrimString(strpublic);
|
|
||||||
|
|
||||||
// If public, return true, non-public returns false.
|
|
||||||
return StrEqual(strpublic, "public", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If nothing is specified, assume public.
|
// Cache current model access flag.
|
||||||
return true;
|
new ModelAccess:access = ModelsGetAccess(index);
|
||||||
}
|
new accessFlag = ModelsGetAccessFlag(access);
|
||||||
|
|
||||||
/**
|
// Check access filtering. Skip if no match.
|
||||||
* Returns the path of a given model index.
|
if (accessRequireFlags > 0 &&
|
||||||
*
|
!(accessRequireFlags & accessFlag))
|
||||||
* @param modelindex The array index of the model.
|
|
||||||
* @param modelpath The output string of the model path.
|
|
||||||
* @param maxlen The maximum length of the output string.
|
|
||||||
*/
|
|
||||||
stock ModelReturnPath(modelindex, String:modelpath[], maxlen)
|
|
||||||
{
|
|
||||||
// Get the entire model string to parse for what we need.
|
|
||||||
decl String:modelsetting[PLATFORM_MAX_PATH + 16];
|
|
||||||
GetArrayString(arrayModels, modelindex, modelsetting, sizeof(modelsetting));
|
|
||||||
|
|
||||||
// Copy to path before split just in case the string has no ";"
|
|
||||||
strcopy(modelpath, maxlen, modelsetting);
|
|
||||||
if (StrContains(modelsetting, ";") > -1)
|
|
||||||
{
|
{
|
||||||
SplitString(modelsetting, ";", modelpath, maxlen);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim whitespace.
|
// Do client group authentication if client is specified.
|
||||||
TrimString(modelpath);
|
if (client > 0)
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a random model index in arrayModels, allows you to specify a filter.
|
|
||||||
*
|
|
||||||
* @param modelpath The output string of the model path.
|
|
||||||
* @param maxlen The maximum length of the output string.
|
|
||||||
* @param all True to choose any of the models in the file, false to use 'publicmodels' param.
|
|
||||||
* @param publicmodels True to find a random public model, false to find non-public.
|
|
||||||
*/
|
|
||||||
stock ModelsGetRandomModelIndex(String:modelpath[], maxlen, bool:all = true, bool:publicmodels = true)
|
|
||||||
{
|
|
||||||
new modelindex = -1;
|
|
||||||
|
|
||||||
// Return any random model.
|
|
||||||
if (all)
|
|
||||||
{
|
{
|
||||||
// Get random model index and return the string in it.
|
// Check if current model use group authentication.
|
||||||
modelindex = GetRandomInt(0, GetArraySize(arrayModels) - 1);
|
if (access == ModelAccess_Group)
|
||||||
|
{
|
||||||
|
decl String:group[64];
|
||||||
|
ModelsGetGroup(index, group, sizeof(group));
|
||||||
|
|
||||||
|
if (!ZRIsClientInGroup(client, group))
|
||||||
|
{
|
||||||
|
// Client not authorized to use this model.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new Handle:modelsarray = CreateArray(PLATFORM_MAX_PATH);
|
// No group authentication. Do regular authentication if model
|
||||||
decl String:modelsetting[PLATFORM_MAX_PATH];
|
// is a admin model.
|
||||||
|
if (access == ModelAccess_Admins &&
|
||||||
// x = Array index.
|
!ZRIsClientAdmin(client))
|
||||||
new size = GetArraySize(arrayModels);
|
|
||||||
for (new x = 0; x < size; x++)
|
|
||||||
{
|
{
|
||||||
if (publicmodels == ModelIsPublic(x))
|
// Client not authorized to use this model.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Model passed filter tests. Add to list.
|
||||||
|
modelIndexes[listCount] = index;
|
||||||
|
listCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any models passed the filter.
|
||||||
|
if (listCount)
|
||||||
{
|
{
|
||||||
// Transfer model to temp array.
|
return modelIndexes[GetRandomInt(0, listCount - 1)];
|
||||||
GetArrayString(arrayModels, x, modelsetting, sizeof(modelsetting));
|
|
||||||
PushArrayString(modelsarray, modelsetting);
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
// y = Array index.
|
|
||||||
size = GetArraySize(modelsarray);
|
|
||||||
|
|
||||||
// If there are no models then copy a blank string to the output.
|
|
||||||
if (size == 0)
|
|
||||||
{
|
{
|
||||||
strcopy(modelpath, maxlen, "");
|
return -1;
|
||||||
|
|
||||||
// Destroy the handle.
|
|
||||||
CloseHandle(modelsarray);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Get random model index from the temp list, and return the string in it.
|
|
||||||
modelindex = GetRandomInt(0, GetArraySize(modelsarray) - 1);
|
/**
|
||||||
|
* Validates the specified index according to maximum number of models, and
|
||||||
// Destroy the handle.
|
* number of models in use. Unused indexes will fail validation by default.
|
||||||
CloseHandle(modelsarray);
|
*
|
||||||
}
|
* @param index Model index to validate.
|
||||||
|
* @param rangeOnly Optional. Do not check if the index is in use. Default
|
||||||
// Get the path to the selected model.
|
* is false, check if in use.
|
||||||
ModelReturnPath(modelindex, modelpath, maxlen);
|
* @return True if valid, false otherwise.
|
||||||
|
*/
|
||||||
|
bool:ModelsIsValidIndex(index, bool:rangeOnly = false)
|
||||||
|
{
|
||||||
|
new bool:rangeValid = (index >= 0 && index < MODELS_MAX);
|
||||||
|
|
||||||
|
if (rangeOnly)
|
||||||
|
{
|
||||||
|
// Only check if the index is valid.
|
||||||
|
return rangeValid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check if the index is valid, and if it's in use.
|
||||||
|
return rangeValid && (index < ModelCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name for the specified model.
|
||||||
|
*
|
||||||
|
* @param index Model index.
|
||||||
|
* @param buffer Destination string buffer.
|
||||||
|
* @param maxlen Size of buffer.
|
||||||
|
* @return Number of cells written, or -1 on error.
|
||||||
|
*/
|
||||||
|
ModelsGetName(index, String:buffer[], maxlen)
|
||||||
|
{
|
||||||
|
// Validate index.
|
||||||
|
if (!ModelsIsValidIndex(index))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strcopy(buffer, maxlen, ModelData[index][Model_Name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the path for the specified model.
|
||||||
|
*
|
||||||
|
* @param index Model index.
|
||||||
|
* @param buffer Destination string buffer.
|
||||||
|
* @param maxlen Size of buffer.
|
||||||
|
* @return Number of cells written, or -1 on error.
|
||||||
|
*/
|
||||||
|
ModelsGetPath(index, String:buffer[], maxlen)
|
||||||
|
{
|
||||||
|
// Validate index.
|
||||||
|
if (!ModelsIsValidIndex(index))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strcopy(buffer, maxlen, ModelData[index][Model_Path]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the team for the specified model.
|
||||||
|
*
|
||||||
|
* @param index Model index.
|
||||||
|
* @return Team for the specified model, ModelTeam_Invalid on error.
|
||||||
|
*/
|
||||||
|
ModelTeam:ModelsGetTeam(index)
|
||||||
|
{
|
||||||
|
// Validate index.
|
||||||
|
if (!ModelsIsValidIndex(index))
|
||||||
|
{
|
||||||
|
return ModelTeam_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModelData[index][Model_Team];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the access setting for the specified model.
|
||||||
|
*
|
||||||
|
* @param index Model index.
|
||||||
|
* @return Access setting for the specified model, ModelAccess_Invalid
|
||||||
|
* on error.
|
||||||
|
*/
|
||||||
|
ModelAccess:ModelsGetAccess(index)
|
||||||
|
{
|
||||||
|
// Validate index.
|
||||||
|
if (!ModelsIsValidIndex(index))
|
||||||
|
{
|
||||||
|
return ModelAccess_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModelData[index][Model_Access];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the access flag for the specified access setting.
|
||||||
|
*
|
||||||
|
* @param access Access setting to convert.
|
||||||
|
* @return Access flag, or 0 on error.
|
||||||
|
*/
|
||||||
|
ModelsGetAccessFlag(ModelAccess:access)
|
||||||
|
{
|
||||||
|
switch (access)
|
||||||
|
{
|
||||||
|
case ModelAccess_Public:
|
||||||
|
{
|
||||||
|
return MODEL_ACCESS_PUBLIC;
|
||||||
|
}
|
||||||
|
case ModelAccess_Admins:
|
||||||
|
{
|
||||||
|
return MODEL_ACCESS_ADMINS;
|
||||||
|
}
|
||||||
|
case ModelAccess_Hidden:
|
||||||
|
{
|
||||||
|
return MODEL_ACCESS_HIDDEN;
|
||||||
|
}
|
||||||
|
case ModelAccess_MotherZombies:
|
||||||
|
{
|
||||||
|
return MODEL_ACCESS_MOTHER_ZOMBIES;
|
||||||
|
}
|
||||||
|
case ModelAccess_Group:
|
||||||
|
{
|
||||||
|
return MODEL_ACCESS_GROUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid access flag.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the group for the specified model.
|
||||||
|
*
|
||||||
|
* @param index Model index.
|
||||||
|
* @param buffer Destination string buffer.
|
||||||
|
* @param maxlen Size of buffer.
|
||||||
|
* @return Number of cells written, or -1 on error.
|
||||||
|
*/
|
||||||
|
ModelsGetGroup(index, String:buffer[], maxlen)
|
||||||
|
{
|
||||||
|
// Validate index.
|
||||||
|
if (!ModelsIsValidIndex(index))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strcopy(buffer, maxlen, ModelData[index][Model_Group]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the full model file path for the specified model.
|
||||||
|
*
|
||||||
|
* @param index Model index.
|
||||||
|
* @param buffer Destination string buffer.
|
||||||
|
* @param maxlen Size of buffer.
|
||||||
|
* @return Number of cells written, or -1 on error.
|
||||||
|
*/
|
||||||
|
ModelsGetFullPath(index, String:buffer[], maxlen)
|
||||||
|
{
|
||||||
|
decl String:path[PLATFORM_MAX_PATH];
|
||||||
|
decl String:name[64];
|
||||||
|
|
||||||
|
ModelsGetPath(index, path, sizeof(path));
|
||||||
|
ModelsGetName(index, name, sizeof(name));
|
||||||
|
|
||||||
|
buffer[0] = 0;
|
||||||
|
|
||||||
|
StrCat(buffer, maxlen, path);
|
||||||
|
StrCat(buffer, maxlen, name);
|
||||||
|
StrCat(buffer, maxlen, ".mdl");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the specified string to a team setting.
|
||||||
|
*
|
||||||
|
* @param team String to convert.
|
||||||
|
* @return Team setting, or ModelTeam_Invalid on error.
|
||||||
|
*/
|
||||||
|
ModelTeam:ModelsStringToTeam(const String:team[])
|
||||||
|
{
|
||||||
|
if (StrEqual(team, "zombies", false))
|
||||||
|
{
|
||||||
|
return ModelTeam_Zombies;
|
||||||
|
}
|
||||||
|
else if (StrEqual(team, "humans", false))
|
||||||
|
{
|
||||||
|
return ModelTeam_Humans;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModelTeam_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the specified class team ID to a team setting.
|
||||||
|
*
|
||||||
|
* @param teamid Class team ID.
|
||||||
|
* @return Team setting, or ModelTeam_Invalid on error.
|
||||||
|
*/
|
||||||
|
ModelTeam:ModelsTeamIdToTeam(teamid)
|
||||||
|
{
|
||||||
|
switch (teamid)
|
||||||
|
{
|
||||||
|
case ZR_CLASS_TEAM_ZOMBIES:
|
||||||
|
{
|
||||||
|
return ModelTeam_Zombies;
|
||||||
|
}
|
||||||
|
case ZR_CLASS_TEAM_HUMANS:
|
||||||
|
{
|
||||||
|
return ModelTeam_Humans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModelTeam_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the specified string to a access setting.
|
||||||
|
*
|
||||||
|
* @param access String to convert.
|
||||||
|
* @return Access setting, or ModelAccess_Invalid on error.
|
||||||
|
*/
|
||||||
|
ModelAccess:ModelsStringToAccess(const String:access[])
|
||||||
|
{
|
||||||
|
if (StrEqual(access, "public", false))
|
||||||
|
{
|
||||||
|
return ModelAccess_Public;
|
||||||
|
}
|
||||||
|
else if (StrEqual(access, "admins", false))
|
||||||
|
{
|
||||||
|
return ModelAccess_Admins;
|
||||||
|
}
|
||||||
|
else if (StrEqual(access, "hidden", false))
|
||||||
|
{
|
||||||
|
return ModelAccess_Hidden;
|
||||||
|
}
|
||||||
|
else if (StrEqual(access, "motherzombies", false))
|
||||||
|
{
|
||||||
|
return ModelAccess_MotherZombies;
|
||||||
|
}
|
||||||
|
else if (StrEqual(access, "group", false))
|
||||||
|
{
|
||||||
|
return ModelAccess_Group;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModelAccess_Invalid;
|
||||||
}
|
}
|
||||||
|
@ -77,24 +77,64 @@ bool:ClassApplyAttributes(client, bool:improved = false)
|
|||||||
*/
|
*/
|
||||||
bool:ClassApplyModel(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER)
|
bool:ClassApplyModel(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER)
|
||||||
{
|
{
|
||||||
|
new bool:isAttributePreset = false;
|
||||||
decl String:modelpath[PLATFORM_MAX_PATH];
|
decl String:modelpath[PLATFORM_MAX_PATH];
|
||||||
|
new index;
|
||||||
|
new ModelTeam:team;
|
||||||
|
new access;
|
||||||
|
new model;
|
||||||
|
|
||||||
// Get the model path from the specified cache.
|
// Get correct index according to cache type.
|
||||||
if (cachetype == ZR_CLASS_CACHE_PLAYER)
|
if (cachetype == ZR_CLASS_CACHE_PLAYER)
|
||||||
{
|
{
|
||||||
ClassGetModelPath(client, modelpath, sizeof(modelpath), cachetype);
|
index = client;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ClassGetModelPath(classindex, modelpath, sizeof(modelpath), cachetype);
|
index = classindex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user specified a pre-defined model setting.
|
// Get the model path from the specified cache.
|
||||||
|
ClassGetModelPath(index, modelpath, sizeof(modelpath), cachetype);
|
||||||
|
|
||||||
|
// Get model team setting from the specified cache.
|
||||||
|
team = ModelsTeamIdToTeam(ClassGetTeamID(index, cachetype));
|
||||||
|
|
||||||
|
// Check if the user specified a pre-defined model setting. If so, setup
|
||||||
|
// model filter settings.
|
||||||
if (StrEqual(modelpath, "random", false))
|
if (StrEqual(modelpath, "random", false))
|
||||||
{
|
{
|
||||||
// TODO: Make a function that gets a random model from the specified team.
|
// Set access filter flags.
|
||||||
ModelsGetRandomModelIndex(modelpath, sizeof(modelpath), false, true);
|
access = MODEL_ACCESS_PUBLIC | MODEL_ACCESS_ADMINS;
|
||||||
Format(modelpath, sizeof(modelpath), "%s.mdl", modelpath);
|
|
||||||
|
// Specify client for including admin models if client is admin.
|
||||||
|
index = client;
|
||||||
|
|
||||||
|
isAttributePreset = true;
|
||||||
|
}
|
||||||
|
else if (StrEqual(modelpath, "random_public", false))
|
||||||
|
{
|
||||||
|
access = MODEL_ACCESS_PUBLIC;
|
||||||
|
index = -1;
|
||||||
|
isAttributePreset = true;
|
||||||
|
}
|
||||||
|
else if (StrEqual(modelpath, "random_hidden", false))
|
||||||
|
{
|
||||||
|
access = MODEL_ACCESS_HIDDEN;
|
||||||
|
index = -1;
|
||||||
|
isAttributePreset = true;
|
||||||
|
}
|
||||||
|
else if (StrEqual(modelpath, "random_admin", false))
|
||||||
|
{
|
||||||
|
access = MODEL_ACCESS_ADMINS;
|
||||||
|
index = -1;
|
||||||
|
isAttributePreset = true;
|
||||||
|
}
|
||||||
|
else if (StrEqual(modelpath, "random_mother_zombie", false))
|
||||||
|
{
|
||||||
|
access = MODEL_ACCESS_MOTHER_ZOMBIES;
|
||||||
|
index = -1;
|
||||||
|
isAttributePreset = true;
|
||||||
}
|
}
|
||||||
else if (StrEqual(modelpath, "default", false))
|
else if (StrEqual(modelpath, "default", false))
|
||||||
{
|
{
|
||||||
@ -112,12 +152,33 @@ bool:ClassApplyModel(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (StrEqual(modelpath, "nochange", false))
|
else if (StrEqual(modelpath, "no_change", false))
|
||||||
{
|
{
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if model setting is a attribute preset.
|
||||||
|
if (isAttributePreset)
|
||||||
|
{
|
||||||
|
// Get model based on filter settings set up earlier.
|
||||||
|
model = ModelsGetRandomModel(index, team, access);
|
||||||
|
|
||||||
|
// Check if found.
|
||||||
|
if (model >= 0)
|
||||||
|
{
|
||||||
|
// Get model path.
|
||||||
|
ModelsGetFullPath(model, modelpath, sizeof(modelpath));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Couldn't find any models based on filter. Fall back to a random
|
||||||
|
// public model. Then get its path.
|
||||||
|
model = ModelsGetRandomModel(-1, team, MODEL_ACCESS_PUBLIC);
|
||||||
|
ModelsGetFullPath(model, modelpath, sizeof(modelpath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SetEntityModel(client, modelpath);
|
SetEntityModel(client, modelpath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -162,8 +162,12 @@ stock ClassValidateAttributes(classindex)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Check if a model different from a pre-defined setting.
|
// Validate only if not a pre-defined setting.
|
||||||
if (!StrEqual(model_path, "random", false) &&
|
if (!StrEqual(model_path, "random", false) &&
|
||||||
|
!StrEqual(model_path, "random_public", false) &&
|
||||||
|
!StrEqual(model_path, "random_hidden", false) &&
|
||||||
|
!StrEqual(model_path, "random_admins", false) &&
|
||||||
|
!StrEqual(model_path, "random_mother_zombies", false) &&
|
||||||
!StrEqual(model_path, "default", false) &&
|
!StrEqual(model_path, "default", false) &&
|
||||||
!StrEqual(model_path, "nochange", false))
|
!StrEqual(model_path, "nochange", false))
|
||||||
{
|
{
|
||||||
@ -705,8 +709,8 @@ stock bool:ClassFilterMatch(index, filter[ClassFilter], cachetype = ZR_CLASS_CAC
|
|||||||
stock bool:ClassFlagFilterMatch(index, require, deny, cachetype)
|
stock bool:ClassFlagFilterMatch(index, require, deny, cachetype)
|
||||||
{
|
{
|
||||||
new flags;
|
new flags;
|
||||||
new bool:requirepassed;
|
new bool:requirepassed = false;
|
||||||
new bool:denypassed;
|
new bool:denypassed = false;
|
||||||
|
|
||||||
// Do quick check for optimization reasons: Check if no flags are specified.
|
// Do quick check for optimization reasons: Check if no flags are specified.
|
||||||
if (require == 0 && deny == 0)
|
if (require == 0 && deny == 0)
|
||||||
@ -723,11 +727,6 @@ stock bool:ClassFlagFilterMatch(index, require, deny, cachetype)
|
|||||||
// All required flags are set.
|
// All required flags are set.
|
||||||
requirepassed = true;
|
requirepassed = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Not all required flags are set.
|
|
||||||
requirepassed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match deny filter.
|
// Match deny filter.
|
||||||
if (deny == 0 || !(flags & deny))
|
if (deny == 0 || !(flags & deny))
|
||||||
@ -735,11 +734,6 @@ stock bool:ClassFlagFilterMatch(index, require, deny, cachetype)
|
|||||||
// No denied flags are set.
|
// No denied flags are set.
|
||||||
denypassed = true;
|
denypassed = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// It has denied flags set.
|
|
||||||
denypassed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if required and denied flags passed the filter.
|
// Check if required and denied flags passed the filter.
|
||||||
if (requirepassed && denypassed)
|
if (requirepassed && denypassed)
|
||||||
@ -747,11 +741,9 @@ stock bool:ClassFlagFilterMatch(index, require, deny, cachetype)
|
|||||||
// The class pass the filter.
|
// The class pass the filter.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// The class didn't pass the filter.
|
// The class didn't pass the filter.
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -376,11 +376,6 @@ new ClassNoFilter[ClassFilter];
|
|||||||
*/
|
*/
|
||||||
new ClassNoSpecialClasses[ClassFilter] = {false, 0, ZR_CLASS_SPECIALFLAGS, -1};
|
new ClassNoSpecialClasses[ClassFilter] = {false, 0, ZR_CLASS_SPECIALFLAGS, -1};
|
||||||
|
|
||||||
/**
|
|
||||||
* Keyvalue handle to store class data.
|
|
||||||
*/
|
|
||||||
new Handle:kvClassData = INVALID_HANDLE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The original class data. This array only changed when class data is loaded.
|
* The original class data. This array only changed when class data is loaded.
|
||||||
* ZR_CLASS_CACHE_ORIGINAL is the cache type to this array.
|
* ZR_CLASS_CACHE_ORIGINAL is the cache type to this array.
|
||||||
@ -413,7 +408,7 @@ new Float:ClassMultiplierCache[ZR_CLASS_TEAMCOUNT][ClassMultipliers];
|
|||||||
new ClassCount;
|
new ClassCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies wether the class team requirement and attributes are valid or not.
|
* Specifies whether the class team requirements and attributes are valid or not.
|
||||||
* Used to block events that happend before the module is done loading.
|
* Used to block events that happend before the module is done loading.
|
||||||
*/
|
*/
|
||||||
new bool:ClassValidated;
|
new bool:ClassValidated;
|
||||||
@ -485,11 +480,9 @@ ClassLoad()
|
|||||||
// Register config file.
|
// Register config file.
|
||||||
ConfigRegisterConfig(File_Classes, Structure_Keyvalue, CONFIG_FILE_ALIAS_CLASSES);
|
ConfigRegisterConfig(File_Classes, Structure_Keyvalue, CONFIG_FILE_ALIAS_CLASSES);
|
||||||
|
|
||||||
|
new Handle:kvClassData;
|
||||||
|
|
||||||
// Make sure kvClassData is ready to use.
|
// Make sure kvClassData is ready to use.
|
||||||
if (kvClassData != INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
CloseHandle(kvClassData);
|
|
||||||
}
|
|
||||||
kvClassData = CreateKeyValues(CONFIG_FILE_ALIAS_CLASSES);
|
kvClassData = CreateKeyValues(CONFIG_FILE_ALIAS_CLASSES);
|
||||||
|
|
||||||
// Get weapons config path.
|
// Get weapons config path.
|
||||||
|
Loading…
Reference in New Issue
Block a user