general questions - help for fixing a bug that's been there for ages in my mod!

Started by ninekorn, April 11, 2022, 12:07:47 PM

ninekorn

Hi,

I think ai_enabled answered my question somehow on this post https://forums.atomictorch.com/index.php?topic=989.msg6198#msg6198 but i don't remember even seeing the post where he says:

QuoteAnother problem with global variables - we cannot serialize them easily and write into the savegame. So even if we had global variables (shared across all the scripts), it will be very easy to write bad code (which will prevent the game from properly saving the game state). So, we have storage scripting API instead. It's also very limited, but for the most cases, it was enough to get the things done.

So, every global variables that i am creating in my scripts, cannot be serialized and saved during a savegame if i understand correctly? do i need to empty the global variables before a savegame happens, or should i just from now on use the storage API instead for storing the global variables that i need? There is a lot of global variables in the AI scripts i developed in the libs section of my mod and i am currently trying to fix my galaxy market mod, and after that i am jumping on my AI scripts logic. I am not familiar with serialization of code and will go read a bit on that soon.

Thank you for your time answering,
9

Edit: It is not just my galaxy market the issue, it might not even be. I've set my globals variables to be inside of functions instead, so they are local variables for arrays, and the rest is using storage.SetGlobal... Thank you for understanding my frustration here.



I am using storage.SetGlobal for all of my variables that i need to access from other scripts or npcs. Should i use storage.Set instead? Is there a limit to the number of variables that i can storage.SetGlobal to in Void Expanse? It is easy to debug which script or variable is causing issues when you have the source code. When you don't it's a needle in a haystack with that kind of error that doesn't point to anything precise on where to look for the issue.

For instance, i use 4 scripts for the salvaging device. 1 script for the device, 1 script for storing the salvageable items in a global variable, 1 script for checking the player inventory, 1 script for activating the device with a library on specified coordinates.



using(npc);
using(console);
using(timer);

var SC_Salvage_Object_Storage =
{
    AddSpaceObjectToStorage: function (system_id, SpaceObjectID, randomYieldToStartOff)
    {
        if (storage.IsSetGlobal("systemid_" + system_id + "_salvage"))
        {
            var toReceiveData = storage.GetGlobal("systemid_" + system_id + "_salvage");
            var objectdata = { sys_id: system_id, id: SpaceObjectID, yield: randomYieldToStartOff, GameTime: timer.GetGameTime() };
            toReceiveData.push(objectdata);

            storage.SetGlobal("systemid_" + system_id + "_salvage", toReceiveData);
            /*var someTest;
            var toReceiveData = storage.GetGlobal("drone_mining_added_" + chosenPosition);

            var droneData = { id: droneid, index: droneIndex };
            toReceiveData[droneIndex] = droneData;
            storage.SetGlobal("drone_mining_added_" + chosenPosition, toReceiveData);*/
        }
        else
        {
            var toSendData = [];
            var objectdata = { sys_id: system_id, id: SpaceObjectID, yield: randomYieldToStartOff, GameTime: timer.GetGameTime()};
            toSendData.push(objectdata);
            storage.SetGlobal("systemid_" + system_id + "_salvage", toSendData);
        }
    },
    GetSpaceObjectStorageLength: function (system_id)
    {
        if (storage.IsSetGlobal("systemid_" + system_id + "_salvage"))
        {
            var toReceiveData = storage.GetGlobal("systemid_" + system_id + "_salvage");
            return toReceiveData.length;
        }
        else
        {
            return 0;
        }
    },


    RemoveFromYield: function (system_id, SpaceObjectID, currentYieldMinus)
    {
        if (storage.IsSetGlobal("systemid_" + system_id + "_salvage"))
        {
            var toReceiveData = storage.GetGlobal("systemid_" + system_id + "_salvage");

            for (var s = 0; s < toReceiveData.length;s++)
            {
                if (toReceiveData[s].id == SpaceObjectID)
                {
                    toReceiveData[s].yield = toReceiveData[s].yield - currentYieldMinus;
                    break;
                }
            }

            storage.SetGlobal("systemid_" + system_id + "_salvage", toReceiveData);
        }
        else
        {
            console.PrintError("the space object doesn't exist in the global array and this message is never supposed to print even with a console debug_reinit. If it prints, tell me. 0");
        }
    },

    SetDepleted: function (system_id, SpaceObjectID)
    {
        if (storage.IsSetGlobal("systemid_" + system_id + "_salvage"))
        {
            var toReceiveData = storage.GetGlobal("systemid_" + system_id + "_salvage");
            var s = 0
            for (s = 0; s < toReceiveData.length; s++)
            {
                if (toReceiveData[s].id == SpaceObjectID)
                {
                    toReceiveData[s] = null;
                    break;
                }
            }

            toReceiveData.splice(s, 1);

            storage.SetGlobal("systemid_" + system_id + "_salvage", toReceiveData);
        }
        else
        {
            console.PrintError("the space object doesn't exist in the global array and this message is never supposed to print even with a console debug_reinit. If it prints, tell me. 1");
        }
    },


    GetSpaceObjectYield: function (system_id, SpaceObjectID)
    {
        if (storage.IsSetGlobal("systemid_" + system_id + "_salvage"))
        {
            var toReceiveData = storage.GetGlobal("systemid_" + system_id + "_salvage");

            for (var s = 0; s < toReceiveData.length; s++)
            {
                if (toReceiveData[s].id == SpaceObjectID)
                {
                    return toReceiveData[s].yield;
                }
            }
        }
        else
        {
            console.PrintError("the space object doesn't exist in the global array and this message is never supposed to print even with a console debug_reinit. If it prints, tell me. 2");
        }
    },
};



using(npc);
using(console);
using(timer);

var counterFrame = 0;
var counterDevice = 0;

var SC_Salvage_Object_Timer =
{
    ClearCurrentDevice: function (sys_id, device_id, ship_id, slot_id) //IsWorking
    {
        game.IsShipPlayerControlled(ship_id);

        var playerName = game.GetShipOwner(ship_id);

        if (storage.IsSetGlobal("GlobalIndex_Player_" + playerName))
        {
            var someGlobalIndex = storage.GetGlobal("GlobalIndex_Player_" + playerName);


            if (!storage.IsSetGlobal("systemid_" + sys_id + "_ship_" + ship_id + "_salvage_device_" + device_id))
            {
                storage.SetGlobal("systemid_" + sys_id + "_ship_" + ship_id + "_salvage_device_" + device_id, { swtch: 1, ship_id: ship_id, device_id: device_id, slot_id: slot_id, timer_id: null, reset: 1 });

            }
            else
            {
                var globalSalvageStorage = storage.GetGlobal("systemid_" + sys_id + "_ship_" + ship_id + "_salvage_device_" + device_id);

                if (globalSalvageStorage != null) {

                    if (globalSalvageStorage.timer_id != null)
                    {
                        //timer.AddOrUpdate("CustomOnFrame", null);
                        //timer.AddOrUpdate(0.25, "CustomOnFrame", null, 1); //

                        game.ShipStopSound(ship_id, "mining_process_" + slot_id);
                        visual.DeviceDeactivateEffect(ship_id, device_id, "mining_visual_effect");

                        timer.ClearTimer(globalSalvageStorage.timer_id);

                        var data = { swtch: 1, ship_id: ship_id, device_id: device_id, slot_id: slot_id, timer_id: null, reset: 0 };
                        storage.SetGlobal("systemid_" + sys_id + "_ship_" + ship_id + "_salvage_device_" + device_id, data);


                        //console.PrintError("cleared device timer: " + globalSalvageStorage.timer_id);
                        return 1;
                    }
                    else
                    {
                        //console.PrintError("null timer0");
                        return 0;
                    }
                }
                else
                {
                    //console.PrintError("null globalSalvageStorage");
                    return 0;
                }

            }
        }
    },

    SetDevice: function (sys_id, device_id, ship_id, timer_id) //IsWorking
    {
        game.IsShipPlayerControlled(ship_id);
        var playerName = game.GetShipOwner(ship_id);

        if (storage.IsSetGlobal("GlobalIndex_Player_" + playerName))
        {
            var someGlobalIndex = storage.GetGlobal("GlobalIndex_Player_" + playerName);

        }
    },

    AddDeviceID: function (sys_id, device_id, slot_id, ship_id, timer_id)
    {
        game.IsShipPlayerControlled(ship_id);

        var playerName = game.GetShipOwner(ship_id);

        if (storage.IsSetGlobal("GlobalIndex_Player_" + playerName))
        {
            var someGlobalIndex = storage.GetGlobal("GlobalIndex_Player_" + playerName);

            //storage.GetGlobal("systemid_" + sys_id + "_ship_" + ship_id + "_salvage_device_" + device_id); //, { swtch: 1, ship_id: ship_id, device_id: device_id, slot_id: slot_id, timer_id: timer_id}

            var globalSalvageStorage = storage.GetGlobal("systemid_" + sys_id + "_ship_" + ship_id + "_salvage_device_" + device_id);

            if (globalSalvageStorage != null) {

                if (globalSalvageStorage.timer_id != null)
                {
                    timer.ClearTimer(globalSalvageStorage.timer_id);
                    //console.PrintError("cleared device timer: " + globalSalvageStorage.timer_id);
                }
                else {
                    //console.PrintError("null timer1");
                }
            }
            else {
                //console.PrintError("null globalSalvageStorage");
            }

            var data = { swtch: 1, ship_id: ship_id, device_id: device_id, slot_id: slot_id, timer_id: timer_id, reset: 0 };

            storage.SetGlobal("systemid_" + sys_id + "_ship_" + ship_id + "_salvage_device_" + device_id, data );
        }

        var deviceArray = [];


        if (deviceArray == null)
        {
            deviceArray = [];
        }
        var objectData = { sys_id: sys_id, device_id: device_id, ship_id: ship_id };
        deviceArray.push(objectData);

        var arrayData = { index: deviceArray.length - 1, length: deviceArray.length };
        return arrayData;
    },

    AddCounterFrame: function ()
    {
        counterFrame++;
        return counterFrame;
    },

    GetCounterFrame: function () {
        return counterFrame;
    },

    ResetCounterFrame: function ()
    {
        counterFrame = 0;
        return counterFrame;
    },

    AddCounterDevice: function () {
         counterDevice++;
         return counterDevice;
    },

    GetCounterDevice: function () {
        return counterDevice;
    },

    ResetCounterDevice: function () {
        counterDevice = 0;
        return counterDevice;
    }
};





ninekorn

I might be onto something here. I noticed that the original core.cpk devices JS scripts don't have for any of them a single reference to include another lib. I noticed also that the ai JS scripts only include the NpcLib.js script from the libraries. And from the NpcLib.js, there aren't any includes. That might be where i have been going wrong where in my device script i am using include on 4 different libraries.

include(SC_Utilities.js);
include(SC_Salvage_Object_Storage.js);
include(SC_Salvage_Object_Timer.js);
include(SC_Salvaging_Utilities.js);

but none of those libraries have inner includes statements so i always thought that a "single layer of depth" to the include statement wouldn't cause that much issues.  About 30++ minutes and the multiplayer server running and no crash today and i did use the salvaging device a bit... I will test in singleplayer again but most importantly, i will probably remove those libraries and include the utility functions inside of the device script instead to remove that depth of included libraries. I will repost here once i have results.

Edit: meh, the second save on a singleplayer game and the serialization error happened. I did salvage a couple of times... where is the issue?

Edit: i thought maybe it was my cargo check function that really was to try and bypass using GetFinalCache or GetCurrentValue functions. Earlier i was checking the cargo by adding items inside of it and removing it. I thought maybe the sheer amount of items i was trying to add might have been the issue. My old function was:


function AIIsPlayerCargoFull(playerID)
{
    for (var i = 0; i < 1; i++) {
        var totalSizeOfPlayerStorage = 0;
        var initialQuantityOfItemsInPlayerStorage = 0;
        var emptySpaceToRemovePlayer = 0;

        var PlayerContainerID = items.GetGameObjectContainerId(playerID);
        var itemsInCargoOfPlayer = items.GetItemsAndCargo(PlayerContainerID);
        if (itemsInCargoOfPlayer != null) {
            if (itemsInCargoOfPlayer.length > 0) {
                if (itemsInCargoOfPlayer[0] != null) {
                    for (var i = 0; i < itemsInCargoOfPlayer.length; i++) {
                        initialQuantityOfItemsInPlayerStorage += itemsInCargoOfPlayer[i].quantity;
                    }
                }
                else {
                    initialQuantityOfItemsInPlayerStorage = 0;
                }
            }
            else {
                initialQuantityOfItemsInPlayerStorage = 0;
            }
        }
        else {
            initialQuantityOfItemsInPlayerStorage = 0;
        }


        items.AddItem(PlayerContainerID, "goods_emptyspace", 100000);
        var itemsInCargoOfPlayerAfterAddingEmptySpace = items.GetItemsAndCargo(PlayerContainerID);

        if (itemsInCargoOfPlayerAfterAddingEmptySpace != null) {
            if (itemsInCargoOfPlayerAfterAddingEmptySpace.length > 0) {
                if (itemsInCargoOfPlayerAfterAddingEmptySpace[0] != null) {
                    for (var i = 0; i < itemsInCargoOfPlayerAfterAddingEmptySpace.length; i++) {
                        totalSizeOfPlayerStorage += itemsInCargoOfPlayerAfterAddingEmptySpace[i].quantity;
                    }
                }
                else {
                    totalSizeOfPlayerStorage = 0;
                }
            }
            else {
                totalSizeOfPlayerStorage = 0;
            }
        }
        else {
            totalSizeOfPlayerStorage = 0;
        }


        var emptySpaceToRemovePlayer = totalSizeOfPlayerStorage - initialQuantityOfItemsInPlayerStorage;
        items.RemoveCargo(PlayerContainerID, "goods_emptyspace", emptySpaceToRemovePlayer);

        if (emptySpaceToRemovePlayer > 1) {
            var someData = { swtc: 0, space: emptySpaceToRemovePlayer };
            return someData;
        }
        else {
            var someData = { swtc: 1, space: emptySpaceToRemovePlayer };
            return someData;
        }
    }
}


my new function is:



function AIIsPlayerCargoFull(playerID)
{
    var value = ship.GetTotalCargoAmount(playerID); 
    var somefinalcval = ship.GetFinalCacheValue(playerID, "cargo_capacity");

    var emptyspace = somefinalcval - value;
    if (value < somefinalcval)
    {
        var someData = { swtc: 0, space: emptyspace };
        return someData;
    }
    else
    {
        var someData = { swtc: 1, space: emptyspace };
        return someData;

    }
}


But this change didn't stop the error from happening. Then i noticed this at the top of a device script:

Quote
/*
Script can contain following functions:
OnUpdateCache - called when device is equipped or initialized, or some values are changed
OnStart - called when device is activated (for all)
OnFrame - called every frame (only for "per frame" mode)
OnFinished - called when device effect should be applied (only for "per frame" and "on complete")
*/

I am creating my own functions inside of a device script. Custom functions to accomodate the logic for a salvaging device that i developed. Could it be that the devices scripts don't allow any other types of functions that those mentioned above?

ninekorn

I thought it was all of my obj files that were causing issues. As for as far as i remember, i had been exporting from blender and deleting the .mtl file forever. Which in turn was causing issues in Void Expanse as the material file (.mtl) wasn't found for all of my objs. I found that out by testing an opengl c# tutorial obj file loader that wouldn't load the file when the .mtl file was deleted. Void expanse still loads the file but a debug error shows only in the keyboard key ~ console debugger within the game itself and not on the console. I corrected that for the destroyed ship parts re-exporting everything but removing the material file from the setting options. The same bug still happens in singleplayer and multiplayer. I have a couple of things left to test. I am wondering if maybe, it could be the fact that i was using an empty object as a weapon for NPCs that are stationed static in-base, in order to not spawn them a ship when they remain in base. So i added a tiny face for my 'invisible weapons' so that it is barely visible, and i have yet to also do the same thing for the "no ship" inbase NPC characters. Maybe an empty obj file from blender exported inside of Void Expanse is causing the issue but in this case, there are no errors in the game keyboard key ~ console and neither in the server console. Except for that, i have no clue what else could be causing the issue.

I have removed the galaxy market and drones and interior stations from my mod to test it as an almost blank mod but the issue persists when only using the salvaging mod. So i have put the logs of singleplayer and multiplayer and the mod i was using here. Note that the bug starts after salvaging destroyed ship parts, going in a station after or before the savegame happens, then undocking saves the game automatically and the bug happens in singleplayer. In multiplayer, i used the console save option multiple times as per the log and everytime the serialization bug happened but in multiplayer it doesn't crash the server. In singleplayer it crashes the server. That serialization error makes it impossible to save the game even if it doesn't crash the server in multiplayer. The bug happens in the first system. Not sure if the other systems also create the bug.

https://drive.google.com/file/d/1Gife7v5alAeKyesJcDRY9zi5sjOwL_jz/view?usp=sharing,
https://drive.google.com/file/d/1inacD1WRWmBDdGRgog_tiSghwth3mtes/view?usp=sharing,
https://drive.google.com/file/d/1k1fWQl_cChvGJfVwXnvdowfp-1ZK7iAr/view?usp=sharing

there is also one other thing. For as far as i remember i have been using PNG instead of JPG and i know JPG is less heavy in harddrive usage but the PNG file is different than the JPG file. Could it be the PNG files the issue? There is nothing debugging in the consoles though for any errors relating to the extension of those images. Void Expanse loads both PNGs and JPGs but could the PNGs be causing a serialization issue? Also i was wondering, if my mod isn't released on the Steam Workshop, would it be causing that security transparency issue?

I barely read on this, but reading on it, i've found that this error can be avoided in C# when using a header [assembly:AllowPartiallyTrustedCallers] . But i can't use that in javascript EcmaScript5. So if i would release my mod from the Steam Workshop, would my files/scripts be added that header automatically from Steam and redistributed with somehow security transparency embedded somewhere that doesn't crash my program?

https://stackoverflow.com/questions/12092435/system-methodaccessexception-attempt-by-security-transparent-method-to-access-s
https://stackoverflow.com/questions/20252500/attempt-by-security-transparent-method-to-access-security-critical-method-failed
https://docs.microsoft.com/en-us/dotnet/api/system.security.securitytransparentattribute?view=net-6.0
https://docs.microsoft.com/en-us/dotnet/api/system.security.allowpartiallytrustedcallersattribute?view=net-6.0

Thank you for the help,
nine