From 81f1199a9660d3327ed049bf962ab8f4b35ed1fc Mon Sep 17 00:00:00 2001 From: Hash Borgir Date: Fri, 2 Jun 2023 20:43:18 -0600 Subject: [PATCH] ajaxify d2s editor --- CharEditor.php | 32 ++++++------- res/app.js | 44 ++++++++++++++++-- saveCharacter.php | 103 +++++++++++++++++++++++++++++++++++------- src/D2Char.php | 36 +++++++++++++-- src/tabs/Chars.php | 76 +++++++++++++++++++------------ templates/htmlTop.php | 2 +- 6 files changed, 223 insertions(+), 70 deletions(-) diff --git a/CharEditor.php b/CharEditor.php index 0c28dba..d91e14f 100644 --- a/CharEditor.php +++ b/CharEditor.php @@ -43,7 +43,7 @@ foreach ($ISCData as $k => $v) { //$filePath = "D:\Diablo II\MODS\MedianXL2012\save\Test.d2s"; -$filePath = "Test.d2s"; +$filePath = "Pest.d2s"; $char = new D2Char($filePath); //$char->setChar("CharacterStatus", "Died", 0); @@ -51,23 +51,23 @@ $char = new D2Char($filePath); //$char->setChar("CharacterStatus", "Expansion", 1); //$char->setChar("LeftmousebuttonskillID", 223); -$char->setAllSkills(1); -//$char->setSkill(1, 99); +//$char->setAllSkills(1); +$char->setSkill(4, 99); //$char->setChar("CharacterClass", "Necromancer"); // 127 //$char->setChar("CharacterProgression", 1); // 0 in normal, 1 finished normal, 2 finished nm, 3 finished hell //$char->setChar("CharacterStatus", "Died", 1); -$char->setChar("CharacterLevel", 99); -$char->setStat("strength", 270); -$char->setStat("energy", 270); -$char->setStat("dexterity", 270); -$char->setStat("vitality", 270); -$char->setStat("hitpoints", 100); -$char->setStat("maxhp", 150); -$char->setStat("stamina", 280); -$char->setStat("maxstamina", 290); -$char->setStat("mana", 70); -$char->setStat("maxmana", 200); +//$char->setChar("CharacterLevel", 99); +//$char->setStat("strength", 270); +//$char->setStat("energy", 270); +//$char->setStat("dexterity", 270); +//$char->setStat("vitality", 270); +//$char->setStat("hitpoints", 100); +//$char->setStat("maxhp", 150); +//$char->setStat("stamina", 280); +//$char->setStat("maxstamina", 290); +//$char->setStat("mana", 70); +//$char->setStat("maxmana", 200); //$char->setStat("soulcounter", 80); @@ -88,5 +88,5 @@ unset($char); // destroy $char so we can read it again after writing to it to ge $char = new D2Char($filePath); -var_dump($char->cData['CharacterStatus']); -var_dump($char->cData['stats']); +var_dump($char->cData); +//var_dump($char->cData['stats']); diff --git a/res/app.js b/res/app.js index e156821..9ba0b1f 100755 --- a/res/app.js +++ b/res/app.js @@ -334,9 +334,9 @@ $(document).ready(function () { // Get the name of the checkbox var name = $(this).attr("name"); - + // Get the name of the difficulty - var diff = $(this).attr("diff"); + var diff = $(this).attr("diff"); // Get the value of the input named "filePath" var filePath = $("input[name='filePath']").val(); @@ -358,9 +358,9 @@ $(document).ready(function () { // Get the name of the checkbox var name = $(this).attr("name"); - + // Get the name of the difficulty - var diff = $(this).attr("diff"); + var diff = $(this).attr("diff"); // Get the value of the input named "filePath" var filePath = $("input[name='filePath']").val(); @@ -376,5 +376,41 @@ $(document).ready(function () { }); }); + // Get the value of the input named "filePath" + function constructURL(cmd, name, value, filePath) { + return "/saveCharacter.php?cmd=" + cmd + "&name=" + name + "&value=" + value + "&filePath=" + filePath; + } + + $(".charform input[name='Difficulty'], .charform .skill, #CharacterName, #CharacterClass, #CharacterLevel, #CharacterClass").change(function () { + var name = $(this).attr("name"); + var newValue = $(this).val(); + + var cmd = $(this).attr("cmd") || $(this).attr("id") || name; + var parentFormId = $(this).closest("form").attr("id"); + var parentFormClass = $(this).closest("form").attr("class"); + var filePath = $(`#${parentFormId} input[name='filePath']`).val(); + + var url = constructURL(cmd, name, newValue, filePath); + + console.log(url); + console.log(newValue) + + + $.get(url, function (response) { + if (cmd == 'CharacterName') { + location.reload(); + } + console.log(response); + }); + + + + }); + + + + + + });// end document.ready \ No newline at end of file diff --git a/saveCharacter.php b/saveCharacter.php index a3244f1..3b6be2f 100644 --- a/saveCharacter.php +++ b/saveCharacter.php @@ -36,6 +36,11 @@ require_once './src/D2ItemDesc.php'; require_once './src/D2Char.php'; require_once './src/D2CharStructureData.php'; require_once './src/D2ByteReader.php'; +require_once './src/D2BitReader.php'; +require_once './src/D2Item.php'; +require_once './src/D2Char.php'; + +PDO_Connect("sqlite:" . DB_FILE); // Create an instance of D2CharStructureData class $csData = new D2CharStructureData(); @@ -45,8 +50,7 @@ $cmd = $g['cmd']; // Get the file path from the POST data and replace backslashes / $filePath = $g['filePath']; -$filePath = str_replace("\\", "\\\\", $filePath); - +//$filePath = str_replace("\\", "\\\\", $filePath); // Handle the WP check/uncheck if ($cmd == "wp") { $diff = $g['diff']; @@ -74,7 +78,7 @@ if ($cmd == "wp") { $fileContents = file_get_contents($filePath); // Read the contents of the file $ByteReader = new D2ByteReader($fileContents); // Create a new instance of D2ByteReader with the file data - $fileData = $ByteReader->getData(); // Get the data from the ByteReader instance + $fileData = $ByteReader->getData(); // Get the data from the ByteReader instance $wpBytes = $ByteReader->read($offset, 5, 1); $wpBytesToBits = $ByteReader->toBits($wpBytes); @@ -100,22 +104,22 @@ if ($cmd == "wp") { /* * array (size=5) - 'cmd' => string 'q' (length=1) - 'name' => string 'Sisters_Burial_Grounds' (length=29) - 'value' => string '1' (length=1) - 'filePath' => string 'D:\\Diablo II\\MODS\\ironman-dev\\save\\Sorc.d2s' (length=48) - 'diff' => string 'Norm' (length=4) + 'cmd' => string 'q' (length=1) + 'name' => string 'Sisters_Burial_Grounds' (length=29) + 'value' => string '1' (length=1) + 'filePath' => string 'D:\\Diablo II\\MODS\\ironman-dev\\save\\Sorc.d2s' (length=48) + 'diff' => string 'Norm' (length=4) At each quest offset, read a short, 2 bytes. - 347 => 'Den_Of_Evil', - 349 => 'Sisters_Burial_Grounds', - 351 => 'Tools_Of_The_Trade', - 353 => 'The_Search_For_Cain', - 355 => 'The_Forgotten_Tower', - 357 => 'Sisters_To_The_Slaughter', + 347 => 'Den_Of_Evil', + 349 => 'Sisters_Burial_Grounds', + 351 => 'Tools_Of_The_Trade', + 353 => 'The_Search_For_Cain', + 355 => 'The_Forgotten_Tower', + 357 => 'Sisters_To_The_Slaughter', Each short is 16 bytes. - * + * * 0xFEFF = 11111110 11111111 * Short #0 Den of Evil Bit 4 is set when you enter the Den. @@ -153,7 +157,7 @@ if ($cmd == "q") { // Write the byte value 0xFF at the current position fwrite($fp, pack('C', 0xFF)); - + echo "Quest Just Finished, Collect Reward!"; } else { // Set the file pointer position to the quest offset @@ -167,10 +171,75 @@ if ($cmd == "q") { // Write the byte value 0xFF at the current position fwrite($fp, pack('C', 0x00)); - + echo "Quest Not Started Yet!"; } $checksum = (shell_exec("bin\d2scs.exe \"$filePath\"")); fclose($fp); } + +$cmd = $_GET['cmd']; +$name = $_GET['name']; +$value = $_GET['value']; + +$char = new D2Char(basename($filePath)); + +switch ($cmd) { + case "CharacterName": + // Handle CharacterName command + // Validate the character name length + if (strlen($value) < 2 || strlen($value) > 15) { + echo "Character name must be between 2 and 15 characters long."; + // You can handle the error case accordingly (e.g., return an error response) + // Additional validation checks can be added here as needed + } else { + // Validate the character name format + $pattern = '/^[A-Za-z0-9_-]+$/'; // Regular expression pattern for allowed characters + if (!preg_match($pattern, $value)) { + echo "\nCharacter name contains invalid characters. Only alphabets, numbers, underscore, and dash are allowed."; + // Handle the error case accordingly + } else { + // The character name is valid, proceed with further processing + $char->setChar($cmd, $value); + echo "\nCharacter Name and filename Changed"; + } + } + echo "\nHandling CharacterName command - Name: $value, File Path: $filePath"; + break; + case "CharacterClass": + // Handle CharacterClass command + $char->setChar($cmd, $value); + echo "Handling CharacterClass command - Class: $value, File Path: $filePath"; + break; + case "CharacterLevel": + // Handle CharacterLevel command + $char->setChar($cmd, $value); + echo "Handling CharacterLevel command - Level: $value, File Path: $filePath"; + break; + + // handle difficulty wierdly + case "Normal": + $char->setChar("Difficulty", $value); + echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath"; + break; + case "NM": + $char->setChar("Difficulty", $value); + echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath"; + break; + case "Hell": + $char->setChar("Difficulty", $value); + echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath"; + break; + + // skills + case "skills": + //var_dump($char->cData); + $char->setSkill($name, $value); + echo "Handling skills command - Skill: $name, Value: $value, File Path: $filePath"; + break; + default: + // Handle unknown command + echo "Unknown command: $cmd"; + break; +} \ No newline at end of file diff --git a/src/D2Char.php b/src/D2Char.php index ff80023..435065c 100644 --- a/src/D2Char.php +++ b/src/D2Char.php @@ -254,6 +254,7 @@ WHERE sk.charclass = '$class'"; foreach ($skills as $k => $v) { if ($this->skillData[$k]['String']) { $cData['skills'][$k] = [ + 'id' => $this->skillData[$k]['Id'], 'skill' => $this->skillData[$k]['String'], 'points' => $v, 'page' => $this->skillData[$k]['SkillPage'], @@ -373,12 +374,23 @@ WHERE sk.charclass = '$class'"; public function setChar(string $stat, mixed $val, mixed $val2 = null) { switch ($stat) { case 'CharacterName': - if (strlen($val) < 1 || strlen($val) > 15) { - return false; - } $pack = $this->ByteReader->bitsToHexString($this->ByteReader->toBits(pack('Z16', $val))); $this->ByteReader->writeBytes(20, $pack); - rename($this->filePath, $_SESSION['savepath'] . "$val.d2s"); + $this->data = $this->ByteReader->getData(); + $this->save(); + + // file is not being saved, and copied before being saved, hence the bug, fixed + + $fileName = pathinfo($this->filePath, PATHINFO_FILENAME); + $originalFileNames = glob($_SESSION['savepath'] . $fileName . '*'); + foreach ($originalFileNames as $originalFileName) { + $newFileName = $_SESSION['savepath'] . $val . '.' . pathinfo($originalFileName, PATHINFO_EXTENSION); + if ($originalFileName !== $newFileName) { + copy($originalFileName, $newFileName); + unlink($originalFileName); + } + } + break; case "CharacterClass": @@ -398,6 +410,7 @@ WHERE sk.charclass = '$class'"; if ($val > 99) { $val = 99; } + $this->ByteReader->writeByte(43, $val); $this->setStat('level', $val); @@ -443,6 +456,21 @@ WHERE sk.charclass = '$class'"; $this->save(); break; + case 'Difficulty': + switch ($val) { + case "Normal": + $this->data[168] = pack('C', 255); // 1000 0000 MSB = Difficulty + break; + case "NM": + $this->data[169] = pack('C', 255); + break; + case "Hell": + $this->data[170] = pack('C', 255); + break; + } + + break; + case 'LeftmousebuttonskillID': $this->ByteReader->writeBytes(120, dechex($val)); break; diff --git a/src/tabs/Chars.php b/src/tabs/Chars.php index 55339f6..be2e2f2 100644 --- a/src/tabs/Chars.php +++ b/src/tabs/Chars.php @@ -8,7 +8,7 @@ $tabs .= << - {$c->cData['CharacterName']} + {$c->cData['CharacterName']} EOT; echo $tabs; @@ -39,19 +39,17 @@ EOT; } $wps = ''; - $wps .= ""; - $wps .= "
"; - $wps .= ""; - $wps .= "
"; + //$wps .= ""; + //$wps .= "
"; + //$wps .= ""; + //$wps .= "
"; - - foreach ($c->cData['Waypoints'] as $diff => $waypoints) { // diff is difficulty $wps .= "

$diff

"; array_pop($waypoints); $wp_count = 0; foreach ($waypoints as $k => $v) { - + $kD = str_replace("_", " ", $k); $kD = str_replace([" NM", " Hell"], "", $kD); $checked = ($v == 1 && $k != '') ? 'checked ' : ''; @@ -60,7 +58,6 @@ EOT; $wps .= "
"; $wp_count++; } - } $classOptions = [ @@ -74,54 +71,77 @@ EOT; } $difficulties = [ - 'Normal' => 'DifficultyNormal', - 'NM' => 'DifficultyNM', - 'Hell' => 'DifficultyHell' + 'Normal' => '1', + 'NM' => '2', + 'Hell' => '3' ]; $radio = ''; foreach ($difficulties as $difficulty => $id) { $checked = ($c->cData['Difficulty'][$difficulty] == 1) ? 'checked' : ''; - $radio .= "$difficulty
"; + $radio .= ""; + $radio .= "
"; } $skills = ''; + /* + 'skills' => + array (size=1) + 'skills' => + array (size=52) + 0 => + array (size=7) + 'id' => int 36 + 'skill' => string 'Fire Bolt' (length=9) + 'points' => int 0 + 'page' => int 3 + 'row' => int 1 + 'col' => int 2 + 'icon' => int 0 + */ + $skillcounter = 1; foreach ($c->cData['skills']['skills'] as $k => $skill) { - $skills .= ": {$skill['skill']}
"; + $skills .= ": {$skill['skill']}
"; + $skillcounter++; } // dump($c['Waypoints']); $tabContent .= << -
+
+
-

{$c->cData['CharacterName']}

- -
- - +
+ - Level:
- $radio - $skills +
+ Character Level:
+
+ +
+

Skills

+ $skills +
-

Quests

+

Quests

$quests
-

Waypoints

+

Waypoints

$wps
- +
EOT; diff --git a/templates/htmlTop.php b/templates/htmlTop.php index 2d262d9..005a4b6 100644 --- a/templates/htmlTop.php +++ b/templates/htmlTop.php @@ -179,7 +179,7 @@ $htmltop = <<