drekdrek / grinding-stats

Openplanet plugin which shows statistics
https://openplanet.dev/plugin/grindingstats
MIT License
6 stars 5 forks source link

add cam 7 time #36

Open ezio416 opened 3 months ago

ezio416 commented 3 months ago

Currently it seems the plugin only counts time as long as the car is moving, For RPG maps for instance, I think time spent in cam 7 looking for the route makes sense to be included in playtime. I can help in detecting movement in cam 7 if needed, I have a plugin that messes with this

drekdrek commented 2 months ago

yeah, if there is a way of detecting camera movement in cam 7 it can be added pretty easily

ezio416 commented 2 months ago

I'll admit it's not exactly ideal as the current camera is not exposed via API and therefore requires at least one Dev call, but this is how it would be done (excluding safety checks for the sake of brevity):

bool inCam7 = false;
iso4 location = iso4();
bool moving = false;

void Update(float) {
    CTrackMania@ App = cast<CTrackMania@>(GetApp());
    CSmArenaClient@ Playground = cast<CSmArenaClient@>(App.CurrentPlayground);

    inCam7 = Dev::GetOffsetUint32(Playground.GameTerminals[0], 0x34) == 2;

    // can use index 1 or 2 here, they appear to be the same
    if (DifferentIso4(location, Viewport.Cameras[1].NextLocation)) {
        location = Viewport.Cameras[1].NextLocation;
        moving = true;
    }
}

// iso4 doesn't have an opCmp method for some reason
bool DifferentIso4(const iso4 &in a, const iso4 &in b) {
    return a.tx != b.tx || a.ty != b.ty || a.tz != b.tz
        || a.xx != b.xx || a.xy != b.xy || a.xz != b.xz
        || a.yx != b.yx || a.yy != b.yy || a.yz != b.yz
        || a.zx != b.zx || a.zy != b.zy || a.zz != b.zz;
}

You could also use a different set of Dev calls to get the actual cam 7 object which will simply be null if not in cam 7 (used by one of my plugins, taken from FreeCam: Show CP:

bool moving = false;

void Update(float) {
    CGameControlCameraFree@ Cam = GetFreeCamControls();
    moving = Cam.m_MoveSpeed > 0.0f;
}

const uint ActiveCamControlOffset = 0x80;

uint16 GetMemberOffset(const string &in className, const string &in memberName) {
    const Reflection::MwClassInfo@ type = Reflection::GetType(className);

    if (type is null)
        throw("Unable to find reflection info for " + className);

    const Reflection::MwMemberInfo@ member = type.GetMember(memberName);

    return member.Offset;
}

CGameControlCameraFree@ GetFreeCamControls() {
    CTrackMania@ App = cast<CTrackMania@>(GetApp());

    if (App is null || App.GameScene is null || App.CurrentPlayground is null)
        return null;

    // get the game camera struct
    // orig 0x2b8; GameScene at 0x2a8
    CMwNod@ gameCamCtrl = Dev::GetOffsetNod(App, GetMemberOffset("CGameManiaPlanet", "GameScene") + 0x10);
    if (gameCamCtrl is null)
        return null;

    if (Dev::GetOffsetUint64(gameCamCtrl, ActiveCamControlOffset) & 0xF != 0)
        return null;

    return cast<CGameControlCameraFree@>(Dev::GetOffsetNod(gameCamCtrl, ActiveCamControlOffset));
}

Unfortunately I don't know of any way that doesn't use Dev, so if you're hesitant to use these methods then I totally understand and you can close this issue.