Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
47cc385
Impl placeholders
ArKaNeMaN Mar 27, 2026
7971661
Fix api & add default placeholders
ArKaNeMaN Mar 27, 2026
dc82118
Gen guideline for claude
ArKaNeMaN Mar 28, 2026
6075e1e
Reformat code
ArKaNeMaN Mar 28, 2026
d988197
Update ph api
ArKaNeMaN May 3, 2026
2a51f81
Impl templates
ArKaNeMaN May 3, 2026
aeea5b9
Fix
ArKaNeMaN May 3, 2026
f588abc
Impl test plugin for ph
ArKaNeMaN May 3, 2026
604fb8e
Add `Regexp` type
ArKaNeMaN Apr 10, 2026
71d9e69
Add pcget and pcsingle for regexp
ArKaNeMaN Apr 10, 2026
90c734c
Fix inc
ArKaNeMaN Apr 10, 2026
2d6bb48
Minor fixes in pcjson
ArKaNeMaN Apr 10, 2026
befb08e
Impl `PCGet_RegexpMatch` func
ArKaNeMaN Apr 10, 2026
4bb086d
Add PCParam-style for params list registering
ArKaNeMaN Apr 10, 2026
dacd504
Remove test plugin
ArKaNeMaN May 3, 2026
3cdb833
Merge branch 'master' into feature/placeholders
ArKaNeMaN May 3, 2026
15ee6d2
Impl default ph keys for global context
ArKaNeMaN May 3, 2026
93e9241
Impl default keys for player context
ArKaNeMaN May 3, 2026
9f93509
Impl proxy ph groups
ArKaNeMaN May 3, 2026
a34aeb0
Add `PH-Template` param type
ArKaNeMaN May 3, 2026
e0389f4
Fix
ArKaNeMaN May 4, 2026
8368599
Add `PlayerModel` type
ArKaNeMaN May 16, 2026
8d2af50
Bump version
ArKaNeMaN May 16, 2026
b621b71
Fix player model type
ArKaNeMaN May 16, 2026
6fe4064
Add missing PCSingle_* helpers
ArKaNeMaN May 21, 2026
d1b866c
Use amxx-builder
ArKaNeMaN May 31, 2026
c31d8f9
Add unknown param type handling
ArKaNeMaN May 31, 2026
7057fb4
Show warn when param with unknown param is specified
ArKaNeMaN May 31, 2026
6e909e5
Bump version
ArKaNeMaN May 31, 2026
31dbbc0
Add OC cfg with amxb
ArKaNeMaN Aug 27, 2026
c430afd
Fix placeholders and cleanup repo
ArKaNeMaN Aug 27, 2026
00898b7
Add placeholders
ArKaNeMaN Sep 14, 2026
8ab323a
Merge branch 'master' into feature/placeholders
ArKaNeMaN Sep 15, 2026
72499dc
Fix conflicts
ArKaNeMaN Sep 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# AGENTS.md

Guidance for AI agents working with code in this repository.

## Build

**Requirements:** [amxx-builder](https://github.com/AmxxModularEcosystem/amxx-builder) (`amxb`). The manifest is `amxbuild.yml` — it pins the AMXX compiler version (`amxmodx.version`) and declares include dependencies (`deps`).

```bat
build.bat :: local wrapper around `amxb build`
amxb build :: actual build command
```

Output goes to `dist/` (or `ParamsController.zip` at repo root when packaging). Build settings live in `amxbuild.yml`. No `deps` are currently declared — the plugin intentionally has no third-party include dependencies (ReAPI was removed; default placeholder groups use only AMXX core natives).

There are no test or lint commands — the CI pipeline (`.github/workflows/CI.yml`) runs the same `amxb build` as the validation step.

> The plugin must compile without warnings that are errors — CI treats compiler output as the gate. Run `amxb build` before pushing.

## Architecture

ParamsController is an AmxModX plugin library (written in PAWN) that provides:

1. **Parameter parsing** — a JSON-based typed parameter framework. A consumer plugin calls `ParamsController_Init()`, constructs typed parameters with `ParamsController_Param_Construct()`, then reads a JSON object via `ParamsController_Param_ReadList()`. Each parameter is validated against its registered type handler.
2. **Placeholder system** — a global/per-player string substitution framework (groups, keys, contexts, proxy groups, compiled templates). Full design is documented in `PLACEHOLDERS.md`.

### Layer structure

| Layer | Path | Role |
|---|---|---|
| Public API | `amxmodx/scripting/include/ParamsController.inc` | All native/forward declarations + stock helpers; this is what consumers include |
| Main plugin | `amxmodx/scripting/ParamsController.sma` | Entry point, library registration, init flow, forward registration |
| Params API impl | `ParamsController/API/` | Native implementations (General, Param, ParamType, Utils) |
| Placeholder API impl | `ParamsController/Placeholders/API/` | `PCPH_*` native implementations (General, Group, Key) |
| Object model | `ParamsController/Objects/` | `Param.inc` (Array + free-list storage), `ParamType.inc` (Trie-keyed type registry, current-param stack) |
| Placeholder objects | `ParamsController/Placeholders/Objects/` | `PHGroup.inc` (group registry, contexts, values, callback stack), `PHTemplate.inc` (compiled template cache) |
| Placeholder utils | `ParamsController/Placeholders/PHParse.inc` | Shared placeholder parsing (`PHParse_FindClosing`, `PHParse_Placeholder`) used by inline formatting and template compilation |
| Built-in types | `ParamsController/DefaultObjects/ParamType/` | 18 files registering 20 type names: Boolean, Integer, Float, String/ShortString/LongString, RGB, Model, PlayerModel, Sound, Resource, File, Dir, ChatMessage, Time, TimeInterval, WeekDay, Flags, Regexp, PH-Template |
| Default placeholders | `ParamsController/DefaultObjects/Placeholder/` | `Global.inc`, `Player.inc` — built-in groups (`{map}`, `{real-map}`, `{server-name}`, `{server-ip}`, `{date}`, `{time}`, `{datetime}`, `{players-count}`, `{max-players-count}`, `{uptime}`, `{nextmap}`, `{time-left}`, `{gametime}`, `{mod}`, `{amx-version}`, `{alive-count}`, `{dead-count}`, `{bot-count}`, `{human-count}`; `{p:authid}`, `{p:name}`, `{p:ip}`, `{p:userid}`, `{p:health}`, `{p:armor}`, `{p:frags}`, `{p:ping}`, `{p:connect-time}`, `{p:deaths}`, `{p:team}`, `{p:team-name}`, `{p:alive}`, `{p:bot}`, `{p:loss}`, `{p:index}`) |
| Registrar | `ParamsController/DefaultObjects/Registrar.inc` | Wires up all default types and placeholder groups on plugin load |
| Forwards | `ParamsController/Forwards.inc` | Generic forward registration utility used throughout |

### Key design patterns

- **Parameter storage:** Array-based with a free-list for handle reuse (`Objects/Param.inc`)
- **Type registry:** Trie-keyed by type name string (`Objects/ParamType.inc`); read callbacks are `CreateOneForward`-based, so plugin-owned
- **Current param context:** `CurrentParams`/`CurrentParamName` globals + a save/restore stack, so read callbacks can nest (types that internally read other types via `PCSingle_*`)
- **Placeholder groups:** Array-backed, Trie-keyed by prefix (`Placeholders/Objects/PHGroup.inc`); values stored as `"key:contextKey"` strings; contexts are per-group stacks
- **Proxy groups:** alias a source group's keys/callbacks/values but keep an independent context stack (two players in one string)
- **Callback reentrancy:** the currently-active callback (group/key/context) is kept on a stack (`S_PHCurrentCallback`), so `PCPH_Format`/`PCPH_Cb_Set*` can be called from inside a callback — nested calls restore the outer state
- **Compiled templates:** `PCPH_CompileTemplate` pre-parses a format string into parts and caches group/forward handles (`Placeholders/Objects/PHTemplate.inc`)
- **Extensibility:** consumers can register custom parameter types (`ParamsController_ParamType_Register` / `ParamsController_RegSimpleType`) and placeholder groups/keys via `PCPH_*` natives
- **Error reporting:** `E_ParamsReadErrorType` enum returned from `ReadList`; error details (param name, expected/got type) accessible via out-params of `ParamsController_Param_ReadList`

### Init flow (`PluginInit` in `ParamsController.sma`)

1. `Forwards_Init()`, `Param_Init()`, `PHGroup_Init()` — allocate storages
2. `DefaultObjects_Register()` — register built-in param types + default placeholder groups
3. Forward `ParamsController_OnRegisterTypes` — consumers register custom param types
4. Forward `PCPH_OnRegisterGroups` — consumers register placeholder groups/keys
5. Forward `PCPH_OnRegisterProxyGroups` — consumers register proxy groups (all normal groups already exist)
6. Forward `ParamsController_OnInited` — everything is ready

### Language notes

PAWN uses `#include` for all modular decomposition. `.inc` files are not independently compiled — they are all included into `ParamsController.sma`. The public header (`ParamsController.inc`) only declares natives/forwards and stock helpers; it contains no plugin state or implementation logic.

## Conventions

- Natives are named `ParamsController_*` (params) and `PCPH_*` (placeholders); implementation handlers use the `@` prefix (e.g. `@API_Param_Construct`) and `register_native(name, "@handler")`.
- All buffers that cross the callback boundary should be local (`new`), not `static` — placeholder callbacks can re-enter the formatter.
- Keep the manifest free of undeclared includes: any `#include <...>` beyond AMXX stdlib must be declared in `amxbuild.yml` `deps` (or removed).
- Do not commit build output — `dist/`, `build/`, `.amxb-cache/` are git-ignored.
5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

All repository guidance lives in [AGENTS.md](AGENTS.md) — build instructions, architecture, conventions, and language notes. Read it before working with the code.
44 changes: 41 additions & 3 deletions amxmodx/scripting/ParamsController.sma
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "ParamsController/Forwards"

#include "ParamsController/Objects/Param"
#include "ParamsController/Placeholders/Objects/PHGroup"
#include "ParamsController/DefaultObjects/Registrar"

public stock const PluginName[] = "Params Controller";
Expand All @@ -27,17 +28,48 @@ PluginInit() {

Forwards_Init();
Param_Init();
DefaultObjects_ParamType_Register();
PHGroup_Init();
DefaultObjects_Register();

// Тут регать типы
// Тут регать типы параметров
Forwards_RegAndCall("ParamsController_OnRegisterTypes", ET_IGNORE);

// Тут регать группы и ключи плейсхолдеров
Forwards_RegAndCall("PCPH_OnRegisterGroups", ET_IGNORE);

// Тут регать прокси-группы (все обычные группы уже зарегистрированы)
Forwards_RegAndCall("PCPH_OnRegisterProxyGroups", ET_IGNORE);

register_srvcmd("params_controller_types", "@SrvCmd_Types");

// После этого можно юзать типы
// После этого можно юзать типы и плейсхолдеры
Forwards_RegAndCall("ParamsController_OnInited", ET_IGNORE);
}

public client_authorized(playerIndex, const authId[]) {
if (!IsPluginInited()) {
return;
}

DefaultObjects_OnClientAuth(playerIndex, authId);
}

public client_putinserver(playerIndex) {
if (!IsPluginInited()) {
return;
}

DefaultObjects_OnClientPutInServer(playerIndex);
}

public client_disconnected(playerIndex) {
if (!IsPluginInited()) {
return;
}

DefaultObjects_OnClientDisconnected(playerIndex);
}

@SrvCmd_Types() {
ParamType_PrintListToConsole();
}
Expand All @@ -49,9 +81,15 @@ bool:IsPluginInited() {
#include "ParamsController/API/General"
#include "ParamsController/API/Param"
#include "ParamsController/API/ParamType"
#include "ParamsController/Placeholders/API/General"
#include "ParamsController/Placeholders/API/Group"
#include "ParamsController/Placeholders/API/Key"

public plugin_natives() {
API_General_Register();
API_Param_Register();
API_ParamType_Register();
API_PH_General_Register();
API_PH_Group_Register();
API_PH_Key_Register();
}
4 changes: 2 additions & 2 deletions amxmodx/scripting/ParamsController/API/General.inc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ API_General_Register() {
API_CheckPluginInited();
API_CheckCurrentParams();

return TrieSetCell(g_tCurrentParams, g_sCurrentParamName, get_param(Arg_Cell));
return TrieSetCell(CurrentParams, CurrentParamName, get_param(Arg_Cell));
}

@API_SetString() {
Expand All @@ -29,5 +29,5 @@ API_General_Register() {
static sString[PARAM_LONG_STRING_MAX_LEN];
get_string(Arg_String, sString, charsmax(sString));

return TrieSetString(g_tCurrentParams, g_sCurrentParamName, sString);
return TrieSetString(CurrentParams, CurrentParamName, sString);
}
51 changes: 25 additions & 26 deletions amxmodx/scripting/ParamsController/API/Param.inc
Original file line number Diff line number Diff line change
Expand Up @@ -9,61 +9,60 @@ API_Param_Register() {
}

T_Param:@API_Param_Construct() {
enum {Arg_sKey = 1, Arg_sParamTypeName, Arg_bRequired}
enum {Arg_Key = 1, Arg_ParamTypeName, Arg_Required}

API_CheckPluginInited();

new sKey[PARAM_KEY_MAX_LEN];
get_string(Arg_sKey, sKey, charsmax(sKey));
new key[PARAM_KEY_MAX_LEN];
get_string(Arg_Key, key, charsmax(key));

new sParamTypeName[PARAM_TYPE_NAME_MAX_LEN + PARAM_TYPE_TAG_MAX_LEN + 1];
get_string(Arg_sParamTypeName, sParamTypeName, charsmax(sParamTypeName));

new bool:bRequired = !!get_param(Arg_bRequired);
new paramTypeName[PARAM_TYPE_NAME_MAX_LEN + PARAM_TYPE_TAG_MAX_LEN + 1];
get_string(Arg_ParamTypeName, paramTypeName, charsmax(paramTypeName));

new bool:bRequired = !!get_param(Arg_Required);
new sParamType[PARAM_TYPE_NAME_MAX_LEN], sParamTag[PARAM_TYPE_TAG_MAX_LEN];
ParamType_GetTypeAndTag(sParamTypeName,
ParamType_GetTypeAndTag(paramTypeName,
sParamType, charsmax(sParamType),
sParamTag, charsmax(sParamTag)
);
new T_ParamType:iParamType = ParamType_Find(sParamType, .orFail = false);

if (iParamType == Invalid_ParamType) {
if (bRequired) {
log_error(AMX_ERR_PARAMS, "Param '%s' is required, but type '%s' is not registered.", sKey, sParamType);
log_error(AMX_ERR_PARAMS, "Param '%s' is required, but type '%s' is not registered.", key, sParamType);
}

return Param_Construct(sKey, iParamType, bRequired, sParamTypeName);
return Param_Construct(key, iParamType, bRequired, paramTypeName);
}

return Param_Construct(sKey, iParamType, bRequired, sParamTag);
return Param_Construct(key, iParamType, bRequired, sParamTag);
}

// native Trie:ParamsController_Param_ReadList(const Array:aParams, const JSON:jObj, &Trie:tAppend = Invalid_Trie, &E_ParamsReadErrorType:iErrType, sErrParamName[], const iErrParamNameLen = 0);
// native Trie:ParamsController_Param_ReadList(const Array:params, const JSON:objectJson, &Trie:append = Invalid_Trie, &E_ParamsReadErrorType:errType, errParamName[], const errParamNameLen = 0);
Trie:@API_Param_ReadList() {
enum {Arg_aParams = 1, Arg_jObj, Arg_tAppend, Arg_iErrType, Arg_sErrParamName, Arg_iErrParamNameLen}
enum {Arg_Params = 1, Arg_ObjectJson, Arg_Append, Arg_ErrType, Arg_ErrParamName, Arg_ErrParamNameLen}

API_CheckPluginInited();

new Array:aParams = Array:get_param(Arg_aParams);
new JSON:jObj = JSON:get_param(Arg_jObj);
new Trie:tAppend = Trie:get_param_byref(Arg_tAppend);
new E_ParamsReadErrorType:iErrType = E_ParamsReadErrorType:get_param_byref(Arg_iErrType);
new sErrParamName[PARAM_KEY_MAX_LEN];
get_string(Arg_sErrParamName, sErrParamName, charsmax(sErrParamName));
new iErrParamNameLen = get_param(Arg_iErrParamNameLen);
new Array:params = Array:get_param(Arg_Params);
new JSON:objectJson = JSON:get_param(Arg_ObjectJson);
new Trie:append = Trie:get_param_byref(Arg_Append);
new E_ParamsReadErrorType:errType = E_ParamsReadErrorType:get_param_byref(Arg_ErrType);
new errParamName[PARAM_KEY_MAX_LEN];
get_string(Arg_ErrParamName, errParamName, charsmax(errParamName));
new errParamNameLen = get_param(Arg_ErrParamNameLen);

if (!json_is_object(jObj)) {
log_error(AMX_ERR_PARAMS, "[ERROR] Param jObj must be an object. (%d)", jObj);
if (!json_is_object(objectJson)) {
log_error(AMX_ERR_PARAMS, "[ERROR] Param objectJson must be an object. (%d)", objectJson);
return Invalid_Trie;
}

new Trie:tRet = Param_ReadList(aParams, jObj, tAppend, iErrType, sErrParamName, iErrParamNameLen);
new Trie:ret = Param_ReadList(params, objectJson, append, errType, errParamName, errParamNameLen);

set_param_byref(Arg_iErrType, _:iErrType);
set_string(Arg_sErrParamName, sErrParamName, iErrParamNameLen);
set_param_byref(Arg_ErrType, _:errType);
set_string(Arg_ErrParamName, errParamName, errParamNameLen);

return tRet;
return ret;
}

bool:@API_Param_Read() {
Expand Down
2 changes: 1 addition & 1 deletion amxmodx/scripting/ParamsController/API/Utils.inc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ stock API_CheckPluginInited() {
}

stock API_CheckCurrentParams() {
if (g_tCurrentParams == Invalid_Trie) {
if (CurrentParams == Invalid_Trie) {
abort(AMX_ERR_PARAMS, "Attempt to set param value outside the read callback.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ DefaultObjects_ParamType_ChatMessage_Register() {

bool:@DefaultObjects_ParamType_ChatMessage_OnRead(const JSON:valueJson) {
static str[PARAM_CHAT_MESSAGE_MAX_LEN];
json_get_string(valueJson, str, charsmax(str));
PCSingle_String(valueJson, str, charsmax(str));

replace_all(str, charsmax(str), "^^1", "^1");
replace_all(str, charsmax(str), "^^3", "^3");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ DefaultObjects_ParamType_Dir_Register() {

bool:@DefaultObjects_ParamType_Dir_OnRead(const JSON:valueJson, const Trie:p, const key[]) {
static path[PLATFORM_MAX_PATH];
json_get_string(valueJson, path, charsmax(path));
PCSingle_String(valueJson, path, charsmax(path));

if (!dir_exists(path)) {
PCJson_LogForFile(valueJson, "WARNING", "Dir '%s' not found.", path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ DefaultObjects_ParamType_File_Register() {

bool:@DefaultObjects_ParamType_File_OnRead(const JSON:valueJson, const Trie:p, const key[]) {
static path[PLATFORM_MAX_PATH];
json_get_string(valueJson, path, charsmax(path))
PCSingle_String(valueJson, path, charsmax(path))

if (!file_exists(path)) {
PCJson_LogForFile(valueJson, "WARNING", "File '%s' not found.", path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ DefaultObjects_ParamType_Flags_Register() {

bool:@DefaultObjects_ParamType_Flags_OnRead(const JSON:valueJson) {
static str[32];
json_get_string(valueJson, str, charsmax(str));
PCSingle_String(valueJson, str, charsmax(str));

return ParamsController_SetCell(read_flags(str));
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ DefaultObjects_ParamType_Model_Register() {

bool:@DefaultObjects_ParamType_Model_OnRead(const JSON:valueJson, const Trie:p, const key[], const tag[]) {
static path[PLATFORM_MAX_PATH];
json_get_string(valueJson, path, charsmax(path));
PCSingle_String(valueJson, path, charsmax(path));

if (!file_exists(path)) {
PCJson_LogForFile(valueJson, "WARNING", "Model '%s' not found.", path);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <amxmodx>
#include <json>
#include <ParamsController>

DefaultObjects_ParamType_PHTemplate_Register() {
ParamsController_RegSimpleType(DEFAULT_PARAMS_PH_TEMPLATE_NAME, "@DefaultObjects_ParamType_PHTemplate_OnRead");
}

bool:@DefaultObjects_ParamType_PHTemplate_OnRead(const JSON:valueJson) {
return ParamsController_SetCell(
PCPH_CompileTemplate(
PCSingle_iString(valueJson)
)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ bool:@DefaultObjects_ParamType_RGB_OnRead(const JSON:valueJson, const Trie:p, co
}
} else if (json_is_string(valueJson)) {
static str[32], colorStr[3][8];
json_get_string(valueJson, str, charsmax(str));
PCSingle_String(valueJson, str, charsmax(str));

if (contain(str, ",")) {
explode_string(str, ",", colorStr, 3, charsmax(colorStr[]));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ DefaultObjects_ParamType_Regexp_Register() {

bool:@DefaultObjects_ParamType_Regexp_OnRead(const JSON:valueJson) {
static pattern[PARAM_VALUE_MAX_LEN];
json_get_string(valueJson, pattern, charsmax(pattern));
PCSingle_String(valueJson, pattern, charsmax(pattern));

static error[256];
new ret;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ DefaultObjects_ParamType_Resource_Register() {

bool:@DefaultObjects_ParamType_Resource_OnRead(const JSON:valueJson, const Trie:p, const key[], const tag[]) {
static path[PLATFORM_MAX_PATH];
json_get_string(valueJson, path, charsmax(path));
PCSingle_String(valueJson, path, charsmax(path));

if (!file_exists(path)) {
PCJson_LogForFile(valueJson, "WARNING", "Precaching file '%s' not found.", path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ DefaultObjects_ParamType_Sound_Register() {

bool:@DefaultObjects_ParamType_Sound_OnRead(const JSON:valueJson, const Trie:p, const key[], const tag[]) {
static path[PLATFORM_MAX_PATH];
json_get_string(valueJson, path, charsmax(path));
PCSingle_String(valueJson, path, charsmax(path));

static fullPath[PLATFORM_MAX_PATH];
formatex(fullPath, charsmax(fullPath), "sound/%s", path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ bool:@DefaultObjects_ParamType_Time_OnRead(const JSON:valueJson) {
}
case JSONString: {
static str[PARAM_SHORT_STRING_MAX_LEN];
json_get_string(valueJson, str, charsmax(str));
PCSingle_String(valueJson, str, charsmax(str));

new parts[3][3];
if (explode_string(str, ":", parts, 3, 3) > 3) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ bool:@DefaultObjects_ParamType_TimeInterval_OnRead(const JSON:valueJson) {
}
case JSONString: {
static str[PARAM_SHORT_STRING_MAX_LEN];
json_get_string(valueJson, str, charsmax(str));
PCSingle_String(valueJson, str, charsmax(str));

// https://dev-cs.ru/threads/222/page-3#post-33411
new t, k;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ DefaultObjects_ParamType_WeekDay_Register() {

bool:@DefaultObjects_ParamType_WeekDay_OnRead(const JSON:valueJson) {
static str[PARAM_SHORT_STRING_MAX_LEN];
json_get_string(valueJson, str, charsmax(str));
PCSingle_String(valueJson, str, charsmax(str));

new res;
if (TrieGetCell(WeekDaysMap, str, res)) {
Expand Down
Loading
Loading