Hello again. I cant seem to understand what is going wrong here.

Godot 4.3. I was happy to announce that converting object to bytes an back worked for the RPC but it does not.

Problem is this.

extends Resource
class_name PlayerData

var id: int
var player_name:String
var is_server:bool
var score: float

I have a dic of PlayerData

var player_list: Dictionary

The principle is this -> peer connected -> sends rpc to server to add_player() -> Server then sends to every player/peer RPC to create local players -> players are locally created in all peer instances.

But it seems that data is null..

In the server part i send bytes -> dictionary converted to bytes. The dictionary contains 2 players. So far so good.

Then in the local part 'add_local_players()` i get the dic bytes, then i convert back, but its not exact.

Bytes

Dic

id is correct

But here the data is null..

the casted player_obj from dictionary is null, not exactly null it just dont have the correct values.

And in the end no players gets added, even tho i have received bytes and converted them to dictionary..

Can someone has any idea why am i wrong here?

  • Jesusemora replied to this.
  • Alright, nobody wanted to help me here, had to pull out for harambe.
    Thanks to @volt from "sources" and this post

    TLDR:

    Create a sub class

    serializable.gd

    class_name Serializable
    
    
    # Convert instance to a dictionary.
    func to_dict() -> Dictionary:
    	var result = {
    		"_type": get_script().get_path()  # This is a reference to the class/script type.
    	}
    	
    	for property in self.get_property_list():
    		#print("Property name: ", property.name, " Usage: ", property.usage)
    		if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE:
    			result[property.name] = get(property.name)
    	
    	return result
    
    
    # Populate the instance from a dictionary.
    static func from_dict(data: Dictionary) -> Serializable:
    	var instance = load(data["_type"]).new()
    	
    	for key in data.keys():
    		if key != "_type":
    			instance.set(key, data[key])
    	
    	return instance

    Then extend this into your class:

    player_data.gd

    extends Serializable
    class_name PlayerData
    
    var id: int
    var player_name:String
    var is_server:bool
    var score: float

    Then to work with rpc just do this.
    In my case im doing this > peer joins > send notif to server with data > server adds to player_list > server sends out player_list to all peers > peers create players based on the list on their end.

    so.. in server send to peers part:

    	if multiplayer.is_server():
    		
    		for id in GameManager.player_list:  # this is a Dictionary of PlayerData objects
    			if not id == 1: # here i check if the player in the list is server, then dont do nothing.
    			
    				var list_byte: Array
    				
    				for b in GameManager.player_list:
    				
    					var pb = GameManager.player_list[b].to_dict()
    					list_byte.append(pb)
    
    				add_local_players.rpc_id(id,list_byte)
    				
    				pass
    				
    @rpc
    func add_local_players(player_list_bytes):
    
    	var player_list:Dictionary
    
    	for p in player_list_bytes:
    		var player_obj:PlayerData = PlayerData.from_dict(p)
    		player_list[player_obj.id]=player_obj
    	
    	# do more stuff with it

    kuligs2 this code is sus:

    for id in GameManager.player_list:
         if not id == 1:
              var bytes = var_to_bytes_with_objects(GameManager.player_list) # <----- you are iterating a list but then sending the entire list
              add_local_players.rpc_id(id, bytes)

    you are invalidating the entire point of checking if id == 1

      Jesusemora im avoiding sending add_local_players to the server wich is 1.

      Besides thats not the point of the problem. Problem is that byte data with objects are not actually readable objects..

      Even tho godot says it cant rpc objects, yet they can send bytes via rpc .. the supplied functions for conversion works but dont work.. so im just shaving my head thinking where did i go wrong..

      Alright, nobody wanted to help me here, had to pull out for harambe.
      Thanks to @volt from "sources" and this post

      TLDR:

      Create a sub class

      serializable.gd

      class_name Serializable
      
      
      # Convert instance to a dictionary.
      func to_dict() -> Dictionary:
      	var result = {
      		"_type": get_script().get_path()  # This is a reference to the class/script type.
      	}
      	
      	for property in self.get_property_list():
      		#print("Property name: ", property.name, " Usage: ", property.usage)
      		if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE:
      			result[property.name] = get(property.name)
      	
      	return result
      
      
      # Populate the instance from a dictionary.
      static func from_dict(data: Dictionary) -> Serializable:
      	var instance = load(data["_type"]).new()
      	
      	for key in data.keys():
      		if key != "_type":
      			instance.set(key, data[key])
      	
      	return instance

      Then extend this into your class:

      player_data.gd

      extends Serializable
      class_name PlayerData
      
      var id: int
      var player_name:String
      var is_server:bool
      var score: float

      Then to work with rpc just do this.
      In my case im doing this > peer joins > send notif to server with data > server adds to player_list > server sends out player_list to all peers > peers create players based on the list on their end.

      so.. in server send to peers part:

      	if multiplayer.is_server():
      		
      		for id in GameManager.player_list:  # this is a Dictionary of PlayerData objects
      			if not id == 1: # here i check if the player in the list is server, then dont do nothing.
      			
      				var list_byte: Array
      				
      				for b in GameManager.player_list:
      				
      					var pb = GameManager.player_list[b].to_dict()
      					list_byte.append(pb)
      
      				add_local_players.rpc_id(id,list_byte)
      				
      				pass
      				
      @rpc
      func add_local_players(player_list_bytes):
      
      	var player_list:Dictionary
      
      	for p in player_list_bytes:
      		var player_obj:PlayerData = PlayerData.from_dict(p)
      		player_list[player_obj.id]=player_obj
      	
      	# do more stuff with it
      kuligs2 changed the title to Help with byte/object conversion sent over RPC .