Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing or outdated docs for client-side API objects (e.g. undefined currentRound, currentGame etc.) #10

Open
kaglowka opened this issue Apr 21, 2024 · 3 comments

Comments

@kaglowka
Copy link

kaglowka commented Apr 21, 2024

https://docs.empirica.ly/overview/api

I tried to use objects returned by Empirica React hooks along the lines of the documentation for Server:
https://docs.empirica.ly/overview/api#server-objects

It looks like only some objects included in the docs are defined, in particular all "currentX" properties are not set, unlike their "X" versions.
Is it that all API is in fact different than in the docs, or is the client-side API different from Server?
If I learn something new about your object API, I'd be happy to contribute to the docs, but at this point I'm confused what is wrong: the behaviour or the docs.

All game-related objects were added in Empirica.onGameStart with calls such as

const round = game.addRound({
  data: {
    opponentType: 'none',
    expRoundIdx: roundIdx,
    roundType: 'training',
  },
});
round.addStage({
  name: 'response',
  displayName: 'Training',
  duration: 10, //Number(gameConfig.responseDuration),
});

Here's a test component:

import React from 'react';

import TaskStimulus from './TaskStimulus';
import TaskResponse from "./TaskResponse.jsx";
import {useGame, usePlayer, useRound, useStage} from "@empirica/core/player/classic/react";

export default function Task(props){
    const game = useGame();
    const player = usePlayer();
    const round = useRound();
    const stage = useStage();

    const gameProps = {game, player, round, stage, ...props};

    console.log('game.players', game.players);
    console.log('game.rounds', game.rounds);
    console.log('game.stages', game.stages);
    console.log('game.round', game.round);
    console.log('game.currentRound', game.currentRound);
    console.log('game.stage', game.stage);
    console.log('game.currentStage', game.currentStage);

    console.log('round.stages', round.stages);
    console.log('round.game', round.game);
    console.log('round.currentGame', round.currentGame);

    console.log('stage.round', stage.round);
    console.log('stage.game', stage.game);
    console.log('stage.currentGame', stage.currentGame);

    console.log('player.round', player.round);
    console.log('player.currentRound', player.currentRound);
    console.log('player.stage', player.stage);
    console.log('player.currentStage', player.currentStage);
    console.log('player.game', player.game);
    console.log('player.currentGame', player.currentGame);

    return (
      <div className="task">
        <TaskStimulus {...gameProps} />
        <TaskResponse {...gameProps} />
      </div>
    );
}

Firefox console output at localhost:3000:
image

@kaglowka
Copy link
Author

I can also confirm that server-side models seem to comply with the docs ( stage.currentGame), e.g. code such as:

Empirica.onStageStart(({ stage }) => {
  const game = stage.currentGame;
  game.players.forEach((player, i) => {
    const position = {
      x: game.gameConfig.startPosition,
      y: game.gameConfig.startPosition,
    }
    player.set('position', position, { ephemeral: true });
  });
});

And as an offtopic, which I'm currently struggling with: could you suggest the best way to record history of player positions within the current architecture? I can imagine two scenarios: 1) recording player position history on the server (I don't know if on callback could do the job and react to every position change?) 2) collecting position history on the client, which then persists the history on stage end.

@npaton
Copy link
Contributor

npaton commented Apr 24, 2024

Thank you for ticket, I will try to fix the docs asap.

For the position, I assume this is mouse positions? That might be a lot of data, so it would be preferable to store it separately from the main data. With ephemeral, the on callbacks should still trigger (you might want to test this first), and you would maybe append to a file.

Untested example:

const fs = require("fs");
const path = require("path");

// The file path where we'll store the player data
const filePath = path.join(__dirname, "playerData.json");

// Ideally, we'd close the stream when we're done writing, but, normally, Node.js
// will close it when the process exits.
const stream = fs.createWriteStream(filePath, { flags: "a" });

function appendPlayerData(data) {
  data.timestamp = new Date().toISOString();
  const dataString = JSON.stringify(data) + "\n";
  stream.write(dataString, (err) => {
    if (err) {
      console.error("Failed to append data:", err);
    }
  });
}

appendPlayerData({ playerID: "player123", x: 100, y: 200 });
appendPlayerData({ playerID: "player456", x: 150, y: 250 });

@kaglowka
Copy link
Author

Thank you for your quick answer.
Actually, the positions are agent positions on the board, but it doesn't matter. There will be some 20 updates a second, so just like you're saying, it could be a bit of updates & data. Avoiding lags is important as they could impact the experiment. I'll try it out the way you're suggesting.

Also, I count myself luck, doing this experiment just weeks after you added ephemeral option to updates -- if updates were always persisted in the database, then I don't know about the important details in Empirica architecture that could impact the client-side latency -- things such as: are player updates instantly propagated to other subscribers before running any heavier code such as callbacks, how quick are database updates etc.
Frankly, this part may be the least clear to me, as the database is self-made. Again, I'll just try it out and see how it goes. I'll be happy to contribute to the docs in the future in as much as I learn Empirica's details and quirks either by using or from you!

Maybe this question could be a separate issue after all -- I did think of adding some kind of "question" issue but currently only bug / feature can be submitted in Empirica code repo. I guess users considering highly real-time experiments could be able to find it (BTW I know about a similar experiment implemented in Empirica 1, and actually it was implemented using Meteor's DDP stream for communication between the clients, who submitted the position history on stage end; it'll be interesting to see how it will compare to using Empirica 2 ephemeral player updates).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants