UPDATE: Add ldiff
This commit is contained in:
378
frontend/src/pages/diff/index.tsx
Normal file
378
frontend/src/pages/diff/index.tsx
Normal file
@@ -0,0 +1,378 @@
|
||||
import useSettingStore from "@/stores/settingStore"
|
||||
import { Check, Folder, File, X, Settings } from "lucide-react"
|
||||
import { useEffect } from "react"
|
||||
import { toast } from "react-toastify"
|
||||
import { DiffService} from "@bindings/firefly-launcher/internal/diff-service"
|
||||
import { FSService } from "@bindings/firefly-launcher/internal/fs-service"
|
||||
import { motion } from "motion/react"
|
||||
import useDiffStore from "@/stores/diffStore"
|
||||
|
||||
export default function DiffPage() {
|
||||
const { gameDir, setGameDir } = useSettingStore()
|
||||
const {
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
folderCheckResult,
|
||||
setFolderCheckResult,
|
||||
diffDir,
|
||||
setDiffDir,
|
||||
diffCheckResult,
|
||||
setDiffCheckResult,
|
||||
isDiffLoading,
|
||||
setIsDiffLoading,
|
||||
progressUpdate,
|
||||
setProgressUpdate,
|
||||
maxProgressUpdate,
|
||||
setMaxProgressUpdate,
|
||||
stageType,
|
||||
setStageType,
|
||||
messageUpdate,
|
||||
setMessageUpdate
|
||||
} = useDiffStore()
|
||||
|
||||
useEffect(() => {
|
||||
const getLanguage = async () => {
|
||||
if (gameDir) {
|
||||
const subPath = 'StarRail_Data/StreamingAssets/DesignData/Windows'
|
||||
const fullPath = `${gameDir}/${subPath}`
|
||||
|
||||
const exists = await FSService.DirExists(fullPath)
|
||||
if (exists) {
|
||||
setFolderCheckResult('success')
|
||||
} else {
|
||||
setFolderCheckResult('error')
|
||||
setGameDir('')
|
||||
}
|
||||
}
|
||||
}
|
||||
getLanguage()
|
||||
}, [gameDir])
|
||||
|
||||
const handlePickGameFolder = async () => {
|
||||
try {
|
||||
setIsLoading({game: true, diff: false})
|
||||
const basePath = await FSService.PickFolder()
|
||||
if (basePath) {
|
||||
setGameDir(basePath)
|
||||
const subPath = 'StarRail_Data/StreamingAssets/DesignData/Windows'
|
||||
const fullPath = `${basePath}/${subPath}`
|
||||
|
||||
const exists = await FSService.DirExists(fullPath)
|
||||
setFolderCheckResult(exists ? 'success' : 'error')
|
||||
setGameDir(exists ? basePath : '')
|
||||
if (!exists) {
|
||||
toast.error('Game directory not found. Please select the correct folder.')
|
||||
}
|
||||
} else {
|
||||
toast.error('No folder path selected')
|
||||
setFolderCheckResult('error')
|
||||
setGameDir('')
|
||||
}
|
||||
} catch (err: any) {
|
||||
toast.error('PickFolder error:', err)
|
||||
setFolderCheckResult('error')
|
||||
} finally {
|
||||
setIsLoading({game: false, diff: false})
|
||||
}
|
||||
}
|
||||
|
||||
const handlePickDiffFile = async () => {
|
||||
try {
|
||||
setIsLoading({game: false, diff: true})
|
||||
const basePath = await FSService.PickFile("")
|
||||
if (basePath) {
|
||||
if (!basePath.endsWith(".7z") && !basePath.endsWith(".zip") && !basePath.endsWith(".rar")) {
|
||||
toast.error('Not valid file type')
|
||||
setDiffCheckResult('error')
|
||||
setDiffDir('')
|
||||
return
|
||||
}
|
||||
const [isOk, validType, errorType] = await DiffService.CheckTypeHDiff(basePath)
|
||||
if (!isOk) {
|
||||
toast.error(errorType)
|
||||
setDiffCheckResult('error')
|
||||
setDiffDir('')
|
||||
return
|
||||
}
|
||||
if (validType == "") {
|
||||
toast.error('Not valid file type')
|
||||
setDiffCheckResult('error')
|
||||
setDiffDir('')
|
||||
return
|
||||
}
|
||||
setDiffDir(basePath)
|
||||
setDiffCheckResult('success')
|
||||
} else {
|
||||
toast.error('No file path selected')
|
||||
setDiffCheckResult('error')
|
||||
setDiffDir('')
|
||||
}
|
||||
} catch (err: any) {
|
||||
toast.error('PickFile error:', err)
|
||||
setDiffCheckResult('error')
|
||||
} finally {
|
||||
setIsLoading({game: false, diff: false})
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateGame = async () => {
|
||||
try {
|
||||
setIsDiffLoading(true)
|
||||
if (!gameDir || !diffDir) {
|
||||
toast.error('Please select game directory and diff file')
|
||||
setIsDiffLoading(false)
|
||||
return
|
||||
}
|
||||
setStageType('Check Type HDiff')
|
||||
setProgressUpdate(0)
|
||||
setMaxProgressUpdate(1)
|
||||
const [isOk, validType, errorType] = await DiffService.CheckTypeHDiff(diffDir)
|
||||
if (!isOk) {
|
||||
toast.error(errorType)
|
||||
setIsDiffLoading(false)
|
||||
return
|
||||
}
|
||||
setProgressUpdate(1)
|
||||
|
||||
|
||||
|
||||
if (validType === 'hdiffmap.json') {
|
||||
setStageType('Version Validate')
|
||||
setProgressUpdate(0)
|
||||
setMaxProgressUpdate(1)
|
||||
const [validVersion, errorVersion] = await DiffService.VersionValidate(gameDir, diffDir)
|
||||
if (!validVersion) {
|
||||
toast.error(errorVersion)
|
||||
setIsDiffLoading(false)
|
||||
return
|
||||
}
|
||||
setProgressUpdate(1)
|
||||
}
|
||||
|
||||
const isSkipVerify = validType === 'manifest' || validType === 'hdifffiles.txt'
|
||||
setStageType('Data Extract')
|
||||
const [validData, errorData] = await DiffService.DataExtract(gameDir, diffDir, isSkipVerify)
|
||||
if (!validData) {
|
||||
toast.error(errorData)
|
||||
setIsDiffLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
setStageType('Cut Data')
|
||||
setMessageUpdate('')
|
||||
const [validCut, errorCut] = await DiffService.CutData(gameDir)
|
||||
if (!validCut) {
|
||||
toast.error(errorCut)
|
||||
setIsDiffLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
if ( validType === 'hdifffiles.txt' || validType === 'hdiffmap.json') {
|
||||
setStageType('Patch Data')
|
||||
const [validPatch, errorPatch] = await DiffService.HDiffPatchData(gameDir)
|
||||
if (!validPatch) {
|
||||
toast.error(errorPatch)
|
||||
setIsDiffLoading(false)
|
||||
return
|
||||
}
|
||||
setStageType('Delete old files')
|
||||
const [validDelete, errorDelete] = await DiffService.DeleteFiles(gameDir)
|
||||
if (!validDelete) {
|
||||
toast.error(errorDelete)
|
||||
setIsDiffLoading(false)
|
||||
return
|
||||
}
|
||||
} else if (validType === 'manifest') {
|
||||
setStageType('Patch Data')
|
||||
const [validPatch, errorPatch] = await DiffService.LDiffPatchData(gameDir)
|
||||
if (!validPatch) {
|
||||
toast.error(errorPatch)
|
||||
setIsDiffLoading(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
toast.success('Update game completed')
|
||||
} catch (err: any) {
|
||||
console.error(err)
|
||||
toast.error('PickFile error:', err)
|
||||
setIsDiffLoading(false)
|
||||
} finally {
|
||||
setIsDiffLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-2 mx-4">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-2">
|
||||
<h1 className="text-4xl font-bold mb-2">
|
||||
🎮 Game Update by Hdiffz
|
||||
</h1>
|
||||
<p className="">Help you update game with hdiffz</p>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="rounded-2xl p-2 space-y-4">
|
||||
|
||||
{/* Folder Selection Section */}
|
||||
<div className="pb-2">
|
||||
<h2 className="text-2xl font-semibold mb-4 flex items-center gap-2">
|
||||
<Folder className="text-primary" size={24} />
|
||||
Game Directory
|
||||
</h2>
|
||||
|
||||
<div className="space-y-1">
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-2 items-center'>
|
||||
<button
|
||||
onClick={handlePickGameFolder}
|
||||
disabled={isLoading.game}
|
||||
className="btn btn-primary"
|
||||
>
|
||||
<Folder size={20} />
|
||||
{isLoading.game ? 'Selecting...' : 'Select Game Folder'}
|
||||
</button>
|
||||
|
||||
{gameDir && (
|
||||
<div className="rounded-lg p-2">
|
||||
<p className="font-mono text-sm px-3 py-2 rounded border truncate max-w-full overflow-hidden whitespace-nowrap">
|
||||
{gameDir}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{folderCheckResult && (
|
||||
<div className={`flex items-center gap-2 p-3 rounded-lg ${folderCheckResult === 'success'
|
||||
? 'bg-success/5 text-success border border-success'
|
||||
: 'bg-error/5 text-error border border-error'
|
||||
}`}>
|
||||
{folderCheckResult === 'success' ? (
|
||||
<>
|
||||
<Check size={20} />
|
||||
<span>Valid game directory found!</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<X size={20} />
|
||||
<span>Game directory not found. Please select the correct folder.</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Folder Selection Section */}
|
||||
<div className="pb-2">
|
||||
<h2 className="text-2xl font-semibold mb-4 flex items-center gap-2">
|
||||
<File className="text-primary" size={24} />
|
||||
Diff file Directory
|
||||
</h2>
|
||||
|
||||
<div className="space-y-1">
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-2 items-center'>
|
||||
<button
|
||||
onClick={handlePickDiffFile}
|
||||
disabled={isLoading.diff}
|
||||
className="btn btn-primary"
|
||||
>
|
||||
<File size={20} />
|
||||
{isLoading.diff ? 'Selecting...' : 'Select Diff file Folder'}
|
||||
</button>
|
||||
|
||||
{diffDir && (
|
||||
<div className="rounded-lg p-2">
|
||||
<p className="font-mono text-sm px-3 py-2 rounded border truncate max-w-full overflow-hidden whitespace-nowrap">
|
||||
{diffDir}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{diffCheckResult && (
|
||||
<div className={`flex items-center gap-2 p-3 mt-2 rounded-lg ${diffCheckResult === 'success'
|
||||
? 'bg-success/5 text-success border border-success'
|
||||
: 'bg-error/5 text-error border border-error'
|
||||
}`}>
|
||||
{diffCheckResult === 'success' ? (
|
||||
<>
|
||||
<Check size={20} />
|
||||
<span>Valid diff file found!</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<X size={20} />
|
||||
<span>Diff file not found. Please select the correct file.</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Apply Button */}
|
||||
<div className="mt-6 flex justify-center">
|
||||
<button
|
||||
onClick={handleUpdateGame}
|
||||
disabled={!diffDir || !gameDir || isLoading.game || isLoading.diff}
|
||||
className="bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 disabled:from-gray-400 disabled:to-gray-500 text-white px-8 py-3 rounded-lg font-medium transition-all duration-200 flex items-center gap-2 shadow-lg hover:shadow-xl disabled:cursor-not-allowed cursor-pointer"
|
||||
>
|
||||
<Settings size={20} />
|
||||
{isDiffLoading ? 'Updating...' : 'Update Game'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isDiffLoading && (
|
||||
<div className="fixed inset-0 z-50 h-full flex items-center justify-center bg-black/40 backdrop-blur-sm">
|
||||
<div className="relative w-[90%] max-w-5xl bg-base-100 text-base-content rounded-xl border border-purple-500/50 shadow-lg shadow-purple-500/20">
|
||||
<div className="border-b border-purple-500/30 px-6 py-4 mb-4 text-center">
|
||||
<h3 className="font-bold text-2xl text-transparent bg-clip-text bg-gradient-to-r from-pink-400 to-cyan-400">
|
||||
Update Game
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="px-6 pb-6">
|
||||
<div className="w-full p-4">
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-center items-center text-sm text-white/80">
|
||||
<span className="font-bold text-lg text-warning">{stageType}:</span>
|
||||
<div className="flex items-center gap-4 ml-2">
|
||||
{stageType !== 'Cut Data' && <span className="text-white font-bold">{progressUpdate.toFixed(0)} / {maxProgressUpdate.toFixed(0)}</span>}
|
||||
{stageType === 'Cut Data' && <span className="text-white font-bold truncate max-w-full overflow-hidden whitespace-nowrap">{messageUpdate}</span>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full bg-white/20 rounded-full h-2 overflow-hidden">
|
||||
<motion.div
|
||||
className="h-full bg-gradient-to-r from-cyan-400 to-blue-500 rounded-full"
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: `${(progressUpdate/maxProgressUpdate)*100}%` }}
|
||||
transition={{ duration: 0.3 }}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-center text-lg text-white/60">
|
||||
Please wait...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Instructions */}
|
||||
<div className="bg-info/5 rounded-lg p-4 border border-info/30 mt-6">
|
||||
<h3 className="font-medium text-error mb-2">📋 Instructions:</h3>
|
||||
<ol className="text-sm text-error space-y-1">
|
||||
<li>1. Click "Select Game Folder" and choose your game's root directory</li>
|
||||
<li>2. Wait for the system to validate the game directory</li>
|
||||
<li>3. Click "Select Diff file Folder" and choose your diff file's root directory</li>
|
||||
<li>4. Wait for the system to validate the diff file directory</li>
|
||||
<li>5. Click "Update Game" to save your changes</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user