oniksan / godobuf Goto Github PK
View Code? Open in Web Editor NEWA Google Protobuf implementation for Godot / GDScript
License: BSD 3-Clause "New" or "Revised" License
A Google Protobuf implementation for Godot / GDScript
License: BSD 3-Clause "New" or "Revised" License
Protobuf 3.15 (Feb 18, 2021) introduced optional messages to know if a message value was set or not.
Example from: https://stackoverflow.com/a/62566052/12619313
syntax = "proto3";
message Foo {
int32 bar = 1;
optional int32 baz = 2;
}
A
has_baz()
/hasBaz()
method is generated for the optional field above, just as it was in proto2.
This is useful for example if you want to display imported 3d OpenStreetMap data that only sometimes contains height data.
message Vec3 {
float x = 1;
optional float y = 2; // Godot UP
float z = 3;
}
I'm curious if we could add setters for fields such as arrays and messages, is there any reason you couldn't? Its quite a pain if you already have an object created to then have to create another and set all the fields.
Hi there,
There's a slight issue with your submission on Godot's Asset Library as it uses "master" as download hash, but this changes everytime you push a commit and will thus invalidate the SHA256 sum we store to validate the download.
It would be better to use a commit hash, or a tag for version 0.2.2. You can edit the submission on https://godotengine.org/asset-library/asset/edit/608
The addon is amazing, is it still in development?
Are services and packages planned to come on next updates? If not, do you think it's possible? (In case I decide to fork and attempt to work on it)
Hello,
If you have such message:
message Nop {
string message = 1;
}
You will receive this error message from parser:
error: Syntax error in construction 'string'. Unacceptable use 'message'
Consider a message like this:
message Test {
oneof foo {
uint32 field1 = 1;
uint32 field2 = 2;
}
}
If I set field1 to 0, which is a default value in proto3, and pack the message, the result is empty. However, I should expect the packed data to include that field1 is set, that it's set to 0, and that field2 is unset.
message Ping {
int64 sent_at = 1;
}
message Pong {
int64 ping_sent_at = 1;
int64 received_at = 2;
int64 sent_at = 3;
}
message api_message {
oneof notice_way {
Ping ping = 1;
Pong pong = 2;
}
string name = 7;
}
var test2 = apiProto.api_message.new()
test2.set_name("asdad")
test2.set_ping() # miss func
How to fill in values for custom types?
Hello,
first of a BIG thank you for all the work that went into this project!
I'm trying to have a message wrapper so I can send only one message over the wire in order to have easier message recognition on the receiving end.
syntax = "proto3";
enum PlayerCommand {
SHOOT = 0;
}
message PlayerPosition {
int32 id = 1;
float x = 2;
float y = 3;
float rot = 4;
}
message PlayerInput {
int32 id = 1;
float rotL = 2;
float rotM = 3;
repeated PlayerCommand com = 4;
}
message PlayerPositions {
repeated PlayerPosition playerpos = 1;
}
message CompositeMessage {
oneof payload {
PlayerPosition playerstart = 1;
PlayerInput playerupdate = 2;
int32 removeplayer = 3;
PlayerPositions allplayersupdate = 4;
}
}
the generated code however does not seem to have the setter functions for playerstart
, playerupdate
and allplayersupdate
. The only setter generated is set_removeplayer
. The other type of functions like get_playerupdate
, clear_playerupdate
and new_playerupdate
are generated correctly.
The generated code raises 3 unused variable warnings which is a bit annoying if you try to have warning-free projects like me,
#wrong photo
syntax = "proto3";
message A {
B f1 = 1;
}
message B {
string f1 = 1 ;
}
#Right photo
message A {
message B {
string f1 = 1;
}
B f1 = 1;
}
Following #9, consider the following example:
message GiantSlime {}
message PettySlime {}
message MagicOrc {}
message NormalOrc {}
message Slime {
oneof type_of_slime {
GiantSlime giant_slime = 1;
PettySlime petty_slime = 2;
}
}
message Orc {
oneof type_of_orc {
MagicOrc magic_orc = 1;
NormalOrc normal_orc = 2;
}
}
message Enemy {
oneof type_of_enemy {
Slime slime = 1;
Orc orc = 2;
}
}
If one has the following function in GD Script:
const MyProto = preload("res://proto/myproto.gd")
....
func SpawnOrc(spawn_orc:MyProto.Orc) -> MyProto.Enemy:
var spawn_enemy:MyProto.Enemy = MyProto.Enemy.new()
var orc:MyProto.Orc = spawn_enemy.new_orc()
orc = spawn_orc
return spawn_enemy
spawn_enemy
will not contain a copy of spawn_orc
, but will instead be empty. The user would have to call the individual set_
function for each property, but will encounter that for composite properties that are defined by messages (like the one in this example) they'll have to initialise a new object and "set" it with the data that comes from spawn_orc
.
The API could provide a function to "deepcopy" one proto into another, thus avoiding the need of going each property one by one and setting it to the correct value. An example would be:
const MyProto = preload("res://proto/myproto.gd")
....
func SpawnOrc(spawn_orc:MyProto.Orc) -> MyProto.Enemy:
var spawn_enemy:MyProto.Enemy = MyProto.Enemy.new()
var orc:MyProto.Orc = spawn_enemy.new_orc()
orc.deepcopy(spawn_orc)
return spawn_enemy
GDScript now supports optional types. This feature helps with code readability and maintainability, and it also improves code completion in the editor. It would be great if Godobuf added types to its generated code (in function parameters and return values) to take advantage of this feature.
GDScript doesn't support namespaces, and so I'm running into a situation where proto messages can't be called the same thing as GDScript types.
For example, a serialized "Enemy" message vs. a Godot node type named "Enemy".
It would be nice if in the Godobuf importer we could set a name prefix, for example "Proto", so message Enemy
is translated to GDScript as ProtoEnemy
.
Hi there!
I like your idea of having a GDScript compiler for Godot. However, I need more advanced features of the Protocol Buffers for my use case, thus a few questions.
What is the reason for not supporting types, services, and optional fields?
It is because of the complexity of marshaling or missing features in Godot?
If so, what would be a reasonable approach and the next steps to implement support for them?
Do you consider making a protoc plugin reasonable since that imho would be the regular way to go?
Thanks!
Hi,
I adapted most of the API changes in my fork of godobuf. It is not ready yet to be merged but you can take a look at the changes
https://github.com/kelteseth/godobuf
Godot API Changes:
Buggy:
Not working:
protobuf_core.gd
line 106 and 109 error when using const
with []
. No idea how to solve this.
const DEFAULT_VALUES_3 = {
[...]
#PB_DATA_TYPE.BYTES: [],
PB_DATA_TYPE.MESSAGE: null,
#PB_DATA_TYPE.MAP: []
}
This next one looks similar to #26
Parse Error: Identifier "PROTO_VERSION" not declared in the current scope.
res://addons/protobuf/protobuf_core.gd:533 - Parse Error: Identifier "PROTO_VERSION" not declared in the current scope.`
Protobuf files are used to be shared between multiple projects. For example, I have a CMake/C++ based server that generates the Protobuf c++ files, if I change the content of my messages.proto. For Godot, I have to do it manually and often simply forget to do it. It would be handy to automatically convert the protofile on change (like CMake does) or a way on how to trigger it externally via a command line tool.
The lack of tests makes it somewhat difficult to contribute to this repo because I'm worried that by changing things, I'd be breaking other things :(
I have a proto3 map field with int32
keys:
message GameState {
map<int32, PlayerData> player_data = 6;
}
This normally works, except when the map key is 0
.
For example, this code is broken because from_bytes
returns error REQUIRED_FIELDS
:
var s = API.GameState.new()
s.add_player_data(0)
print(s.from_bytes(s.to_bytes())) # Prints -9, aka "REQUIRED_FIELDS".
However, when I change the map key to something else (e.g. 1
), deserialization works fine.
I assume this is due to improper handling of default values as map keys. I haven't tested it, but I assume the same issue is present for other default types (e.g. empty strings).
Hi Oleg,
Thanks for creating the proto converter! :)
I have three proto files:
File 1:
message P2PEvent {
oneof event {
FutureEvent future_event = 1;
ImmediateEvent immediate_event = 2;
}
}
File 2:
message FutureEvent {
oneof event {
...
}
}
File 3:
message ImmediateEvent {
oneof event {
...
}
}
I get errors when compile the parent file (File 1), I wonder if this case is supported?
Appreciate the help!
Given the proto:
// Sent from client->server
message Request {
message Init{}
oneof kind {
Init init = 1;
}
}
Godobuf generates:
class Request:
func _init():
var service
_init = PBField.new("init", PB_DATA_TYPE.MESSAGE, PB_RULE.OPTIONAL, 1, true, DEFAULT_VALUES_3[PB_DATA_TYPE.MESSAGE])
service = PBServiceField.new()
service.field = _init
service.func_ref = Callable(self, "new_init")
data[_init.tag] = service
var data = {}
var _init: PBField
Which fails to compile with Variable "_init" has the same name as a previously declared function.
. Maybe generated variable names should use a __
prefix to dodge conflicts?
Currently, the generated classes extend Object, so when they're no longer used, they need to be deallocated manually or else they will leak (see here). I propose that they should extend Reference so when they're no longer used, they get deallocated automatically.
Where is C# or VisualScript support? I really need Protobuf for C# but Godot isn't recognizing it as a NuGet package.
Hello,
Is it possible to add support of service? For example:
syntax = "proto3";
service ServiceName {
rpc Ping(PingOut) returns (PingIn) {}
}
message PingOut {}
message PingIn {}
All protobuf files are here:
https://github.com/OpenShiftDemos/srt-godot-test/tree/main/proto
Snippet:
DualStickRawInputCommandBuffer.proto
syntax = "proto2";
package redhatgamedev.srt;
import "box2d.proto";
message DualStickRawInputCommandBuffer
{
required box2d.PbVec2 pbv2Move = 1;
required box2d.PbVec2 pbv2Shoot = 2;
}
box2d.proto
syntax = "proto2";
package box2d;
message PbVec2 {
required float x = 1;
required float y = 2;
}
Results in compilation error:
/home/thoraxe/Red_Hat/openshift/srt-godot-test/proto/DualStickRawInputCommandBuffer.proto: analysis.
/home/thoraxe/Red_Hat/openshift/srt-godot-test/proto/DualStickRawInputCommandBuffer.proto:9:5: error: Type 'box2d.PbVec2' of the 'pbv2Move' field undefined
/home/thoraxe/Red_Hat/openshift/srt-godot-test/proto/DualStickRawInputCommandBuffer.proto:10:5: error: Type 'box2d.PbVec2' of the 'pbv2Shoot' field undefined
/home/thoraxe/Red_Hat/openshift/srt-godot-test/proto/DualStickRawInputCommandBuffer.proto: analysis error.
It appears that import parsing may not be working correctly. PbVec2
is defined in box2d.proto
which is imported by DualStickRawInputCommandBuffer.proto
.
Trying to use this against Godot 3.4
I am seeing various errors now and again. Here's one that came up with Godot mostly just sitting there at the editor:
ERROR: Failed parse script res://addons/protobuf/protobuf_core.gd
The identifier "PROTO_VERSION" isn't declared in the current scope.
at: reload_all_workspace_scripts (modules/gdscript/language_server/gdscript_workspace.cpp:217)
Right now, the only way to "reset" a repeated field seems to be clearing the field (which I believe to be broken due to #21) and re-adding all entries in a loop - for example:
msg.clear_repeated_field()
for item in [1, 2, 3]:
msg.add_repeated_field(item)
It would be super cool to get a method where we could do this in one statement - i.e. msg.set_repeated_field([1, 2, 3])
!
Given:
message Foo {
repeated int32 i = 1;
repeated string s = 2;
repeated Bar b = 3;
}
Currently we generate:
get_i() -> Array
get_s() -> Array
get_b() -> Array
With gdscript warnings enabled, this tends to generate lots of warnings in consuming code, and require "unsafe" casts that must be ignored.
It would be nice if we could generate typed return values, like:
get_i() -> Array[int]
get_s() -> Array[string]
get_b() -> Array[Bar]
I have a repeated proto3 field:
repeated int32 players_in_game = 11;
Adding to the field (msg.add_players_in_game(1)
) works fine at first.
However, once you clear the field (msg.clear_players_in_game()
), further additions don't work since the field seems to be getting reset to a singular int (I think). Per the language guide, the default value of an cleared repeated field should be an empty array.
Error message:
Invalid call. Nonexistent function 'append' in base 'int'.
For reference, the generated code:
func clear_players_in_game() -> void:
data[11].state = PB_SERVICE_STATE.UNFILLED
_players_in_game.value = DEFAULT_VALUES_3[PB_DATA_TYPE.INT32]
func add_players_in_game(value : int) -> void:
_players_in_game.value.append(value) # <-- breakage happens here
This is happening on version 0.4.4 on Godot 3.4.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.