1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-12-22 09:39:43 +01:00

Make commands, sb, and hooklist not use separate length-trackers

This is a refactor that turns the script-related arrays `ed.sb`, and
`ed.hooklist` into C++ vectors (`script.commands` was already a vector, it was
just misused). The code handling these vectors now looks more like idiomatic
C++ than sloppily-pasted pseudo-ActionScript. This removes the variables
`script.scriptlength`, `ed.sblength`, and `ed.numhooks`, too.

This reduces the amount of code needed to e.g. simply remove something from
any of these vectors. Previously the code had to manually shift the rest of
the elements down one-by-one, and doing it manually is definitely error-prone
and tedious.

But now we can just use fancy functions like `std::vector::erase()` and
`std::remove()` to do it all in one line!

Don't worry, I checked and `std::remove()` is in the C++ standard since at least
1998.

This patch makes it so the `commands` vector gets cleared when
`scriptclass::load()` is ran. Previously, the `commands` vector never actually
properly got cleared, so there could potentially be glitches that rely on the
game indexing past the bounds set by `scriptlength` but still in-bounds in the
eyes of C++, and people could potentially rely on such an exploit...

However, I checked, and I'm pretty sure that no such glitch previously existed
at all, because the only times the vector gets indexed are when `scriptlength`
is either being incremented after starting from 0 (`add()`) or when it's
underneath a `position < scriptlength` conditional.

Furthermore, I'm unaware of anyone who has actually found or used such an
exploit, and I've been in the custom level community for 6 years.

So I think it's fine.
This commit is contained in:
Misa 2020-02-20 09:43:52 -08:00 committed by Ethan Lee
parent 58fc42b638
commit 1be398319c
5 changed files with 43 additions and 99 deletions

View file

@ -11,12 +11,10 @@ scriptclass::scriptclass()
//Start SDL
//Init
commands.resize(500);
words.resize(40);
txt.resize(40);
position = 0;
scriptlength = 0;
scriptdelay = 0;
running = false;
@ -72,7 +70,7 @@ void scriptclass::run( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map,
{
while(running && scriptdelay<=0 && !game.pausescript)
{
if (position < scriptlength)
if (position < (int) commands.size())
{
//Let's split or command in an array of words
tokenize(commands[position]);
@ -3596,7 +3594,7 @@ void scriptclass::hardreset( KeyPoll& key, Graphics& dwgfx, Game& game,mapclass&
//Script Stuff
position = 0;
scriptlength = 0;
commands.clear();
scriptdelay = 0;
scriptname = "null";
running = false;

View file

@ -23,8 +23,7 @@ public:
void inline add(std::string t)
{
commands[scriptlength] = t;
scriptlength++;
commands.push_back(t);
}
void clearcustom();
@ -51,7 +50,7 @@ public:
std::vector<std::string> words;
std::vector<std::string> txt;
std::string scriptname;
int position, scriptlength;
int position;
int looppoint, loopcount;
int scriptdelay;

View file

@ -11,7 +11,7 @@ void scriptclass::load(std::string t)
{
//loads script name t into the array
position = 0;
scriptlength=0;
commands.clear();
running = true;
int maxlength = (std::min(int(t.length()),7));

View file

@ -324,25 +324,11 @@ void editorclass::reset()
}
}
if(numhooks>0)
{
for(int i=0; i<numhooks; i++)
{
removehook(hooklist[i]);
}
}
hooklist.clear();
for (int i = 0; i < 500; i++)
{
sb[i]="";
}
for (int i = 0; i < 500; i++)
{
hooklist[i]="";
}
sb.clear();
clearscriptbuffer();
sblength=1;
sbx=0;
sby=0;
pagey=0;
@ -353,7 +339,6 @@ void editorclass::reset()
hookmenupage=0;
hookmenu=0;
numhooks=0;
script.customscript.clear();
returneditoralpha = 0;
@ -370,7 +355,7 @@ void editorclass::weirdloadthing(std::string t)
void editorclass::gethooks()
{
//Scan through the script and create a hooks list based on it
numhooks=0;
hooklist.clear();
std::string tstring;
std::string tstring2;
for(size_t i=0; i<script.customscript.size(); i++)
@ -392,8 +377,7 @@ void editorclass::gethooks()
{
tstring2+=tstring[j];
}
hooklist[numhooks]=tstring2;
numhooks++;
hooklist.push_back(tstring2);
}
}
}
@ -427,12 +411,15 @@ void editorclass::loadhookineditor(std::string t)
else
{
//load in this line
sb[sblength-1]=script.customscript[i];
sblength++;
sb.push_back(script.customscript[i]);
}
}
}
if(sblength>1) sblength--;
if(sb.empty())
{
//Always have one line or we'll have problems
sb.resize(1);
}
}
void editorclass::addhooktoscript(std::string t)
@ -440,12 +427,9 @@ void editorclass::addhooktoscript(std::string t)
//Adds hook+the scriptbuffer to the end of the scriptclass
removehookfromscript(t);
script.customscript.push_back(t+":");
if(sblength>=1)
for(size_t i=0; i<sb.size(); i++)
{
for(int i=0; i<sblength; i++)
{
script.customscript.push_back(sb[i]);
}
script.customscript.push_back(sb[i]);
}
}
@ -500,35 +484,22 @@ void editorclass::removehookfromscript(std::string t)
void editorclass::removehook(std::string t)
{
//Check the hooklist for the hook t. If it's there, remove it from here and the script
for(int i=0; i<numhooks; i++)
{
if(hooklist[i]==t)
{
removehookfromscript(t);
for(int j=i; j<numhooks; j++)
{
hooklist[j]=hooklist[j+1];
}
hooklist[numhooks]="";
numhooks--;
i--;
}
}
removehookfromscript(t);
hooklist.erase(std::remove(hooklist.begin(), hooklist.end(), t), hooklist.end());
}
void editorclass::addhook(std::string t)
{
//Add an empty function to the list in both editor and script
removehook(t);
hooklist[numhooks]=t;
numhooks++;
hooklist.push_back(t);
addhooktoscript(t);
}
bool editorclass::checkhook(std::string t)
{
//returns true if hook t already is in the list
for(int i=0; i<numhooks; i++)
for(size_t i=0; i<hooklist.size(); i++)
{
if(hooklist[i]==t) return true;
}
@ -538,43 +509,22 @@ bool editorclass::checkhook(std::string t)
void editorclass::clearscriptbuffer()
{
for(int i=0; i<sblength+1; i++)
{
sb[i]="";
}
sblength=1;
sb.clear();
}
void editorclass::removeline(int t)
{
//Remove line t from the script
if(sblength>1)
if((int)sb.size()>1)
{
if(sblength==t)
{
sblength--;
}
else
{
for(int i=t; i<sblength; i++)
{
sb[i]=sb[i+1];
}
sb[sblength]="";
sblength--;
}
sb.erase(sb.begin() + t);
}
}
void editorclass::insertline(int t)
{
//insert a blank line into script at line t
for(int i=sblength; i>=t; i--)
{
sb[i+1]=sb[i];
}
sb[t]="";
sblength++;
sb.insert(sb.begin() + t, "");
}
void editorclass::loadlevel( int rxi, int ryi )
@ -2912,21 +2862,21 @@ void editorrender( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, ent
dwgfx.Print(16,44,"PRESS ESC TO RETURN TO MENU", 123, 111, 218, true);
//dwgfx.Print(16,60,"READY.", 123, 111, 218, false);
if(ed.numhooks>0)
if(!ed.hooklist.empty())
{
for(int i=0; i<9; i++)
{
if(ed.hookmenupage+i<ed.numhooks)
if(ed.hookmenupage+i<(int)ed.hooklist.size())
{
if(ed.hookmenupage+i==ed.hookmenu)
{
std::string tstring="> " + ed.hooklist[(ed.numhooks-1)-(ed.hookmenupage+i)] + " <";
std::string tstring="> " + ed.hooklist[(ed.hooklist.size()-1)-(ed.hookmenupage+i)] + " <";
std::transform(tstring.begin(), tstring.end(),tstring.begin(), ::toupper);
dwgfx.Print(16,68+(i*16),tstring,123, 111, 218, true);
}
else
{
dwgfx.Print(16,68+(i*16),ed.hooklist[(ed.numhooks-1)-(ed.hookmenupage+i)],123, 111, 218, true);
dwgfx.Print(16,68+(i*16),ed.hooklist[(ed.hooklist.size()-1)-(ed.hookmenupage+i)],123, 111, 218, true);
}
}
}
@ -2945,7 +2895,7 @@ void editorrender( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, ent
//Draw text
for(int i=0; i<25; i++)
{
if(i+ed.pagey<500)
if(i+ed.pagey<(int)ed.sb.size())
{
dwgfx.Print(16,20+(i*8),ed.sb[i+ed.pagey], 123, 111, 218, false);
}
@ -3526,15 +3476,15 @@ void editorrender( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, ent
}
/*
for(int i=0; i<script.customscript.size(); i++){
for(size_t i=0; i<script.customscript.size(); i++){
dwgfx.Print(0,i*8,script.customscript[i],255,255,255);
}
dwgfx.Print(0,8*script.customscript.size(),help.String(script.customscript.size()),255,255,255);
for(int i=0; i<ed.numhooks; i++){
for(size_t i=0; i<ed.hooklist.size(); i++){
dwgfx.Print(260,i*8,ed.hooklist[i],255,255,255);
}
dwgfx.Print(260,8*ed.numhooks,help.String(ed.numhooks),255,255,255);
dwgfx.Print(260,8*ed.hooklist.size(),help.String(ed.hooklist.size()),255,255,255);
*/
if(ed.notedelay>0)
@ -3718,9 +3668,9 @@ void editorinput( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, enti
ed.hookmenu++;
}
if(ed.hookmenu>=ed.numhooks)
if(ed.hookmenu>=(int)ed.hooklist.size())
{
ed.hookmenu=ed.numhooks-1;
ed.hookmenu=ed.hooklist.size()-1;
}
if(ed.hookmenu<0) ed.hookmenu=0;
@ -3740,7 +3690,7 @@ void editorinput( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, enti
{
ed.deletekeyheld=1;
music.playef(2);
ed.removehook(ed.hooklist[(ed.numhooks-1)-ed.hookmenu]);
ed.removehook(ed.hooklist[(ed.hooklist.size()-1)-ed.hookmenu]);
}
if (!game.press_action && !game.press_left && !game.press_right
@ -3752,15 +3702,15 @@ void editorinput( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, enti
{
game.jumpheld = true;
}
if ((game.press_action || game.press_map) && ed.numhooks>0)
if ((game.press_action || game.press_map) && !ed.hooklist.empty())
{
game.mapheld=true;
ed.scripthelppage=1;
key.keybuffer="";
ed.sbscript=ed.hooklist[(ed.numhooks-1)-ed.hookmenu];
ed.sbscript=ed.hooklist[(ed.hooklist.size()-1)-ed.hookmenu];
ed.loadhookineditor(ed.sbscript);
ed.sby=ed.sblength-1;
ed.sby=ed.sb.size()-1;
ed.pagey=0;
while(ed.sby>=20)
{
@ -3813,7 +3763,7 @@ void editorinput( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, enti
if(key.keymap[SDLK_DOWN] && ed.keydelay<=0)
{
ed.keydelay=6;
if(ed.sby+ed.pagey<ed.sblength-1)
if(ed.sby+ed.pagey<(int)ed.sb.size()-1)
{
ed.sby++;
if(ed.sby>=20)
@ -3862,7 +3812,7 @@ void editorinput( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, enti
{
game.mapheld=true;
//Continue to next line
if(ed.sby+ed.pagey>=ed.sblength) //we're on the last line
if(ed.sby+ed.pagey>=(int)ed.sb.size()) //we're on the last line
{
ed.sby++;
if(ed.sby>=20)
@ -3870,7 +3820,6 @@ void editorinput( KeyPoll& key, Graphics& dwgfx, Game& game, mapclass& map, enti
ed.pagey++;
ed.sby--;
}
if(ed.sby+ed.pagey>=ed.sblength) ed.sblength=ed.sby+ed.pagey;
key.keybuffer=ed.sb[ed.pagey+ed.sby];
ed.sbx = utf8::unchecked::distance(ed.sb[ed.pagey+ed.sby].begin(), ed.sb[ed.pagey+ed.sby].end());
}

View file

@ -207,9 +207,8 @@ class editorclass{
bool scripteditmod;
int scripthelppage, scripthelppagedelay;
std::string sb[500];
std::vector<std::string> sb;
std::string sbscript;
int sblength;
int sbx, sby;
int pagey;
@ -226,8 +225,7 @@ class editorclass{
void clearscriptbuffer();
void gethooks();
bool checkhook(std::string t);
std::string hooklist[500];
int numhooks;
std::vector<std::string> hooklist;
int hookmenupage, hookmenu;