Author Topic: Multiplayer shifter bug  (Read 764 times)

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Multiplayer shifter bug
« Reply #15 on: April 13, 2011, 02:19:25 am »


               No need to apologize for the delay Gray, it's a videogame after all. Well it is your mod, so you do as you see fit. All I was saying is for people like me (non-scripters) it would be nice to have a working shifter fix on the vault, and if your file contains said fix, you would do me, and I am sure many others a favor by uploading it. In regards to you spell changes, it would just be a nice resource on the vault, you could post a disclaimer with it like: support (other than bug fixes) not included, mod at your own risk/ability, or something...
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Multiplayer shifter bug
« Reply #16 on: April 25, 2011, 01:18:47 am »


               

the.gray.fox wrote...

Hello.

Have a look at my Fox Spells package.
There is a script in it: fox_export_chars.
Its purpose is to export a player (or also all players).
If a player to export happens to be polymorphed, the script will ensure he retains all item properties.
The opening comment of the script explains its usage.

Hm. That script is practically stand-alone.
You may want to rip it and use it for your module -- no problem.
At best you have to delete a couple references to a constant I define elsewhere.
Nothing you can not handle on your own, I am sure.

-fox


I know your not big on providing advice for modifying your file, but I wonder if you or someone else could elaborate on this? I found the script and looked at it, but not sure which lines I should be deleting...
Thanks, Laz
               
               

               
            

Legacy_the.gray.fox

  • Full Member
  • ***
  • Posts: 214
  • Karma: +0/-0
Multiplayer shifter bug
« Reply #17 on: April 25, 2011, 08:27:12 pm »


               You are welcome.
Here is a standalone version.


// +----------------------+
// | FOX_EXPORT_CHARS.nss |
// +----------------------+
//
// ExportAllCharacters()
// ExportSingleCharacter()
//
// [fox - 25 Apr 2011 - standalone version]
// This script is the solution to the problem of polymorphed PCs losing their
// precious itemproperties after an Export of their Character.
//
// This script is designed to run via ExecuteScript().
// Make it run for a PC for an ExportSingleCharacter().
// Make it run for anything else for an ExportAllCharacters().



// +-----------+
// | CONSTANTS |
// +-----------+
// Name of a LocalObject we set on a polymorphed PC prior to export him. We use
// this to keep, briefly, a reference to all his equipment.
const string sFox_EXPORT_SLOTn = "FOX_EXP_00";



// +------------+
// | PROTOTYPES |
// +------------+
void fox_ExportAllCharacters     ();
void fox_ExportSingleCharacter   (object oPC);
void fox_ReapplyEnhancements     (object oPC);
void fox_RemoveAllItemProperties (object oItem);
void fox_CopyAllItemProperties   (object oDest, object oSource);



void main ()
{
    /////////////////////////////
    // Who are we running for?

    object oSelf = OBJECT_SELF;

    // Is this a PC?
    if (GetIsPC (oSelf))
    {
        // He is. Attempt to export him alone.
        fox_ExportSingleCharacter (oSelf);
    }
    else
    {
        // Not a PC. We attempt to export every PC.
        fox_ExportAllCharacters ();
    }
}



// -----------------------------------------------------------------------------
// Only a helper function to reduce the clutter.
// Cycles through all PCs and export them all.
// -----------------------------------------------------------------------------
void fox_ExportAllCharacters ()
{
    ////////////////////////////
    // Cycle through all PCs.

    object oPC = GetFirstPC ();
    while (GetIsObjectValid (oPC))
    {
        fox_ExportSingleCharacter (oPC);

        oPC = GetNextPC ();
    }
}



// -----------------------------------------------------------------------------
// Only a helper function to reduce the clutter.
// Export the given PC.
// -----------------------------------------------------------------------------
void fox_ExportSingleCharacter (object oPC)
{
    // Check if this PC is polymorphed.
    int bPoly = FALSE;
    effect eSeek = GetFirstEffect (oPC);
    while (GetIsEffectValid (eSeek))
    {
        if (GetEffectType (eSeek) == EFFECT_TYPE_POLYMORPH)
        {
            bPoly = TRUE;
            break;
        }

        eSeek = GetNextEffect (oPC);
    }


    ////////////////////////////////////////////////////////////////////////////
    // If the PC is polymorphed, we create a temporary copy of his current
    // equipment. We set a LocalObject on him for each item we create a copy of.
    ////////////////////////////////////////////////////////////////////////////

    if (bPoly)
    {
        // Sanity check. Is the PC in a valid Area?
        if (!GetIsObjectValid (GetArea (oPC)))
        {
            ////////////////////////////////////////////////////////////////////
            // There is a period of time, during Area Transitions, in which the
            // PC is -technically- outside of the Area he was last in, and not
            // yet in the Area he is transitioning to. The length of this window
            // depends on the complexity of the Areas involved in the process.
            // It is possible that a script executes when the PC is in such a
            // no-Area, and any code involving Areas or Locations shall go bug.
            ////////////////////////////////////////////////////////////////////

            // PC is in a no-Area. Quit.
            return;
        }

        // Get the current location of this PC.
        location lAt = GetLocation (oPC);

        // Scan all equipped items on this polymorphed PC.
        int i;
        for (i = 0; i < NUM_INVENTORY_SLOTS; ++i)
        {
            object oEquip = GetItemInSlot (i, oPC);
            if (GetIsObjectValid (oEquip))
            {
                //////////////////////////////////////////////////////
                // Create, on ground, a copy of this equipped item.
                // -------------------------------------------------------
                // NOTE : The copy will stay around for a very brief time.
                //        Nobody will notice it.
                // -------------------------------------------------------

                object oCopy = CopyObject (oEquip, lAt, OBJECT_INVALID, "");
                if (GetIsObjectValid (oCopy))
                {
                    // Set a reference on the PC to the copy we have made.
                    SetLocalObject (oPC, sFox_EXPORT_SLOTn + IntToString (i), oCopy);
                }
            }
        }
    }


    /////////////////////
    // Export this PC.

    ExportSingleCharacter (oPC);


    /////////////////////////////////////////////////////////////////////////
    // If the PC is polymorphed, we now reinstate what itemproperties he just
    // lost to the export.
    /////////////////////////////////////////////////////////////////////////

    if (bPoly)
    {
        DelayCommand (0.1f, fox_ReapplyEnhancements (oPC));
    }
}



// -----------------------------------------------------------------------------
// This function takes care to reapply all the enhancements a polymorphed PC had
// at the time of the export of his Character.
// We discovered that, after an export, all equipped items but the Skin/Hide are
// re-spawned anew on the polymorphed PC. Thus we have a set of itemproperties
// that is missing. And there is no way to unequip nor equip items on a PC while
// polymorphed.
// Our solution is to create temporary copies of all items equipped pre-export.
// Then, post-export, we clear the equipped items on the polymorphed PC of all
// their itemproperties. And immediately after we reinstate all itemproperties
// from the copies we made pre-export. This is the only approach that can react
// properly to new properties added to the equipped items after a polymorph.
//
// Our logic is flawless :-)
// -----------------------------------------------------------------------------
void fox_ReapplyEnhancements (object oPC)
{
    // Scan all equipped items on this polymorphed PC.
    int i;
    for (i = 0; i < NUM_INVENTORY_SLOTS; ++i)
    {
        object oEquip = GetItemInSlot (i, oPC);
        if (GetIsObjectValid (oEquip))
        {
            string sKey = sFox_EXPORT_SLOTn + IntToString (i);

            // Get a reference to the temporary copy we made of this item.
            object oCopy = GetLocalObject (oPC, sKey);

            if (GetIsObjectValid (oCopy))
            {
                // Delete the reference (we no longer need it).
                DeleteLocalObject (oPC, sKey);

                // Remove all current itemproperties from the equipped item.
                fox_RemoveAllItemProperties (oEquip);

                // Copy all itemproperties from the temporary copy.
                // (the copy is destroyed within the function)
                DelayCommand (0.0f, fox_CopyAllItemProperties (oEquip, oCopy));
            }
        }
    }
}



// -----------------------------------------------------------------------------
// Only a helper function to reduce the clutter.
// Removes ALL itemproperties from the given item.
// -----------------------------------------------------------------------------
void fox_RemoveAllItemProperties (object oItem)
{
    itemproperty ipSeek = GetFirstItemProperty (oItem);
    while (GetIsItemPropertyValid (ipSeek))
    {
        RemoveItemProperty (oItem, ipSeek);

        ipSeek = GetNextItemProperty (oItem);
    }
}



// -----------------------------------------------------------------------------
// Only a helper function to reduce the clutter.
// Copy ALL itemproperties from the Source item to the Destination item.
// -----------------------------------------------------------------------------
void fox_CopyAllItemProperties (object oDest, object oSource)
{
    itemproperty ipSeek = GetFirstItemProperty (oSource);
    while (GetIsItemPropertyValid (ipSeek))
    {
        AddItemProperty (DURATION_TYPE_PERMANENT, ipSeek, oDest, 0.0f);

        ipSeek = GetNextItemProperty (oSource);
    }

    // Destroy the Source item.
    // (that is, the temporary copy item we made)
    DestroyObject (oSource, 0.0f);
}


-fox
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Multiplayer shifter bug
« Reply #18 on: April 25, 2011, 11:29:59 pm »


               That's fantastic Grey Fox, thank you so much! So this should work on it's own without any further editing?
               
               

               


                     Modifié par Lazarus Magni, 25 avril 2011 - 10:30 .
                     
                  


            

Legacy_the.gray.fox

  • Full Member
  • ***
  • Posts: 214
  • Karma: +0/-0
Multiplayer shifter bug
« Reply #19 on: April 26, 2011, 01:17:12 pm »


               

Lazarus Magni wrote...

That's fantastic Grey Fox, thank you so much! So this should work on it's own without any further editing?


Yes. It is a self-contained standalone script. Ready as-is.
To be run through ExecuteScript().
The Object you run it for dictates the work mode (ExportSingleCharacter() vs. ExportAllCharacters() ).
Run it for a Player to export that very Player alone.
Run it for any object other than a Player (example: the Module or a sword) to export all Players.

NOTE : This script is not to be used in conjunction with Fox Spells. First: it would not compile. Second: Fox Spells uses its own original and equivalent version of this one. So... keep the two things separate.

-fox



[edit]
Hm. By the way...

18 days ago ShaDoOoW wrote...

[...] The manual saving via Export Character button should be avoided, [...] because it allows exploits [...]


The exploit he refers to is the instant refill of HP and THP in case the Player polymorphed to a creature who received Temporary Hit Points. Most polymorph shapes do this.

Said exploit is easily defeated. Zero away the THP bonus defined in polymorph.2da.
Then have your polymorph script take care to apply said THP bonus using EffectTemporaryHitpoints().
Doing so the export process shall not refill HP nor THP -- so defeating any malicious use of manual exports.

There would be more to tell about polymorphs, but I would go off topic.
If you want to learn all details, have a look at my polymorph system within Fox Spells.

-fox
               
               

               


                     Modifié par the.gray.fox, 26 avril 2011 - 01:52 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Multiplayer shifter bug
« Reply #20 on: April 26, 2011, 08:19:09 pm »


               Hmm, thanks again for the reply Grey Fox. Problem is that the server autosaves every 5 min or so, and that's when the bug happens. Will that script fire automatically on it's own when this occurs?
               
               

               
            

Legacy_Terrorble

  • Sr. Member
  • ****
  • Posts: 370
  • Karma: +0/-0
Multiplayer shifter bug
« Reply #21 on: April 27, 2011, 03:19:03 am »


               The auto-save feature for your server *likely* fires from your module's OnHeartbeat script. (Look at the events tab under module properties) If you look in that script, there's a good chance you'll find where it is exporting the characters every 5min. Comment out that line and add one like this in its place: ExecuteScript("fox_export_chars", GetModule());
*This assumes the file name for fox's function is fox_export_chars

I think that would cover it.

btw Fox, thanks for this, I'll be working this into the server I play since we suffer from a similar issue.
               
               

               


                     Modifié par Terrorble, 27 avril 2011 - 02:20 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Multiplayer shifter bug
« Reply #22 on: April 27, 2011, 07:54:33 pm »


               Thank you for the advice Terrorble. Guile also gave me the link to his shifter system that has a similar script in it as well (I think.)
http://nwvault.ign.c...=198735&id=3773
That is what we used to fix this most recently I believe. I have forwarded this info to the server host, and hopefully he will try one or both of these solutions out soon.
Thanks for all the help everyone.
Laz