#Interface Serialization

1 messages · Page 1 of 1 (latest)

crude jolt
#

Is it possible to serialize an interface? My situation doesn't really warrant me making an abstract class and using inheritance.

urban viper
#

not with unity's serialization, no. some custom stuff does though, ive heard odin inspector supports serializing interfaces i think?

crude jolt
#

is there some sort of workaround?

#

something that achieves the same thing I'm trying to do

urban viper
#

well.. an abstract class?

#

i don't know what you're trying to do

#

i'm not psychic

crude jolt
#

okay that's on me

#

well, I'm trying to make a script that basically enables a selected visual object

#

so when the player looks at something that has the interface IInteractable, that object will light up

#

now, I have 2 objects in my game, an item spawner and a table to put an item on

#

I want to be able to do the same visual selection logic on the table as I do on the spawner

#

I'm hesitating to use inheritance in this case because the two objects do wildy different things

urban viper
#

do you need to serialize that at all?

crude jolt
#

well, yes. I need to reference the actual IInteractable to check if that is the instance I'm pointing to

urban viper
#

reference ≠ serialize

#

if (for example) you do a raycast and just do a GetComponent<IInteractable>, you can reference the interface just fine. no serialization in that operation

crude jolt
#

my system works like this:
player raycasts onto object
object returns script
if the script has the interface, it gets stored in a variable
player sends an event, carrying the interface
visual script checks that and checks if that instance is the same instance it's on

#

I need to expose it in the editor though for the last step

urban viper
#

sends an event for what, to where?

crude jolt
#

from the player, it sends to the visual script

#

since I'm trying to separate visual scripts

urban viper
#

what is this visual script exactly

crude jolt
#
using UnityEngine;

public class SelectedVisual : MonoBehaviour {

    [SerializeField] private GameObject[] selectedGameObjectVisualsArray;
    [SerializeReference] private IInteractable interactable;
    private void Start() {
        Player.Instance.OnInteractableChanged += Player_OnInteractableChanged;
    }

    private void Player_OnInteractableChanged(object sender, Player.OnInteractableChangedEventArgs e) {
        if(e.interactable == this.interactable) {
            Show();

        }
        else {
            Hide();
        }
    }

    private void Show() {
        foreach (GameObject go in selectedGameObjectVisualsArray) {
            go.SetActive(true);
        }
    }

    private void Hide() {
        foreach (GameObject go in selectedGameObjectVisualsArray) {
            go.SetActive(false);
        }
    }
}
urban viper
#

and what's this for exactly...?

#

couldn't you just have this be handled by the interactable

#

just call a method on the interactable

crude jolt
#

well, the interactable is doing something else, for example this one:

#
using UnityEngine;
using System;

[Serializable]
public class BeerKeg : MonoBehaviour, IInteractable {

    [SerializeField] private GameObject beerCupObject;

    private void Start() {
    }

    public void Interact() {

        if (!Player.Instance.HasBeerCup()) {
            BeerCup beerCup = GameObject.Instantiate(beerCupObject).GetComponent<BeerCup>();
            beerCup.SetBeerCupParent(Player.Instance);
        }
    }
}
#

I'm trying to keep the logic there and then the visual stuff in another script

#

and trying to minimize duplicated code

urban viper
#

the visuals you're referring to are like, highlights, right?

crude jolt
#

yes

urban viper
#

if there's a 1:1 correspondance between Interactables and their visual highlights, why not just have the highlights also be handled by the interactable

#

not necessarily the component directly, but at least on the same gameobject

crude jolt
#

so how would I do a check though

urban viper
#

you wouldn't need to

#

you can just grab the interactablehighlight and trigger it

tropic socket
crude jolt
tropic socket
#

Problem with third party serialization is being paranoid your serialization doesnt implode on the off chance

crude jolt
urban viper
# urban viper you can just grab the interactablehighlight and trigger it

eg

selectedInteractable = null

update:
  hit = raycast()
  if hit and hit.trygetcomponent(interactible):
    if selectedInteractible != interactible:
      interactible.Show()
      selectedInteractible.Hide()
      selectedInteractible = interactible   
  else:
    if selectedInteractible != null:
      selectedInteractible.Hide();
    selectedInteractible = null
```in those Show/Hide steps, you could retrieve the highlights there, you could have some way to get the highlights via the interactible itself, you could have IInteractible be an abstract class, etc
crude jolt
#

oh? I don't need to check if it's the instance it's on?

urban viper
#

not if you don't go through a detached system, no

#

if you keep the highlights with the interactible itself, then you know you're getting the right instance

crude jolt
#
 if(e.interactable == this.interactable) {
     Show();

 }
 else {
     Hide();
 }

cuz this check is to validate if it's talking about itself or it's talking about another instance of that

urban viper
#

and you're broadcasting the event to every highlight? that's where the "detached system" aspect comes in

#

instead of having every highlight worry about every interactible, design around the 1:1 relation

crude jolt
#

alright so instead of having everything separate, I should make it so that it's connected?

#

but that would need me to make a visual script for every interactable

#

right

urban viper
#

i mean, if you want each one to have its own highlight, yeah?

#

isn't that the same as what you had before

#

you could have interactibles not have highlights too (even in the case of inheritance, you could just have the visuals be an empty array)

crude jolt
#

well, I only made one visual script that I can attach to every interactible

#

is inheritance really the only option here? If I want to continue the design I'm doing, that is

urban viper
#

you don't need separate scripts

urban viper
#

composition is always an option

crude jolt
#

ooh okay I haven't heard of that actually, do you have any resources I can read on that topic?

urban viper
#

in unity composition is basically just components on the same gameobject that rely/interact with each other

crude jolt
#

I seeee

#

I usually go with the separated systems approach though, it's a lot less messy

#

when can you say it's better to use composition?

urban viper
#

when the 2 things should be coupled together in a way, like here

crude jolt
#

alright I'll definitely look into this

#

thank you so much

tropic socket
#

yeah composition sounds like an idea

#

instead of an interface just make it a component

crude jolt
#

what's the difference though

tropic socket
#

components are classes ;p

crude jolt
#

but aren't abstracts classes too

urban viper
#

components are concrete classes

tropic socket
#

yeah but abstract classes still fall into the pitfalls of OOP

urban viper
#

(though, that wasn't my suggestion)

crude jolt
urban viper
#

concrete = non-abstract

crude jolt
#

instead of two classes like a keg and a table

#

it'll be under one component

urban viper
#

i don't follow the analogy

crude jolt
#

oh I mean those are the two objects that are interactable

#

so instead of interactable A and interactable B in can be just interactable

urban viper
#

oh, no, definitely not

#

each interactible would still be its own thing

crude jolt
#

so how are components and abstracts different (besides components being concrete)

urban viper
#

that's the difference

#

unity can use concrete classes as components

crude jolt
#

oh hold on so meaning

urban viper
#

i mean.. i don't actually know if unity can't use abstract classes. i don't think so. i should test that.

crude jolt
#

I can extend the interactable component?

urban viper
#

ok i feel like there's some confusion here

tropic socket
urban viper
#

my suggestions were one of the following:

  • interactible interface, interactible highlight component, some concrete interactible implements interface, composition
  • interactible abstract class that includes highlights, some concrete interactible extends abstract class, inheritance
crude jolt
#

right so interactable itself will be something I can attach to an object..?

urban viper
crude jolt
#

oh wait so the interface would still exist?

#

if we're using the composition architecture

urban viper
#

i mean, you could change that part to an abstract class too, if you want

tropic socket
#
public class Enemy: Monobehavior
{
  [SerializeField] private Interactable interactable;
}

public abstract class Interactable: Monobehavior
{
  public abstract void Interact();
}```
#

something like that. You don't actually need to include it in the enemy script and can always just do a component search on the game object

urban viper
#

i'm just clarifying what my original suggestions were

#

ah yeah composition inside the component is also an option

tropic socket
#

I hardly use interfaces anymore with monos

crude jolt
#

I'm confused

#

why would I declare an abstract within the script

#

shouldn't it be separate?

urban viper
tropic socket
#

well, 2 + each unique derived interactable class

crude jolt
#

alright I'm starting to understand

#

though, I'll look into it more

#

thanks so much guys

tropic socket
#

then there's the SO idea where if you can somehow make code reusable, a single SO class could work

#

but if you need unique logic which requires hardcoding then making a class per interactable is fine

crude jolt
#

I thought SOs were just data containers though

tropic socket
#

SOs are very customizable and you can use them as blueprints

urban viper
prisma saddle
tropic socket
#

Yeah, but even then that's annoying to work with

prisma saddle
#

How so?

#

I use serializereference extensively with abstract classes, haven't used with interfaces though, but shouldn't be too different

tropic socket
#

It's just more boilerplate which unity should have already provided for us

crude jolt
prisma saddle
#

What part doesn't work? Serialization or showing it in the inspector with a package?

crude jolt
#

It's just showing the name of the field

#

but I can't drag anyting in

prisma saddle
#

So did you add any 3rd party code that would show it?

crude jolt
#

pure vanila

prisma saddle
#

Unity doesn't have native support for showing [SerializeReference] stuff in the inspector

crude jolt
#

so pure the only thing I have is cinemachine

prisma saddle
#

Hence the mentioned package(s)

crude jolt
#

but wouldn't adding the package break things potentially

tropic socket
#

it's not so much the package. SerializedReferences are just iffy

crude jolt
#

so i rlly have to change my design huh

prisma saddle
tropic socket
#

I recall having problems renaming some interfaces and it would just break everything, but it's been a while

#

may be some attributes to help support that

prisma saddle
#

Yeah renaming types isn't that great with SR

crude jolt
#

right so I gotta find a workaround

urban viper
#

i mean you shouldnt have had that roundabout design with events to begin with tbh

rustic scaffold
#

Im late to the chat but I have done this in the past by serialising mono behaviour and using on validate to restrict the value to interface implementors

#

Does require a cast at runtime to then use but I see no way around that

crude jolt
#

update, I refactored my code and I'm not quite sure if this is composition but I feel like it is?

#

because instead of having the look trigger code and the actual visual turning on code in one script,

#

I decoupled the trigger code, letting it send an event when it's looked at

#

so at that point, any script that wants to be activated when the player looks at it turns on just needs to listen to it