Skip to content

Commit

Permalink
little things
Browse files Browse the repository at this point in the history
  • Loading branch information
doctorsolana committed Sep 27, 2024
1 parent b9e66b0 commit 46922c9
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 173 deletions.
43 changes: 21 additions & 22 deletions apps/multiplayer_demo/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// App.tsx
import React, { useState, useEffect, useMemo, useCallback } from 'react'
import { WalletModalButton } from '@solana/wallet-adapter-react-ui'
import { PublicKey, Connection } from '@solana/web3.js'
Expand Down Expand Up @@ -25,6 +26,7 @@ const App = () => {
const [maxPlayers, setMaxPlayers] = useState('')
const [tokenMint, setTokenMint] = useState('So11111111111111111111111111111111111111112')
const [currentBlockchainTime, setCurrentBlockchainTime] = useState(null)
const [fetchTime, setFetchTime] = useState(null) // Record the local time when fetching data
const [gameDuration, setGameDuration] = useState('')
const [wagerAmount, setWagerAmount] = useState('')
const [winners, setWinners] = useState('')
Expand All @@ -38,13 +40,15 @@ const App = () => {
return new MultiplayerProvider(connection, wallet)
}, [connection, wallet])

// Define fetchGames using useCallback to prevent unnecessary re-renders
// Fetch games and blockchain time
const fetchGames = useCallback(async () => {
if (!provider) return
try {
const gameAccounts = await provider.fetchGames()
const currentTimestamp = await provider.getCurrentBlockchainTime()
const fetchTime = Date.now() // Local time when data was fetched
setCurrentBlockchainTime(currentTimestamp)
setFetchTime(fetchTime)
setGames(gameAccounts)
} catch (error) {
console.error('Error fetching games:', error)
Expand All @@ -54,27 +58,27 @@ const App = () => {
useEffect(() => {
if (!wallet.connected || !provider) return

// Fetch games initially
// Initial fetch
fetchGames()

// Subscribe to program account changes
const subscriptionId = connection.onProgramAccountChange(
new PublicKey(MULTIPLAYER_PROGRAM_ID),
(info) => {
// Whenever an account owned by the program changes, fetch updated games
() => {
// Fetch updated games when any program account changes
fetchGames()
},
'confirmed',
)

// Cleanup subscription on unmount or dependency change
// Cleanup subscription on unmount
return () => {
connection.removeProgramAccountChangeListener(subscriptionId)
};
}
}, [wallet.connected, provider, connection, fetchGames])

const gambaConfig = async () => {
if (!provider) return;
if (!provider) return
try {
const gambaFeeAddress = new PublicKey('BoDeHdqeVd2ds6keWYp2r63hwpL4UfjvNEPCyvVz38mQ')
const gambaFeeBps = new BN(100) // 1%
Expand All @@ -93,7 +97,7 @@ const App = () => {
} catch (error) {
console.error('Error configuring gamba:', error)
}
};
}

const createGame = async () => {
if (!provider) return
Expand All @@ -105,15 +109,15 @@ const App = () => {
gameType === WagerType.SameWager ? 0 : 1,
parseInt(wagerAmount),
parseInt(gameDuration),
600, // optional hard settle, if not defined settles in 24 hours
600, // Optional hard settle duration (in seconds)
)

const txId = await sendTransaction(provider.anchorProvider, instruction, undefined, 5000);
const txId = await sendTransaction(provider.anchorProvider, instruction, undefined, 5000)
console.log('Transaction ID:', txId)
} catch (error) {
console.error('Error creating game:', error)
}
};
}

const joinGame = async (game, creatorAddressPubKey, creatorFee) => {
if (!provider) return
Expand Down Expand Up @@ -147,7 +151,7 @@ const App = () => {
} catch (error) {
console.error('Error settling game:', error)
}
};
}

return (
<div>
Expand Down Expand Up @@ -218,15 +222,13 @@ const App = () => {
</div>
<button onClick={createGame}>Create Game</button>
</div>
<div className="button-row">
{/* Removed the Refresh Games button since updates are handled via subscriptions */}
</div>
<div>
{games.map((game, index) => (
<GameCard
key={index}
game={game}
currentBlockchainTime={currentBlockchainTime}
fetchTime={fetchTime}
joinGame={joinGame}
leaveGame={leaveGame}
settleGame={settleGame}
Expand All @@ -235,12 +237,9 @@ const App = () => {
/>
))}
</div>
{wallet.connected && wallet.publicKey && (
<RecentMultiplayerEvents address={wallet.publicKey} />
)}

{wallet.connected && wallet.publicKey && <RecentMultiplayerEvents />}
</div>
);
};
)
}

export default App;
export default App
68 changes: 54 additions & 14 deletions apps/multiplayer_demo/src/components/GameCard.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,54 @@
import React from 'react'
// GameCard.tsx
import React, { useState, useEffect } from 'react'
import { PublicKey } from '@solana/web3.js'
import { BN } from '@coral-xyz/anchor'
import { formatPublicKey, parseGameState, parseWagerType } from '../utils'

interface GameCardProps {
game: any;
currentBlockchainTime: number | null;
joinGame: (game: any, creatorAddressPubKey: PublicKey, creatorFee: number) => void;
leaveGame: (game: any) => void;
settleGame: (game: any) => void;
customWager: string;
setCustomWager: React.Dispatch<React.SetStateAction<string>>;
game: any
currentBlockchainTime: number | null
fetchTime: number | null
joinGame: (game: any, creatorAddressPubKey: PublicKey, creatorFee: number) => void
leaveGame: (game: any) => void
settleGame: (game: any) => void
customWager: string
setCustomWager: React.Dispatch<React.SetStateAction<string>>
}

const GameCard: React.FC<GameCardProps> = ({
game,
currentBlockchainTime,
fetchTime,
joinGame,
leaveGame,
settleGame,
customWager,
setCustomWager,
}) => {
const expirationTimestamp = new BN(game.account.softExpirationTimestamp).toNumber()
const timeUntilExpiration = currentBlockchainTime ? Math.max(0, expirationTimestamp - currentBlockchainTime) : null
const [timeUntilExpiration, setTimeUntilExpiration] = useState<number | null>(null)

useEffect(() => {
if (currentBlockchainTime !== null && fetchTime !== null) {
const expirationTimestamp = new BN(game.account.softExpirationTimestamp).toNumber()
const initialElapsedTime = (Date.now() - fetchTime) / 1000 // Time elapsed since data fetch in seconds
const initialTimeUntilExpiration = Math.max(
0,
expirationTimestamp - (currentBlockchainTime + initialElapsedTime),
)
setTimeUntilExpiration(initialTimeUntilExpiration)

const interval = setInterval(() => {
setTimeUntilExpiration((prev) => {
if (prev !== null) {
return Math.max(0, prev - 1)
}
return null
})
}, 1000)

return () => clearInterval(interval)
}
}, [currentBlockchainTime, fetchTime, game.account.softExpirationTimestamp])

return (
<div className="gameCard">
Expand All @@ -35,7 +60,10 @@ const GameCard: React.FC<GameCardProps> = ({
<div>Winners: {game.account.winners.toString()}</div>
<div>Game ID: {game.account.gameId.toString()}</div>
<div>Game Expiration Timestamp: {game.account.softExpirationTimestamp.toString()}</div>
<div>Time Until Expiration: {timeUntilExpiration !== null ? `${timeUntilExpiration} seconds` : 'Loading...'}</div>
<div>
Time Until Expiration:{' '}
{timeUntilExpiration !== null ? `${Math.floor(timeUntilExpiration)} seconds` : 'Loading...'}
</div>
<div>Wager Type: {parseWagerType(game.account.wagerType)}</div>
<div>Wager: {game.account.wager.toString()}</div>
<div>
Expand All @@ -52,18 +80,30 @@ const GameCard: React.FC<GameCardProps> = ({
</div>
<div className="buttonContainer">
<div className="joinLeaveButtons">
<button onClick={() => joinGame(game, new PublicKey('FaicqUdVsesTNxGRiVo3ZWMgrxdvhAVpSH7CPFnEN3aF'), 100)}>Join Game</button>
<button
onClick={() =>
joinGame(
game,
new PublicKey('FaicqUdVsesTNxGRiVo3ZWMgrxdvhAVpSH7CPFnEN3aF'),
100,
)
}
>
Join Game
</button>
<button onClick={() => leaveGame(game)}>Leave Game</button>
<input
type="number"
placeholder="Enter wager amount"
value={customWager}
onChange={e => setCustomWager(e.target.value)}
onChange={(e) => setCustomWager(e.target.value)}
className="input-field"
/>
</div>
{(parseGameState(game.account.state) === 'Playing' || timeUntilExpiration === 0) && (
<button className="settleButton" onClick={() => settleGame(game)}>Settle Game</button>
<button className="settleButton" onClick={() => settleGame(game)}>
Settle Game
</button>
)}
</div>
</div>
Expand Down
61 changes: 0 additions & 61 deletions apps/multiplayer_demo/src/components/RecentEvents.tsx

This file was deleted.

14 changes: 8 additions & 6 deletions apps/multiplayer_demo/src/components/RecentMultiplayerEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,33 @@ const RecentMultiplayerEvents = () => {
const [recentEvents, setRecentEvents] = useState([]);

useEffect(() => {
const setupEventListener = async () => {
const setupEventListener = () => {
const programId = MULTIPLAYER_PROGRAM_ID;

// Subscribe to program logs
const subscriptionId = connection.onLogs(
programId,
(logs, context) => {
const events = parseTransactionEvents(logs.logs);
const newEvents = events.map(event => ({
const newEvents = events.map((event) => ({
...event,
signature: context.signature,
slot: context.slot,
time: Date.now(),
}));

setRecentEvents(prevEvents => [...newEvents, ...prevEvents]);
setRecentEvents((prevEvents) => [...newEvents, ...prevEvents]);
},
'confirmed'
'confirmed',
);

return () => {
connection.removeOnLogsListener(subscriptionId);
};
};

setupEventListener();
const cleanup = setupEventListener();
return cleanup;
}, [connection]);

return (
Expand Down Expand Up @@ -61,7 +62,8 @@ const RecentMultiplayerEvents = () => {
<div style={{ paddingLeft: '10px' }}>
{Object.entries(event.data).map(([key, value]) => (
<div key={key}>
<strong>{key}:</strong> {typeof value === 'object' ? JSON.stringify(value) : value}
<strong>{key}:</strong>{' '}
{typeof value === 'object' ? JSON.stringify(value) : value}
</div>
))}
</div>
Expand Down
Loading

0 comments on commit 46922c9

Please sign in to comment.