Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of Hercules Ultimate Storage System (HUSS) #3330

Open
wants to merge 28 commits into
base: master
Choose a base branch
from

Conversation

jasonch35
Copy link
Contributor

@jasonch35 jasonch35 commented Nov 4, 2024

Pull Request Prelude

Changes Proposed

  • Implementation of the Hercules Ultimate Storage System
  • Storages can now be created through a configuration file that describes their attributes.
  • Integrated storage_constants (Constant) into the configuration so that it can be assigned dynamically
  • Capacity is capped by MAX_STORAGE at config reading

Storage Configuration

{
        Id: (int)			Unique Identifier
        Name: (string)			Name of the storage sent to the client.
        Constant: (string)		Storage constant to be used by scripts
        Capacity: (int)			Maximum capacity of the storage.
}

Script Command
openstorage(<storage_constant>{, <storage_mode>});

Storage Modes

  • STORAGE_ACCESS_VIEW: View storage only.
  • STORAGE_ACCESS_GET: Allow retrieving items from storage.
  • STORAGE_ACCESS_PUT: Allow depositing items into storage.
  • STORAGE_ACCESS_ALL: (Default mode) Full access for viewing, retrieving, and depositing items.

All atcommands utilizing storage has been updated as well:

  • @storage <storage name/id>
  • @storeall <storage name/id>
  • @clearstorage <storage name/id>
  • @storagelist <storage name/id>

Issues addressed:

Upon testing the following has been fixed as well:

Credits to: @sagunkho and @dastgirp

Let's gooooo let's push this through!

This commit includes:
- HUSS main implementation
- openstorage script command update
- @storage atcommand update
- @clearstorage atcommand update
- @storeall atcommand update
- @storagelist atcommand update
- There can be an unlimited amount of storages and limits.
- All setting names are case-sensitive and must be keyed accurately.
- The storage capacity will default to MAX_STORAGE in mmo.h if it is set higher
- Storage ID 1 is the default (official) storage for accounts.
- Integrated storage_constants (Constant) into the configuration so that it can be assigned dynamically
@vBrenth
Copy link

vBrenth commented Nov 6, 2024

Thank you @jasonch35 hope this one will get implemented.
Also i want to ask about Storage Limit its still 600 correct?

@jasonch35
Copy link
Contributor Author

Thank you @jasonch35 hope this one will get implemented.
Also i want to ask about Storage Limit its still 600 correct?

Yes, Limit is capped by MAX_STORAGE which is 600 by default.

@jasonch35
Copy link
Contributor Author

jasonch35 commented Nov 7, 2024

Btw, I kept the "default" storage without warning/errors as it is set as default in original Herc's branch.
Commands and scripts will result in "no storage found" message if it is removed/changed.
Or parameter error on server start if its constant isn't found.
I believe server owners should be responsible for adjusting the configuration file, just as they would if they manually remove Red_Potion in item_db.conf, they'd have to manually remove them in scripts if they choose to do so.

Copy link
Member

@guilherme-gm guilherme-gm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for putting the effort in fixing the previous PRs!
I did not try running it yet, but from the code review, I got those questions/points that may need to be addressed.

src/map/storage.c Show resolved Hide resolved
src/map/storage.c Outdated Show resolved Hide resolved
src/map/storage.c Show resolved Hide resolved
@MishimaHaruna MishimaHaruna added this to the Release v2024.11 milestone Nov 30, 2024
sql-files/main.sql Show resolved Hide resolved
src/common/msgtable.h Show resolved Hide resolved
src/map/intif.h Outdated Show resolved Hide resolved
if (VECTOR_LENGTH(cp.item) > 0) {

int *delete = aCalloc(cp_size, sizeof(int));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a VECTOR as well, removing the need to allocate it to an arbitrarily large size. It can be expanded as items to be deleted are found, with an appropriate growth step.
This would remove the need for a couple of confusing 'size' support vars

Copy link
Contributor Author

@jasonch35 jasonch35 Dec 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted to local variables since we hardcoded to a fixed MAX_STORAGE anyway.
I think it'll be much more efficient this way.


int cp_size = inter_storage->fromsql(account_id, storage_id, &cp, 0);

bool* matched_p = aCalloc(VECTOR_LENGTH(p->item), sizeof(bool));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good candidate for a VECTOR, to avoid doing array subscript on a bare pointer and to make its length clear to the reader

Copy link
Contributor Author

@jasonch35 jasonch35 Dec 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above:

Reverted to local variables since we hardcoded to a fixed MAX_STORAGE anyway.
I think it'll be much more efficient this way.

nullpo_retr(false, filename);

if (!imported)
VECTOR_INIT(storage->configuration);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change this to VECTOR_CLEAR() and move the init to storage_defaults() so that there are no uninitialized variables

Copy link
Contributor Author

@jasonch35 jasonch35 Dec 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking. I wanna drop this feature altogether. Since storage.conf will be as is almost forever officially similar to other configs. There is no point having additional fields and imports. Nvm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9f08c77

I transferred config read function below the initialization.

src/common/mmo.h Outdated
Comment on lines 647 to 652
/* Hercules Ultimate Storage System [Smokexyz/Hercules] */
struct storage_settings {
int uid; ///< Storage Identifier.
char name[NAME_LENGTH]; ///< Storage Name
int capacity; ///< Item Capacity.
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This belongs to the map server and the char server has no business with it. Please move it to storage.h

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6e485b3

Also regenerated HPM for this.

src/map/storage.c Outdated Show resolved Hide resolved
src/map/storage.c Show resolved Hide resolved
storage->config_read_additional_fields(t, &s_conf, filename);

if (imported) {
ARR_FIND(0, VECTOR_LENGTH(storage->configuration), i, VECTOR_INDEX(storage->configuration, i).uid == s_conf.uid);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it stands, this seems an impossible condition (the duplicate check above was designed to only be executed if imported == false perhaps?)

Copy link
Contributor Author

@jasonch35 jasonch35 Dec 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above:
I've been thinking. I wanna drop this feature altogether. Since storage.conf will be as is almost forever officially similar to other configs. There is no point having additional fields and imports.
Nvm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9f08c77

Added check on the first duplicate check.

Reverted to local variables since its not needed to allocate anymore.
-Direct initialization for struct instead to NULL
-Removed `intval` variable: copy value directly to `storage_id`
-Removed unnecessary message table comments
-Moved stst NULL check outside of if condition
- Check duplicate for non imported storage ID and overwrite when imported ID exist
- Move vector initialization on do_init_storage and transferred config reading after it
@vBrenth
Copy link

vBrenth commented Dec 20, 2024

I know its Holidays but please give us this, we've been waiting for years. (officially)
@MishimaHaruna


VECTOR_ENSURE(p->item, num_rows > MAX_STORAGE ? MAX_STORAGE : num_rows, 1);
if (SQL->NumRows(inter->sql_handle) > 0) {
VECTOR_ENSURE(p->item, MAX_STORAGE, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would be allocating more memory than needed if the storage is not full with MAX_STORAGE items. I think it would be better to keep the original logic of only allocating the needed space, never exceeding the MAX_STORAGE value.

Comment on lines -111 to -114
if (sd->storage.received == false) {
clif->message(sd->fd, msg_sd(sd, MSGTBL_STORAGE_NOT_LOADED)); // Storage has not been loaded yet.
return 1;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is removing the received check intended? from Haru message, he asked whether turning the message into assertion was intended (as an assertion doesn't inform the user why this happened).

But now, we would allow a not received storage to be "open".

src/map/unit.c Outdated

for (int i = 0; i < VECTOR_LENGTH(sd->storage.list); i ) { // Storages
VECTOR_CLEAR(VECTOR_INDEX(sd->storage.list, i).item);
VECTOR_INDEX(sd->storage.list, i).received = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(adding here since the line is gone from the final diff)
the vector still needs to be cleared up, because its internal data is dynamically allocated. you just don't have to set received to false, as this data will be cleared up at VECTOR_CLEAR(sd->storage.list);

ShowError("intif_parse_account_storage: Multiple calls from the inter-server received.\n");
return;
}

storage_count = (payload_size/sizeof(struct item));

VECTOR_ENSURE(sd->storage.item, storage_count, 1);
VECTOR_ENSURE(stor->item, storage_count, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory manager reported a leak from this, I didn't check what is causing it (not sure if related to the missing VECTOR_CLEAR in unit.c

0001 : storage.c line 298 size 352 address 0x0x55976f3717e4
0002 : intif.c line 363 size 440 address 0x0x55977473f1fc

VECTOR_PUSH(sd->storage.item, *item_data);
it = &VECTOR_LAST(sd->storage.item);
if (i == VECTOR_LENGTH(stor->item)) {
VECTOR_ENSURE(stor->item, 1, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory manager reported a leak from this, I didn't check what is causing it (not sure if related to the missing VECTOR_CLEAR in unit.c

0001 : storage.c line 298 size 352 address 0x0x55976f3717e4
0002 : intif.c line 363 size 440 address 0x0x55977473f1fc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants