diff --git a/racing.h b/racing.h index 7381d83..39bd7b7 100644 --- a/racing.h +++ b/racing.h @@ -107,7 +107,11 @@ struct { uint16_t eventCount; uint16_t events[LCR_SETTING_REPLAY_MAX_SIZE]; -} LCR_currentReplay; + + // for playing + uint16_t currentEvent; + uint16_t currentFrame; +} LCR_replay; /** Gets times of the run in milliseconds. @@ -123,6 +127,97 @@ TPE_Vec3 _LCR_TPE_vec3DividePlain(TPE_Vec3 v, TPE_Unit d) return v; } +/** + Initializes replay for recording. +*/ +void LCR_replayInitRecording(void) +{ + LCR_LOG1("initializing replay recording"); + LCR_replay.eventCount = 0; +} + +void LCR_replayInitPlaying(void) +{ + LCR_LOG1("initializing replay playing"); + LCR_replay.currentEvent = 0; + LCR_replay.currentFrame = 0; +} + +/** + During playing of a replay returns the next input and shifts to next frame. +*/ +uint8_t LCR_replayGetNextInput(void) +{ + if (LCR_replay.currentEvent >= LCR_replay.eventCount) + return 0; + + if (LCR_replay.currentFrame == + (LCR_replay.events[LCR_replay.currentEvent] >> 4)) + { + LCR_replay.currentEvent++; + LCR_replay.currentFrame = 0; + } + + LCR_replay.currentFrame++; + + return LCR_replay.currentEvent ? + (LCR_replay.events[LCR_replay.currentEvent - 1] & 0xff) : 0; +} + +int LCR_replayHasFinished(void) +{ + return LCR_replay.currentEvent >= LCR_replay.eventCount; +} + +/** + Records another input event. Returns 1 on success, or 0 if the event couldn't + be recorded. The event is only added if necessary, i.e. this function can + safely be called every frame without worrying about inflating its size. +*/ +int LCR_replayRecordEvent(uint32_t frame, uint8_t input) +{ + LCR_LOG2("recording replay event"); + +#if LCR_SETTING_REPLAY_MAX_SIZE > 0 + uint8_t previousInput = 0; + uint32_t previousFrame = 0; + + if (LCR_replay.eventCount) + { + previousInput = LCR_replay.events[LCR_replay.eventCount - 1] & 0x0f; + previousFrame = LCR_replay.events[LCR_replay.eventCount - 1] >> 4; + } + + if (input == previousInput) + return 1; + + if (frame < previousFrame) + return 0; + + frame -= previousFrame; // convert to offset + + while (frame > 4095 && LCR_replay.eventCount < LCR_SETTING_REPLAY_MAX_SIZE) + { + // add intermediate events + + frame -= 4095; + previousFrame += 4095; + + LCR_replay.events[LCR_replay.eventCount] = + (previousFrame << 4) | previousInput; + LCR_replay.eventCount++; + } + + if (LCR_replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE) + return 0; + + LCR_replay.events[LCR_replay.eventCount] = (frame << 4) | input; + LCR_replay.eventCount++; +#endif + + return 1; +} + /** Helper function for _LCR_racingEnvironmentFunction, returns closest point on a map block placed at coordinate origin. @@ -671,6 +766,8 @@ void LCR_racingRestart(void) LCR_racing.carPositions[1] = LCR_racing.carPositions[0]; LCR_racing.carRotations[1] = LCR_racing.carRotations[0]; + + LCR_replayInitRecording(); } /** @@ -838,6 +935,8 @@ uint32_t LCR_racingStep(unsigned int input) uint8_t onAccel = 0; // standing on accelerator? int groundBlockIndex = -1; + LCR_replayRecordEvent(LCR_racing.tick,input); + carForw = TPE_vec3Normalized(TPE_vec3Plus( TPE_vec3Minus(LCR_racing.carBody.joints[0].position, LCR_racing.carBody.joints[2].position),