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

[Portal 2 VScripts] VSquirrel Class Interactions Break Save/Load Functionality in Portal 2 #440

Open
IaVashik opened this issue Aug 21, 2024 · 3 comments

Comments

@IaVashik
Copy link

Description:

Unusual using classes in VSquirrel 2+ for Portal 2 modding can lead to critical save/load failures, effectively breaking the game. Several specific scenarios involving class interactions consistently trigger these issues.

Problem 1: Inheritance

Even simple inheritance can cause Portal 2 to crash on save/load.

Example:

class foo {
    function something() printl("test")
}

class bar extends foo {
    function doing() printl("bye bye my game :<")
}

While the inheritance mechanism itself works during runtime, attempting to load a saved game state containing these classes results in a crash.

Problem 2: Circular References Within Classes

Mutual references between class instances, even when using weakref, can still lead to crashes during save/load or cause the VSquirrel VM to break down. This is likely due to how references are handled during the serialization process, which fails to properly account for these circular dependencies.

Example:

class Node {
    nextNode = null
    prevNode = null
}

n1 <- Node()
n2 <- Node()

n1.nextNode = n2 // .weakref() does not help
n2.prevNode = n1 // .weakref() does not help

This results in errors like:

Failed to restore a Squirrel object of type <....>
Failed to restore a Squirrel object of type <....>

AN ERROR HAS OCCURED [null cannot be used as index]

CALLSTACK
*FUNCTION [VSquirrel_OnCreateScope()] unnamed line [166]

LOCALS
[result] NULL
[outer] NULL
[name] NULL
[this] NULL

image

Problem 3: Free Variables Within Class Methods

Using free variables within class methods in specific ways, particularly when they reference the class instance itself, can also lead to save/load errors.

Example:

class Foo {
    handler = null
    someInfo = null
    constructor(info) {
        this.someInfo = info
    }

    function RunHandler() return this.handler()
}

test <- Foo("secret information, lol")
test.handler = function() : (test) {
    // something logic
    printl("Aha! I know your info!!")
    printl(test.someInfo)
}

Final Notes and Workarounds:

I understand that classes in VScripts are not widely used in Portal 2 modding, and therefore, these issues might not be prioritized for fixing, which is completely reasonable. However, I'd like to offer some workarounds for those who do encounter these issues:

  1. Inheritance: Instead of using inheritance, consider using composition or replacing the class with a table and a clone method for creating copies.

  2. Mutual References: Use a table with delegation:

    ::qcam <- {}
    
    function qcam:new(owner) {
        local res = delegate qcam : {
            owner = owner,
            mode = null
        }
        res.mode = custommode(res)
        return res
    }
    
    class custommode {
        camRef = null
        constructor(cam) {
            this.camRef = cam
        }
    }
    
    z <- qcam.new("test")

    Or implement a global storage system, as in this example:

    cameras <- {}
    
    class qcam {
        mode = null
        owner = null
    
        constructor(owner) {
            this.owner = owner
            cameras[owner] <- this
            this.mode = custommode(this.owner) 
        }
    }
    
    class custommode {
        camOwner = null
        constructor(cam) {
            this.camOwner = cam 
        }
    }
    
    function GetCamera() {
        return cameras[this.camOwner]
    }
  3. Free Variables: Avoid using free variables in this particular way.

Radical Solution: Disable saving entirely with map_wants_save_disable 1, and you won’t have to deal with these issues! :D

@kisak-valve kisak-valve transferred this issue from ValveSoftware/Source-1-Games Aug 21, 2024
@IaVashik
Copy link
Author

I don't quite understand why this issue was moved to this repository, which is specifically related to the Linux native port, as I understand it. It seems that the Source-1-Games repository would be a more appropriate place for this problem, considering the nature of the issue.
Could you please clarify the reasoning behind this decision?

@kisak-valve
Copy link
Member

Hello @IaVashik, this issue tracker is more likely to be viewed by the Valve dev(s) that maintain Portal 2 than the Source-1-Games issue tracker.

@IaVashik
Copy link
Author

Hello @IaVashik, this issue tracker is more likely to be viewed by the Valve dev(s) that maintain Portal 2 than the Source-1-Games issue tracker.

This is a little confusing to me, due to the repository description, but I get it. Thanks for the quick response!

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

No branches or pull requests

2 participants