Skip to content

Commit

Permalink
Merge pull request #375 from Naviary3/main
Browse files Browse the repository at this point in the history
When rejoining game, animate last move after a short delay (and other minor changes)
  • Loading branch information
Naviary2 authored Dec 14, 2024
2 parents 3d5976e + 09413e3 commit 6974c91
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 17 deletions.
18 changes: 16 additions & 2 deletions src/client/scripts/esm/chess/logic/gamefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,20 @@ function gamefile(metadata, { moves = [], variantOptions, gameConclusion, clockV
terminateIfGenerating: () => { if (this.mesh.isGenerating) this.mesh.terminate = true; },
/** A flag the mesh generation reads to know whether to terminate or not.
* Do ***NOT*** set manually, call `terminateIfGenerating()` instead. */
terminate: false
terminate: false,
/** A list of functions to execute as soon as the mesh is unlocked. @type {(gamefile => {})[]} */
callbacksOnUnlock: [],
/**
* Releases a single lock off of the mesh.
* If there are zero locks, we execute all functions in callbacksOnUnlock
*/
releaseLock: () => {
this.mesh.locked--;
if (this.mesh.locked > 0) return; // Still Locked
// Fully Unlocked
this.mesh.callbacksOnUnlock.forEach(callback => callback(this));
this.mesh.callbacksOnUnlock.length = 0;
}
};

/** The object that contains the buffer model to render the voids */
Expand Down Expand Up @@ -248,7 +261,8 @@ function gamefile(metadata, { moves = [], variantOptions, gameConclusion, clockV
movepiece.makeAllMovesInGame(this, moves);
/** The game's conclusion, if it is over. For example, `'white checkmate'`
* Server's gameConclusion should overwrite preexisting gameConclusion. */
this.gameConclusion = gameConclusion || this.gameConclusion;
if (gameConclusion) this.gameConclusion = gameConclusion;
else gamefileutility.doGameOverChecks(this);

organizedlines.addMoreUndefineds(this, { regenModel: false });

Expand Down
13 changes: 8 additions & 5 deletions src/client/scripts/esm/chess/logic/movepiece.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 +337,12 @@ function makeAllMovesInGame(gamefile, moves) {

// Make the move in the game!

const isLastMove = i === moves.length - 1;
const animate = isLastMove;
makeMove(gamefile, move, { pushClock: false, updateData: false, concludeGameIfOver: false, doGameOverChecks: false, animate });
// const isLastMove = i === moves.length - 1;
// const animate = isLastMove;
makeMove(gamefile, move, { pushClock: false, updateData: false, concludeGameIfOver: false, doGameOverChecks: false, animate: false });
}

if (moves.length === 0) updateInCheck(gamefile, false);

gamefileutility.doGameOverChecks(gamefile); // Update the gameConclusion
}

/**
Expand Down Expand Up @@ -404,6 +402,11 @@ function calculateMoveFromShortmove(gamefile, shortmove) {
*/

function forwardToFront(gamefile, { flipTurn = true, animateLastMove = true, updateData = true, updateProperties = true, simulated = false } = {}) {
if (updateData && gamefile.mesh.locked > 0) { // The mesh is locked (we cannot forward moves right now)
// Call this function again with the same arguments as soon as the mesh is unlocked
gamefile.mesh.callbacksOnUnlock.push(gamefile => forwardToFront(gamefile, { flipTurn, animateLastMove, updateData, updateProperties, simulated }));
return;
}

while (true) { // For as long as we have moves to forward...
const nextIndex = gamefile.moveIndex + 1;
Expand Down
2 changes: 2 additions & 0 deletions src/client/scripts/esm/chess/logic/wincondition.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const kothCenterSquares = [[4,4],[5,4],[4,5],[5,5]];
* @returns {string | false} The conclusion string, if the game is over. For example, "white checkmate", or "draw stalemate". If the game isn't over, this returns *false*.
*/
function getGameConclusion(gamefile) {
if (!moveutil.areWeViewingLatestMove(gamefile)) throw new Error("Cannot perform game over checks when we're not on the last move.");

return detectAllpiecescaptured(gamefile)
|| detectRoyalCapture(gamefile)
|| detectAllroyalscaptured(gamefile)
Expand Down
33 changes: 32 additions & 1 deletion src/client/scripts/esm/game/chess/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import winconutil from '../../chess/util/winconutil.js';
import sound from '../misc/sound.js';
import spritesheet from '../rendering/spritesheet.js';
import loadingscreen from '../gui/loadingscreen.js';
import movepiece from '../../chess/logic/movepiece.js';
import frametracker from '../rendering/frametracker.js';
// Import End

/**
Expand All @@ -63,6 +65,19 @@ let gamefile;
*/
let gameIsLoading = false;

/**
* The timeout id of the timer that animates the latest-played
* move when rejoining a game, after a short delay
*/
let animateLastMoveTimeoutID;
/**
* The delay, in millis, until the latest-played
* move is animated, after rejoining a game.
*/
const delayOfLatestMoveAnimationOnRejoinMillis = 150;



/**
* Returns the gamefile currently loaded
* @returns {gamefile} The current gamefile
Expand Down Expand Up @@ -199,9 +214,19 @@ async function loadGamefile(newGamefile) {
guinavigation.update_MoveButtons();
guigameinfo.updateWhosTurn(gamefile);

await spritesheet.initSpritesheetForGame(gl, gamefile);
try {
await spritesheet.initSpritesheetForGame(gl, gamefile);
} catch (e) { // An error ocurred during the fetching of piece svgs and spritesheet gen
loadingscreen.onError();
}
guipromotion.initUI(gamefile.gameRules.promotionsAllowed);

// Rewind one move so that we can animate the very final move.
if (newGamefile.moveIndex > -1) movepiece.rewindMove(newGamefile, { updateData: false, removeMove: false, animate: false });
// A small delay to animate the very last move, so the loading screen
// spinny pawn animation has time to fade away.
animateLastMoveTimeoutID = setTimeout(movepiece.forwardToFront, delayOfLatestMoveAnimationOnRejoinMillis, gamefile, { flipTurn: false, updateProperties: false });

// Disable miniimages and arrows if there's over 50K pieces. They render too slow.
if (newGamefile.startSnapshot.pieceCount >= gamefileutility.pieceCountToDisableCheckmate) {
miniimage.disable();
Expand All @@ -221,6 +246,8 @@ async function loadGamefile(newGamefile) {

gameIsLoading = false;
loadingscreen.close();
// Required so the first frame of the game & tiles is rendered once the animation page fades away
frametracker.onVisualChange();
}

/** The canvas will no longer render the current game */
Expand All @@ -239,6 +266,10 @@ function unloadGame() {

spritesheet.deleteSpritesheet();
guipromotion.resetUI();

// Stop the timer that animates the latest-played move when rejoining a game, after a short delay
clearTimeout(animateLastMoveTimeoutID);
animateLastMoveTimeoutID = undefined;
}

/** Called when a game is loaded, loads the event listeners for when we are in a game. */
Expand Down
5 changes: 2 additions & 3 deletions src/client/scripts/esm/game/rendering/board.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,11 @@ function recalcTile_MouseOver() {
const tile_MouseOver_IntAndFloat = getTileMouseOver();

tile_MouseOver_Float = tile_MouseOver_IntAndFloat.tile_Float;
if (options.isDebugModeOn()) console.log("Set tile_MouseOver_Float: " + JSON.stringify(tile_MouseOver_Float));
tile_MouseOver_Int = tile_MouseOver_IntAndFloat.tile_Int;
}

function setTile_MouseOverToUndefined() {
tile_MouseOver_Float = undefined;
if (options.isDebugModeOn()) console.log("Set tile_MouseOver_Float: " + JSON.stringify(tile_MouseOver_Float));
tile_MouseOver_Int = undefined;
}

Expand All @@ -171,7 +169,6 @@ function recalcTile_CrosshairOver() {
const coords = space.convertWorldSpaceToCoords(input.getMouseWorldLocation());

tile_MouseOver_Float = coords;
if (options.isDebugModeOn()) console.log("Set tile_MouseOver_Float: " + JSON.stringify(tile_MouseOver_Float));
tile_MouseOver_Int = [Math.floor(coords[0] + squareCenter), Math.floor(coords[1] + squareCenter)];
}

Expand Down Expand Up @@ -206,6 +203,8 @@ function getTileMouseOver() {
const mouseWorld = input.getMouseWorldLocation(); // [x, y]
const tile_Float = space.convertWorldSpaceToCoords(mouseWorld);
const tile_Int = [Math.floor(tile_Float[0] + squareCenter), Math.floor(tile_Float[1] + squareCenter)];

if (options.isDebugModeOn()) console.log("Getting tile mouse over: " + JSON.stringify(mouseWorld) + " " + JSON.stringify(tile_Float) + " " + JSON.stringify(tile_Int));

return { tile_Float, tile_Int };
}
Expand Down
12 changes: 6 additions & 6 deletions src/client/scripts/esm/game/rendering/piecesmodel.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ async function regenModel(gamefile, colorArgs, giveStatus) { // giveStatus can b
if (gamefile.mesh.terminate) {
console.log("Mesh generation terminated.");
gamefile.mesh.terminate = false;
gamefile.mesh.locked--;
gamefile.mesh.releaseLock();
gamefile.mesh.isGenerating--;
return;
}
Expand All @@ -198,7 +198,7 @@ async function regenModel(gamefile, colorArgs, giveStatus) { // giveStatus can b

if (gamefile.mesh.terminate) {
gamefile.mesh.terminate = false;
gamefile.mesh.locked--;
gamefile.mesh.releaseLock();
gamefile.mesh.isGenerating--;
return;
}
Expand All @@ -209,7 +209,7 @@ async function regenModel(gamefile, colorArgs, giveStatus) { // giveStatus can b

frametracker.onVisualChange();

gamefile.mesh.locked--;
gamefile.mesh.releaseLock();
gamefile.mesh.isGenerating--;
}

Expand Down Expand Up @@ -516,7 +516,7 @@ async function initRotatedPiecesModel(gamefile, ignoreGenerating = false) {
console.log("Mesh generation terminated.");
stats.hideRotateMesh();
if (!ignoreGenerating) gamefile.mesh.terminate = false;
gamefile.mesh.locked--;
gamefile.mesh.releaseLock();
gamefile.mesh.isGenerating--;
return;
}
Expand All @@ -525,7 +525,7 @@ async function initRotatedPiecesModel(gamefile, ignoreGenerating = false) {
console.log("Mesh generation terminated.");
stats.hideRotateMesh();
if (!ignoreGenerating) gamefile.mesh.terminate = false;
gamefile.mesh.locked--;
gamefile.mesh.releaseLock();
gamefile.mesh.isGenerating--;
return;
}
Expand Down Expand Up @@ -684,7 +684,7 @@ async function initRotatedPiecesModel(gamefile, ignoreGenerating = false) {
gamefile.mesh.rotatedModel = gamefile.mesh.usingColoredTextures ? buffermodel.createModel_ColorTextured(gamefile.mesh.rotatedData32, 2, "TRIANGLES", spritesheet.getSpritesheet())
: buffermodel.createModel_Textured(gamefile.mesh.rotatedData32, 2, "TRIANGLES", spritesheet.getSpritesheet());

gamefile.mesh.locked--;
gamefile.mesh.releaseLock();
gamefile.mesh.isGenerating--;
frametracker.onVisualChange();
}
Expand Down
2 changes: 2 additions & 0 deletions src/client/scripts/esm/game/rendering/spritesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ async function fetchAllPieceSVGs(types: string[]) {
})
.catch(error => {
console.error(`Failed to fetch ${pieceType}:`, error); // Log specific error
// Propagate the error so that Promise.all() can reject
throw error;
});
});

Expand Down

0 comments on commit 6974c91

Please sign in to comment.