Skip to content
This repository was archived by the owner on Sep 24, 2023. It is now read-only.

Commit a07bcaf

Browse files
committed
Add an "output iterator"
Provides a wrapper around KeyValues that iterates over the output strings, parsing them into their components. Also updated the test plugin to use an entity that usually has outputs.
1 parent c70f613 commit a07bcaf

2 files changed

Lines changed: 93 additions & 5 deletions

File tree

scripting/include/level_keyvalues.inc

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,62 @@
1010
*/
1111
native KeyValues LevelEntity_GetKeysByHammerID(int iHammerID);
1212

13+
/**
14+
* A KeyValues-backed handle that returns and iterates over keys that match the given output
15+
* name, parsing the output value into its components while being iterated.
16+
*/
17+
methodmap LevelEntityOutputIterator < KeyValues {
18+
/**
19+
* Creates an output iterator for a given Hammer ID.
20+
*/
21+
public LevelEntityOutputIterator(int hammerID, const char[] output) {
22+
KeyValues outputs = LevelEntity_GetKeysByHammerID(hammerID);
23+
if (outputs) {
24+
char keyBuffer[128], valueBuffer[128];
25+
outputs.GotoFirstSubKey(false);
26+
bool bNext;
27+
do {
28+
outputs.GetSectionName(keyBuffer, sizeof(keyBuffer));
29+
outputs.GetString(NULL_STRING, valueBuffer, sizeof(valueBuffer));
30+
31+
if (!StrEqual(keyBuffer, output)) {
32+
bNext = outputs.DeleteThis() != -1;
33+
} else {
34+
bNext = outputs.GotoNextKey(false);
35+
}
36+
} while (bNext);
37+
outputs.GotoFirstSubKey(false);
38+
}
39+
return view_as<LevelEntityOutputIterator>(outputs);
40+
}
41+
42+
/**
43+
* Returns an output iterator for a given entity (reference), looking it up by its Hammer
44+
* ID.
45+
*/
46+
public static LevelEntityOutputIterator FromEntity(int entref, const char[] output) {
47+
int entity = EntRefToEntIndex(entref);
48+
return new LevelEntityOutputIterator(GetEntProp(entity, Prop_Data, "m_iHammerID"),
49+
output);
50+
}
51+
52+
/**
53+
* Parses the current output string, storing the values by reference and advancing to the
54+
* next key.
55+
*/
56+
public bool Next(char[] targetName, int targetNameLength,
57+
char[] inputName, int inputNameLength, char[] variantValue, int variantValueLength,
58+
float &delay, int &nFireCount) {
59+
char outputString[512];
60+
this.GetString(NULL_STRING, outputString, sizeof(outputString));
61+
62+
// this.GoBack() is a disgusting hack just to make sure it returns true on the last item
63+
return ParseEntityOutputString(outputString, targetName, targetNameLength, inputName,
64+
inputNameLength, variantValue, variantValueLength, delay, nFireCount)
65+
&& (this.GotoNextKey(false) || this.GoBack());
66+
}
67+
}
68+
1369
/**
1470
* Returns a copy of the KeyValues associated with a given entity.
1571
*/
@@ -20,15 +76,28 @@ stock KeyValues LevelEntity_GetKeysByEntity(int entref) {
2076

2177
/**
2278
* Parses an entity's output value (as formatted in the entity string).
23-
*
2479
* Refer to https://developer.valvesoftware.com/wiki/AddOutput for the format.
80+
*
81+
* @return True if the output string was successfully parsed, false if not.
2582
*/
2683
stock bool ParseEntityOutputString(const char[] output, char[] targetName, int targetNameLength,
2784
char[] inputName, int inputNameLength, char[] variantValue, int variantValueLength,
2885
float &delay, int &nFireCount) {
2986
int delimiter;
3087
char buffer[32];
3188

89+
{
90+
// validate that we have something resembling an output string (four commas)
91+
int i, c, nDelim;
92+
while ((c = FindCharInString(output[i], ',')) != -1) {
93+
nDelim++;
94+
i += c + 1;
95+
}
96+
if (nDelim < 4) {
97+
return false;
98+
}
99+
}
100+
32101
delimiter = SplitString(output, ",", targetName, targetNameLength);
33102
delimiter += SplitString(output[delimiter], ",", inputName, inputNameLength);
34103
delimiter += SplitString(output[delimiter], ",", variantValue, variantValueLength);

scripting/level_keyvalues_test.sp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
#pragma newdecls required
1010
#include <level_keyvalues>
1111

12+
13+
#define OUTPUT_NAME "OnCapTeam1"
14+
1215
public void OnMapStart() {
13-
int logicAuto = FindEntityByClassname(-1, "team_control_point");
16+
int captureArea = FindEntityByClassname(-1, "trigger_capture_area");
1417

15-
if (logicAuto != -1) {
16-
LogMessage("%s", "Found a team_control_point with keys:");
18+
if (captureArea != -1) {
19+
LogMessage("---- %s", "Found a trigger_capture_area with keys:");
1720

18-
KeyValues entityKeys = LevelEntity_GetKeysByEntity(logicAuto);
21+
KeyValues entityKeys = LevelEntity_GetKeysByEntity(captureArea);
1922

2023
if (entityKeys) {
2124
char keyBuffer[128], valueBuffer[128];
@@ -28,5 +31,21 @@ public void OnMapStart() {
2831
} while (entityKeys.GotoNextKey(false));
2932
delete entityKeys;
3033
}
34+
35+
LogMessage("---- %s", "List of " ... OUTPUT_NAME ... " outputs:");
36+
37+
LevelEntityOutputIterator captureOutputEvents =
38+
LevelEntityOutputIterator.FromEntity(captureArea, OUTPUT_NAME);
39+
40+
char targetName[32], inputName[64], variantValue[32];
41+
float delay;
42+
int nFireCount;
43+
44+
while (captureOutputEvents.Next(targetName, sizeof(targetName), inputName,
45+
sizeof(inputName), variantValue, sizeof(variantValue), delay, nFireCount)) {
46+
LogMessage("target %s -> input %s (value %s, delay %.2f, refire %d)",
47+
targetName, inputName, variantValue, delay, nFireCount);
48+
}
49+
delete captureOutputEvents;
3150
}
3251
}

0 commit comments

Comments
 (0)