GithubHelp home page GithubHelp logo

d2s's Introduction

d2s

The goal of this project is to create an es6 compliant reader/writer of Diablo II save files. Additionally, the library should be able to consume files generated by nokka's Go implementation d2s, therefore the output of reading a save will closely mirror the Go's output.

Examples

Using d2s-ui for a frontend:

API/General Usage
/**
* @see constants.bundle.min.js for an already parsed version of 1.13c data
* @param buffers: object of ALL txt files. example: {
*  "ItemStatCost.txt": "Stat\tIDt\Send...",
*  "string.txt": "WarrivAct1IntroGossip1\t45}Greetings,...",
*  ...
* }
* @return constants: constant data required for parsing built from the txt files.
**/
function readConstantData(buffers: any): types.IConstantData

/**
* @param buffer: Uint8Array representation of the file
* @param constants: constant data used for reading the files. @see readConstantData or constants.bundle.min.js
* @param userConfig: optional configuration. used for if there is a dll edit to allow larger stash sizes. example: {
*  extendedStash: true
* }
* @return d2s: the parsed save information
**/
function read(buffer: Uint8Array, constants: types.IConstantData, userConfig?: types.IConfig): Promise<types.ID2S>;

/**
* @param d2s: the parsed save information
* @param constants: constant data used for reading the files. @see readConstantData or constants.bundle.min.js
* @param userConfig: optional configuration. used for if there is a dll edit to allow larger stash sizes. example: {
*  extendedStash: true
* }
* @return buffer: Uint8Array representation of the file
**/
function write(data: types.ID2S, constants: types.IConstantData, userConfig?: types.IConfig): Promise<Uint8Array>;
Useful Links:

d2s's People

Contributors

dependabot[bot] avatar dschu012 avatar gutnar avatar mgamperl avatar retro-pc avatar shamrickus avatar zeddicus-pl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

d2s's Issues

Stash and Cube are mixed up.

EDIT:
My apologies, please ignore, the issue was related to my browser cache.

When using the save editor, under the items tab, the Stash and the Cube are swapped. So the Stash tab is the Cube, and the Cube is the Stash.

combining magical_attributes alters original attributes

Hi,

In the progress of using your api for a project of mine I discovered the following behaviour:

During the process of combining magical_attributes the original magical_attributes get altered so when using the resulting object to write the items back to a file the magical_attributes are wrong.

Example:

Original data:
image

After writing the item:
image

As you can see the enhanced damage is incorrectly written with additional 100%.

The problem lies here:

function _allAttributes(
  item: types.IItem,
  constants: types.IConstantData
): types.IMagicProperty[] {
  let socketed_attributes = [] as types.IMagicProperty[];
  if (item.socketed_items) {
    for (const i of item.socketed_items) {
      socketed_attributes = socketed_attributes.concat(
        //TODO: deep copy
        ...i.magic_attributes
      );
    }
  }
  let magic_attributes = item.magic_attributes || [];
  let runeword_attributes = item.runeword_attributes || [];
  return [
    ...[],
    //TODO: deep copy
    ...magic_attributes,
    //TODO: deep copy
    ...runeword_attributes,
    //TODO: deep copy
    ...socketed_attributes,
  ].filter((attribute) => attribute != null);
}

I can fix this and submit a pull request but I wanted to clarify which solution you prefer:

  1. deep copy using i.e lodash
  2. deep copy using the hacky way with JSON.parse(JSON.stringify())
  3. deep copy using a custom function
  4. deep copy using the spread operator for all the nested levels

I would propose to use solution 1 or 2 as the other two seem to be error prone or too much effort to solve such a small problem.
Maybe you have a better idea then please let me know.

[Bug] character Menu Appearance is not written to d2s file

_readCharMenuAppearance reads the character menu appearance but there is no corresponding function to write it back to the file again. This should be fixed to make the library more consistent. This should also have no impact on processing nokka/d2s json files.

[Bug] Calculating transform color

There seems to be a bug when calculating the transform color for the magical_name_ids:

//line 115 in attribute_enhancer.ts
for (let i = 0; i < 6; i++) {
  let id = item.magical_name_ids[i];
  if (id) {
    if (i % 5 == 0 && constants.magic_suffixes[id].tc) {
      item.transform_color = constants.magic_suffixes[id].tc;
    } else if (constants.magic_prefixes[id].tc) {
      item.transform_color = constants.magic_prefixes[id].tc;
    }
  }
}

from what I have read about the file format in various sources the 6 different ids mean the following:

0: first prefix
1: first suffix
2: second prefix
3: second suffix
4: third prefix
5: third suffix

so the logic should be something like this:

for(let i = 0; i < 6; i++) {
  let id = item.magical_name_ids[i];
  if (id) {
    if (i % 2 == 0 && constants.magic_prefixes[id] && constants.magic_prefixes[id].tc) { // even is prefixes
      item.transform_color = constants.magic_prefixes[id].tc;            
    } else if(constants.magic_suffixes[id] && constants.magic_suffixes[id].tc) { // odd is suffixes
      item.transform_color = constants.magic_suffixes[id].tc;
    }            
  }
}

I am afraid that I miss something but I can not explain why the i %5 == 0 is used in the current implementation and I can not even get my head around of what the current implementation tries to achieve.

I just discovered that problem because I use a D2 version modded with Project Diablo 2 and there it seems that the id's of prefixes and suffixes differ so it will crash with trying to read .tc from undefined. I think under "normal" circumstances his will not throw an error.

As I said maybe I'm missing something but I think if this is a bug it will not be easily discovered as such because under normal conditions this color transformations seems to be very rarely used in that context.

Missing support for 1.07 items

Hello,

I do a fair bit of time traveling and play D2R with a selection of items obtained in previous patches.
D2R works fine with these items and recognize their stats just fine.

However I get an error reading such a character file. using d2s.

Examples of these items include:
1.07 Shako
1.07 Arkaine's Valor
1.07 Wizardspike
1.10b Call to Arms
1.10b Crescent Moon

Any chance to support character files including these types of items?

Cheers.

Items with Enhanced Defense lost maximun defense +1

The editor removes the maximum defense +1 to the objects with ED attribute:

The Defense of Any Superior Armor spawned with +% Enhanced Defense (ac%) is calculated as follows,

Superior NOT Ethereal: Defense = [(maxac + 1) * (100 + ac%)/100]
Superior AND Ethereal: Defense = [[(maxac + 1) * 3/2] * (100 + ac%)/100]

where 'maxac' denotes the maximum base defense.

PD: Also removes durability from items with the max durability attribute

[Bug] magical_name_ids are set to empty array before writing

It seems that in writeItem the array containing the magical_name_ids is set to an empty array exactly before those ids should get written to file. This seems to be a bug as I can not find an explanation to why this should be correct.

After fixing this, I can see that if the fixes from #17 and #16 are also merged the files written are nearly identical to the files read. I'm still investigation what are the remaining differences but I will open other bugs for that.

 case Quality.Crafted:
              _writeBits(writer, _lookupRareId(item.rare_name, constants), start, offset, 8);
              offset += 8;
              _writeBits(writer, _lookupRareId(item.rare_name2, constants), start, offset, 8);
              offset += 8;
              item.magical_name_ids = []; //<<<--- this is problematic
              for (let i = 0; i < 6; i++) {
                  let magical_name_id = item.magical_name_ids[i];
                  if (magical_name_id) {

pull request will follow

magical_attributes poison damage

Hi,

wanted to start the discussion on how to fix the following in attribute_enhancer.ts

if (prop.s === "poisonmindam") {
        //TODO: this is wrong
        property.values[2] = Math.floor(property.values[2] / 25);
        property.values[0] = Math.floor(
          property.values[0] / property.values[2]
        );
        property.values[1] = Math.floor(
          property.values[1] / property.values[2]
        );
      }

During my usage of this api I discovered that poison damage is incorrect and that reading and writing i.e charms with poison damage results in 0 poison damage.

image

I have not yet took a deep dive into the problem, but I thought I'd raise it here to start the discussion.

D2r tcp/ip pvp question

Your exe works great. Just wondering if you had any idea why when I host a tcp/ip in d2r with my friend... Game crashes after someone dies in a pvp match

Is it possible to read BT Diablo saves?

Hi @dschu012 !

I was wondering of it is possible to read BT Diablo saves. I'm not sure exactly if the issue with reading them is due to stash size, or is it some unknown item IDs.
If it's just IDs, is it possible to parse mod's TXT files to equip the d2s to read these items? Can you point me to any things that I could try out please.

I attach an example BT mod save if you want to try it out yourself.
czarka.d2s.zip

Incorrect calculations for attribute "+X Poison Damage Over Y Seconds"

The calculations for the attribute "+X Poison Damage Over Y Seconds" are incorrect (lines 233-235 attribute_enhancer).
The correct math should be with Math.round instead of Math.floor.

    const min = Math.round((property.values[0] * property.values[2]) / 256);
    const max = Math.round((property.values[1] * property.values[2]) / 256);
    const seconds = Math.round(property.values[2] / 25);

Examples:

  1. Unique Item "Serpent Lord Long Staff":
    prop.values[0] = 40
    prop.values[1] = 40
    prop.values[2] = 75
    40 * 75 = 3,000 / 256 = 11.71875. It is rounded down to 11 Poison Damage, whereas the game item has 12.

  2. Unique Item "Blackbog's Sharp Cinquedeas" (helps to show why Math.ceil would also be wrong, in case one had the idea):
    prop.values[0] = 500
    prop.values[1] = 500
    prop.values[2] = 250
    500 * 250 = 125,000 / 256 = 488.28125. It would be rounded up to 489 Poison Damage, while the correct is 488.

Item stat cost resolved failed in DS2Lib C# version but successfully in D2S JS version

JQ.d2s.zip
stats2

Hi master, I found a strange issue when I resolving item stat cost by using your stable C# DS2Lib (Version 2.0 from NUGET).

In the attached JQ.d2s.zip file, I have a wand which has 2 item stat cost. One is ID 37 ( magic resist ) and value is 11, the other one is ID 39 ( fire resist ) and value is 12.

The item stats can be correctly resolved by JS library version, just check the attached picture.

But failed in C# D2SLib version. My program can successfully get 1st item stat cost as ID=37, but a wrong value 211 instead of 11. And then , the next stat cost ID is resolved as a wrong value 78 instead of 39, at last failed in a not existing cost id 507.

I don't know the differences between JS version and C# version , would you please kindly check the C# code?

Thanks!!!

[Bug] _writeMagicProperties alters the values array when writing the data to a d2s file

_writeMagicProperties should not alter the values array when writing the data as the json object can not be used anymore afterwards

see dschu012's comment here

We could probably just use a variable to keep track of the index we're working with instead of doing property.values.shift() which is altering the array. i.e property.values[idx++] everytime we access it should likely work.

Unable to load characters after game update to v. 1.0.66034

After game update (v. 1.0.66034) editor returns exception on when loading character.

d2s.bundle.min.js:1 Uncaught (in promise) Error: D2S identifier 'aa55aa55' not found at position 0
    at Object.<anonymous> (d2s.bundle.min.js:1)
    at d2s.bundle.min.js:1
    at Object.next (d2s.bundle.min.js:1)
    at d2s.bundle.min.js:1
    at new Promise (<anonymous>)
    at s (d2s.bundle.min.js:1)
    at Object.t.readHeader (d2s.bundle.min.js:1)
    at Object.<anonymous> (d2s.bundle.min.js:1)
    at d2s.bundle.min.js:1
    at Object.next (d2s.bundle.min.js:1) 

[Bug] fix reading of skill charge values in _readMagicProperties

In _readMagicProperties fix the order of the values read for skill charges has to be flipped around

from:

 switch (prop.e) {
              case 3:
                  values.push((v >> 8) & 0xff);  //charges
                  values.push(v & 0xff);  //charges
                  break;

to:

switch (prop.e) {
            case 3:
                  values.push(v & 0xff);  // current charges
                  values.push((v >> 8) & 0xff);  //max charges
                  break;

Cannot upload d2s file since 2.5 version

Hello
First of all thank you very much for this page.
Since 2.5 I am unable to upload a d2s file to https://dschu012.github.io/d2s/ ?
Got OS in HC by a pindle minion because I was under amplify damage. 1005 hp gone like that !
So I wanted to use this functionality, but the file doesn't load anymore.

Could you please have a look in your script ? <3

2.5 Bugs, and 2.2.5 Grail bugs.

So, with 2.5 + 2.2.4 the shared stash has bugged out, along with 3 of my characters

This now works,

With 2.5 + 2.2.5 3 of my characters still cannot be read. This occured at the same time as the stash bug.

However, Shared stash is now working.

3 of my characters are not being loaded by the program. I've included all 3 character files to better aid you in identifying the issue

3 Characters.zip

reading and writing Plugy shared stash files

Hi,

during using your api in a project of mine I though maybe I could contribute a feature to read and write Plugy shared stash files with your api.

I could create a pull request for that if you'd like to have this feature added. I have already developed it and my tests with a stash of 5000 items are fine but I would still need to create some testcases before I could finalize the pull request.

Just wanted to check if you are interested in that contribution.

Thanks!

Cannot read property 'np' of undefined

I'm getting this error when trying to load some D2R saves.

image

Uncaught (in promise) TypeError: Cannot read property 'np' of undefined
    at v (d2s.bundle.min.js:formatted:4326)
    at d2s.bundle.min.js:formatted:4109
    at d2s.bundle.min.js:formatted:3695
    at Object.next (d2s.bundle.min.js:formatted:3708)
    at d2s.bundle.min.js:formatted:3614
    at new Promise (<anonymous>)
    at i (d2s.bundle.min.js:formatted:3593)
    at _ (d2s.bundle.min.js:formatted:3937)
    at d2s.bundle.min.js:formatted:3898
    at d2s.bundle.min.js:formatted:3695

Patch 2.6 support

Error when character have items with new runwords

d2s.bundle.min.js:1 Uncaught (in promise) Error: Save Bits is undefined for stat: 200:unused200 at position 14800
    at v (d2s.bundle.min.js:1:66083)
    at d2s.bundle.min.js:1:60920
    at d2s.bundle.min.js:1:54216
    at Object.next (d2s.bundle.min.js:1:54321)
    at d2s.bundle.min.js:1:53233
    at new Promise (<anonymous>)
    at i (d2s.bundle.min.js:1:52978)
    at _ (d2s.bundle.min.js:1:56527)
    at d2s.bundle.min.js:1:56021
    at d2s.bundle.min.js:1:54216

[Feature] add item quality (normal, exceptional, elite) and item type categories (Armor, Helm, Charm, Rune, ...)

Hi,

another proposal that I'd like to bring up. For certain usecases it might be useful to have the information about the item quality (normal, exceptional, elite) and also the category in which the item falls (coming from itemTyes.txt).

This might be usefull to show a list of items based on certain conditions or have the ability so filter items based on those criterias.

Example:

    ...
    "item_quality": "exceptional",
    "categories": [
      "Helm",
      "Any Armor"
    ],
    ...

I would propose to add the following fields to IItem:

export interface IItem {
  ...
  categories: string[];
  item_quality: string; // could also be enum, as you prefer
}

Additionally enhance function _readTypes(tsv: any, strings: any): any in parser.ts to resolve and store the tree of item categories as well as function _readItems(tsv: any, itemtypes: any, strings: any): any[]in parser.ts to store the item_quality based on the information of the txt files.

fixed by #14

[Proposal] Code Formatting Rules

As I'm doing some pull requests and changes in that library, could we agree on what formating rules should be used?
Is there anything specific you have used in the past so that I can adjust my editor accordingly?

If you are using nothing specific I would suggest to use prettier as it is easy to use and provides sane defaults.

Please let's discuss that also ;)

Undefined error in `char.header.right_swap_skill = constants.skills[reader.ReadUInt32()].s`

default_header.js:26

char.header.right_swap_skill = constants.skills[reader.ReadUInt32()].s; //0x0084

throws undefined because reader.ReadUInt32() returns 262198.

Save file attached. Bone.d2s.zip

Fixed temporarily by adding a ternary operator that checks for undefined first, not sure if that's correct way of dealing with this but it seams to read all other stuff fine. I'm not even able to verify this because I don't have D2R, I'm writing a script for my friend.

Larzuk quest and reward not handled correctly

Although it is easy enough to go and do this quest with a high level character, I noticed that the difference between not completing "Siege of Harrogath" and completing it does not correctly trigger the Larzuk reward (using the editor.) It would probably be best to break that option out into a "Consumed reward" part.

I'm going to try and provide screenshots and the D2S files of a character where I tried to record for you to be able to determine the differences.

Normal Siege On Harrogath.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.