Start replay loading

This commit is contained in:
Miloslav Ciz 2025-01-19 22:19:44 +01:00
parent 71aa8156e9
commit 17a371fdca
4 changed files with 169 additions and 16 deletions

View file

@ -85,7 +85,7 @@ static const char *LCR_internalResourceFile =
" map end " " map end "
"#Mmap2;4321 1 :*H1k0J :,s0s0 :fd190 " "#Mmap2;4321 1 :*H1k0J :,s0s0 :fd190 "
"#Rtestrepl;aaa#Rrepl2;" "#Rrep1;testmap;482f70f9 00000188:00c1:0089:0111:00b9:0091:0109:0028:0050:00c1:0093:0030:00d1:0069:0041:0020:0071:0013:0012:0023:0022:0050:0032:0020:0022:0060:0024:00bc:0044"
"#Mmap3;4321 1 :*H1k0J :,s0s0 :fd190 " "#Mmap3;4321 1 :*H1k0J :,s0s0 :fd190 "
"#Mmap4;4321 1 :*H1k0J :,s0s0 :fd190 " "#Mmap4;4321 1 :*H1k0J :,s0s0 :fd190 "
"#Mmap5;4321 1 :*H1k0J :,s0s0 :fd190 " "#Mmap5;4321 1 :*H1k0J :,s0s0 :fd190 "

125
game.h
View file

@ -175,7 +175,11 @@ uint8_t LCR_gameGetNextAudioSample(void);
#define LCR_GAME_STATE_RUN_STARTING 0x01 #define LCR_GAME_STATE_RUN_STARTING 0x01
#define LCR_GAME_STATE_RUN 0x02 #define LCR_GAME_STATE_RUN 0x02
#define LCR_GAME_STATE_RUN_FINISHED 0x03 #define LCR_GAME_STATE_RUN_FINISHED 0x03
#define LCR_GAME_STATE_LOADING_MAP 0x04
#define LCR_GAME_STATE_LOADING_RUN 0x04
#define LCR_GAME_STATE_LOADING_REP1 0x05
#define LCR_GAME_STATE_LOADING_REP2 0x06
#define LCR_GAME_STATE_END 0xff #define LCR_GAME_STATE_END 0xff
// forward decls of pixel drawing functions for the renderer // forward decls of pixel drawing functions for the renderer
@ -422,7 +426,7 @@ void LCR_seekResourceByIndex(unsigned int index, char magicNumber)
} while (c); } while (c);
} }
void LCR_gameStartRun(unsigned int mapIndex) void LCR_gameLoadMap(unsigned int mapIndex)
{ {
char mapName[LCR_MAP_NAME_MAX_LEN]; char mapName[LCR_MAP_NAME_MAX_LEN];
@ -443,7 +447,83 @@ void LCR_gameStartRun(unsigned int mapIndex)
} }
LCR_mapLoadFromStr(LCR_gameGetNextResourceStrChar,mapName); LCR_mapLoadFromStr(LCR_gameGetNextResourceStrChar,mapName);
LCR_gameSetState(LCR_GAME_STATE_LOADING_MAP); }
/**
Loads replay by its index, returns index of a map for the replay (and the map
will be loaded as with LCR_mapLoadFromStr) or -1 if the map wasn't found or -2
if the replay couldn't be loaded. This function potentially reloads current
map!
*/
unsigned int LCR_gameLoadReplay(unsigned int replayIndex)
{
uint32_t mapHash;
uint16_t nameHash;
char c;
LCR_LOG1("loading replay and map");
LCR_seekResourceByIndex(replayIndex,'R');
do // skip name
{
c = LCR_gameGetNextResourceFileChar();
}
while (c && c != LCR_RESOURCE_FILE_SEPARATOR2 &&
c != LCR_RESOURCE_FILE_SEPARATOR);
if (!LCR_replayLoadFromStr(LCR_gameGetNextResourceStrChar,
&mapHash,&nameHash))
return -2;
// now try to find the map with given nameHash
LCR_gameRewindResourceFile();
unsigned int skipTo = 0;
while (1)
{
unsigned int mapIndex = 0;
while (1) // find first skipToth map
{
c = LCR_gameGetNextResourceFileChar();
if (c == 0)
return -1;
else if (c == 'M')
{
if (mapIndex >= skipTo &&
nameHash == _LCR_simpleStrHash(LCR_gameGetNextResourceStrChar,';'))
{
LCR_LOG2("map name hash matches");
LCR_gameLoadMap(mapIndex);
if (mapHash == LCR_currentMap.hash)
return mapIndex;
else
{
LCR_LOG2("map hash doesn't match");
// map hash doesn't match
skipTo = mapIndex + 1;
break;
}
}
mapIndex++;
}
while (c != LCR_RESOURCE_FILE_SEPARATOR)
{
if (c == 0)
return -1;
c = LCR_gameGetNextResourceFileChar();
}
}
}
return 0;
} }
void LCR_gameEraseMenuItemNames(void) void LCR_gameEraseMenuItemNames(void)
@ -608,6 +688,13 @@ void LCR_gameTimeToStr(uint32_t timeMS, char *str)
str[2] = '\''; str[2] = '\'';
} }
int _LCR_gameIsLoading(void)
{
return
(LCR_game.state == LCR_GAME_STATE_LOADING_RUN) ||
(LCR_game.state == LCR_GAME_STATE_LOADING_REP1) ||
(LCR_game.state == LCR_GAME_STATE_LOADING_REP2);
}
void LCR_gameDraw3DView(void) void LCR_gameDraw3DView(void)
{ {
@ -808,10 +895,31 @@ void LCR_gameHandleInput(void)
break; break;
case 1: case 1:
LCR_gameStartRun( LCR_gameLoadMap(LCR_game.resourceFile.firstItemIndex +
LCR_game.resourceFile.firstItemIndex + LCR_game.menu.selectedItem); LCR_game.menu.selectedItem);
LCR_gameSetState(LCR_GAME_STATE_LOADING_RUN);
break; break;
case 2:
case 3:
{
int mapIndex = LCR_gameLoadReplay(LCR_game.resourceFile.firstItemIndex +
LCR_game.menu.selectedItem);
if (mapIndex < -1)
{
LCR_LOG1("couldn't load replay");
}
else if (mapIndex == -1)
{
LCR_LOG1("couldn't load replay map");
}
else
LCR_gameSetState(LCR_GAME_STATE_LOADING_REP1);
break;
}
default: break; default: break;
} }
} }
@ -901,7 +1009,7 @@ uint8_t LCR_gameStep(uint32_t time)
LCR_game.keyStates[i] = LCR_keyPressed(i) ? LCR_game.keyStates[i] = LCR_keyPressed(i) ?
(LCR_game.keyStates[i] < 255 ? LCR_game.keyStates[i] + 1 : 255) : 0; (LCR_game.keyStates[i] < 255 ? LCR_game.keyStates[i] + 1 : 255) : 0;
if (LCR_game.state == LCR_GAME_STATE_LOADING_MAP) if (_LCR_gameIsLoading())
{ {
LCR_rendererLoadMap(); LCR_rendererLoadMap();
LCR_gameResetRun(LCR_racing.playingReplay); LCR_gameResetRun(LCR_racing.playingReplay);
@ -975,8 +1083,7 @@ LCR_replayOutputStr(_LCR_gameResourceCharWrite);
while (time >= LCR_game.nextRenderFrameTime) while (time >= LCR_game.nextRenderFrameTime)
LCR_game.nextRenderFrameTime += 1000 / LCR_SETTING_FPS; LCR_game.nextRenderFrameTime += 1000 / LCR_SETTING_FPS;
if (LCR_game.state == LCR_GAME_STATE_MENU || if ((LCR_game.state == LCR_GAME_STATE_MENU) || _LCR_gameIsLoading())
LCR_game.state == LCR_GAME_STATE_LOADING_MAP)
LCR_rendererDrawMenu(LCR_texts[LCR_TEXTS_TABS LCR_rendererDrawMenu(LCR_texts[LCR_TEXTS_TABS
+ LCR_game.menu.selectedTab],LCR_game.menu.itemNamePtrs, + LCR_game.menu.selectedTab],LCR_game.menu.itemNamePtrs,
LCR_game.menu.itemCount + 1,LCR_game.menu.selectedItem); LCR_game.menu.itemCount + 1,LCR_game.menu.selectedItem);
@ -989,7 +1096,7 @@ LCR_replayOutputStr(_LCR_gameResourceCharWrite);
sleep = tmp < sleep ? tmp : sleep; sleep = tmp < sleep ? tmp : sleep;
} }
if (LCR_game.state == LCR_GAME_STATE_LOADING_MAP) if (_LCR_gameIsLoading())
{ {
// show the "loading" screen // show the "loading" screen

View file

@ -42,4 +42,26 @@ int _LCR_hexDigitVal(char c)
return -1; return -1;
} }
/**
Computes simple hash of a string represented by a function returning next
string character, ending at 0 or endChar. This is intended for simple (but
not 100% reliable) string comparison.
*/
uint16_t _LCR_simpleStrHash(char (*nextChar)(void), char endChar)
{
uint16_t r = 0;
while (1)
{
char c = nextChar();
if (c == 0 || c == endChar)
break;
r = ((r << 5) | (r >> 11)) + c;
}
return r;
}
#endif // guard #endif // guard

View file

@ -47,8 +47,6 @@ typedef int32_t LCR_GameUnit; ///< abstract game unit
#include "map.h" #include "map.h"
#include "tinyphysicsengine.h" #include "tinyphysicsengine.h"
// TODO: move some of this to constants?
#define LCR_GRAVITY (LCR_PHYSICS_UNIT / 160) #define LCR_GRAVITY (LCR_PHYSICS_UNIT / 160)
#define LCR_FAN_FORCE 3 #define LCR_FAN_FORCE 3
#define LCR_FAN_FORCE_DECREASE 6 #define LCR_FAN_FORCE_DECREASE 6
@ -174,8 +172,8 @@ void LCR_replayOutputStr(void (*printChar)(char))
for (int i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
{ {
printChar(_LCR_hexDigit(hash % 16)); printChar(_LCR_hexDigit((hash >> 28) % 16));
hash /= 16; hash <<= 4;
} }
printChar(' '); printChar(' ');
@ -204,15 +202,24 @@ void LCR_replayOutputStr(void (*printChar)(char))
/** /**
Reads replay from string using provided function that returns next character Reads replay from string using provided function that returns next character
in the string. Returns 1 on success, else 0. in the string. The mapHash and nameHash pointers are optional: if non-zero,
they will be filled with the map hash and name hash. Returns 1 on success,
else 0.
*/ */
int LCR_replayLoadFromStr(char (*nextChar)(void)) int LCR_replayLoadFromStr(char (*nextChar)(void),
uint32_t *mapHash, uint16_t *nameHash)
{ {
char c = ' '; char c = ' ';
LCR_replay.eventCount = 0; LCR_replay.eventCount = 0;
LCR_replay.achievedTime = 0; LCR_replay.achievedTime = 0;
if (nameHash)
*nameHash = _LCR_simpleStrHash(nextChar,';');
else
_LCR_simpleStrHash(nextChar,';');
/*
do // map name do // map name
{ {
c = nextChar(); c = nextChar();
@ -220,10 +227,27 @@ int LCR_replayLoadFromStr(char (*nextChar)(void))
if (c == 0) if (c == 0)
return 0; return 0;
} while (c != ';'); } while (c != ';');
*/
if (mapHash)
*mapHash = 0;
for (int i = 0; i < 8; ++i) // hash
{
c = nextChar();
if (_LCR_hexDigitVal(c) < 0)
return 0;
if (mapHash)
*mapHash = ((*mapHash) << 4) | _LCR_hexDigitVal(c);
}
/*
for (int i = 0; i < 8; ++i) // hash for (int i = 0; i < 8; ++i) // hash
if (_LCR_hexDigitVal(nextChar()) < 0) if (_LCR_hexDigitVal(nextChar()) < 0)
return 0; return 0;
*/
nextChar(); nextChar();