WurstModders / WurstMod

Deli mod for H3VR to load custom scenes into the game!
MIT License
24 stars 2 forks source link

Recent discoveries w/ modding #17

Closed nrgill28 closed 4 years ago

nrgill28 commented 4 years ago

So just a couple days ago in the Discord server, multiple users discovered that by using a tool called uTinyRipper on the game's files we can extract a stubbed version of the game's assemblies for use in the editor.
It was used to create custom guns, although I explored it's possible uses for mapping as well and here's what I've learned:

The good

The bad

The ugly

Conclusion

So these discoveries are really useful. From custom guns to custom maps to custom... anything. For a WurstMod 2.0 preview I think it would be good to explore using these new discoveries to allow for more direct creation of custom content, though I am a little worried about having that initial process of extracting the games files that would make getting started more difficult.

Nolenz commented 4 years ago

Good research, uTinyRipper was actually the tool I used initially to do all the initial TNH reversing. I agree with questioning the ethics of distributing a stubbed full assembly, I don't think that's the path we should take.

Proxying VS Stubbing

You're right about the asset hashing stuff, I didn't have quite the full understanding when the current proxying implementation came about. In theory, we can use the exact same namespace and classname so long as we don't want to change the interface at all. However, I value being able to change way fields are organized because it made many of the TNH objects much easier to work with (Supply Point, Hold Point.)

Having the capability to resolve something at runtime is also useful or even required at times to setup certain fields that otherwise would not exist just loading stubs (Barrier data, additional behaviour for Targets.) You can't do that with a stub, and if you implement that you've practically made your stub into a proxy anyway.

Overall, I think the proxying implementation has enough benefits that we can't really fully replace it at this point. Of course, being able to just make a FistVR::Whatever class and have it automatically load is great, unless you want to do anything to it. Stubbing could still have a role somewhere, though.

The Role of Stubbing

I do understand the desire to make it easier to use any class in the game without having to go through the effort of stubbing out a class yourself. Though one could argue that doing the digging to realize you even want to use a specific class puts you about 95% of the way to having the stub... Other than the weird cases where you might need multiple nested stubs I guess. Eh.

Either way, the logic of generating stubs doesn't seem super complex, I get the feeling it could be done on the fly with an editor script and maybe Mono.Cecil. Have it just plonk a generated stub class into the scripts folder based on classes you choose. Yay code generation. Might be worth looking into, but it's probably going to be a decent bit of work so I'm not sure if or when I'll get around to it.

Anvil

It would be fantastic to be able to pull Anvil object IDs from within Unity as well, but that sounds a bit harder. I need to sit down and play with Anvil for a while...

nrgill28 commented 4 years ago

There are a couple more downsides I've discovered since creating this issue;
The first being as you mentioned the loss of flexibility to simplify some of the components, and yeah I agree having that flexibility is much more useful.
The other being that if you fully extract the game with uTinyRipper and import both the scripts and the scriptable objects, map exports take much, much longer. Going from a couple seconds to close to a minute. Having just the scripts isn't that bad, though.

Honestly, after some more poking around, I think the most useful thing that comes from this is if we import just the scripts we have the option of using them raw in the editor (For things like interactable objects, FVRObject definitions and other stuff that we don't really need to proxy), but also so that we can have fields and methods in our code that make use of the game's types without needing an empty proxy.

For example, a while back I changed the return type of a method to object and cast it back at runtime because otherwise Unity would throw an error since it didn't have access to the original type's definition, which is the type of jank we can avoid by just having the stub files exist in the Unity project.