|
19 | 19 | package main |
20 | 20 |
|
21 | 21 | import ( |
22 | | - flatbuffers "github.com/google/flatbuffers/go" |
23 | | - "fmt" |
24 | | - "strconv" |
25 | | - sample "MyGame/Sample" |
| 22 | + sample "MyGame/Sample" |
| 23 | + "fmt" |
| 24 | + flatbuffers "github.com/google/flatbuffers/go" |
| 25 | + "strconv" |
26 | 26 | ) |
27 | 27 |
|
28 | 28 | // Example how to use Flatbuffers to create and read binary buffers. |
29 | 29 | func main() { |
30 | | - builder := flatbuffers.NewBuilder(0) |
31 | | - |
32 | | - // Create some weapons for our Monster ("Sword" and "Axe"). |
33 | | - weaponOne := builder.CreateString("Sword") |
34 | | - weaponTwo := builder.CreateString("Axe") |
35 | | - |
36 | | - sample.WeaponStart(builder) |
37 | | - sample.WeaponAddName(builder, weaponOne) |
38 | | - sample.WeaponAddDamage(builder, 3) |
39 | | - sword := sample.WeaponEnd(builder) |
40 | | - |
41 | | - sample.WeaponStart(builder) |
42 | | - sample.WeaponAddName(builder, weaponTwo) |
43 | | - sample.WeaponAddDamage(builder, 5) |
44 | | - axe := sample.WeaponEnd(builder) |
45 | | - |
46 | | - // Serialize the FlatBuffer data. |
47 | | - name := builder.CreateString("Orc") |
48 | | - |
49 | | - sample.MonsterStartInventoryVector(builder, 10) |
50 | | - // Note: Since we prepend the bytes, this loop iterates in reverse. |
51 | | - for i := 9; i >= 0; i-- { |
52 | | - builder.PrependByte(byte(i)) |
53 | | - } |
54 | | - inv := builder.EndVector(10) |
55 | | - |
56 | | - sample.MonsterStartWeaponsVector(builder, 2) |
57 | | - // Note: Since we prepend the weapons, prepend in reverse order. |
58 | | - builder.PrependUOffsetT(axe) |
59 | | - builder.PrependUOffsetT(sword) |
60 | | - weapons := builder.EndVector(2) |
61 | | - |
62 | | - pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0) |
63 | | - |
64 | | - sample.MonsterStart(builder) |
65 | | - sample.MonsterAddPos(builder, pos) |
66 | | - sample.MonsterAddHp(builder, 300) |
67 | | - sample.MonsterAddName(builder, name) |
68 | | - sample.MonsterAddInventory(builder, inv) |
69 | | - sample.MonsterAddColor(builder, sample.ColorRed) |
70 | | - sample.MonsterAddWeapons(builder, weapons) |
71 | | - sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon) |
72 | | - sample.MonsterAddEquipped(builder, axe) |
73 | | - orc := sample.MonsterEnd(builder) |
74 | | - |
75 | | - builder.Finish(orc) |
76 | | - |
77 | | - // We now have a FlatBuffer that we could store on disk or send over a network. |
78 | | - |
79 | | - // ...Saving to file or sending over a network code goes here... |
80 | | - |
81 | | - // Instead, we are going to access this buffer right away (as if we just received it). |
82 | | - |
83 | | - buf := builder.FinishedBytes() |
84 | | - |
85 | | - // Note: We use `0` for the offset here, since we got the data using the |
86 | | - // `builder.FinishedBytes()` method. This simulates the data you would store/receive in your |
87 | | - // FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to |
88 | | - // pass in the offset of `builder.Head()`, as the builder actually constructs the buffer |
89 | | - // backwards. |
90 | | - monster := sample.GetRootAsMonster(buf, 0) |
91 | | - |
92 | | - // Note: We did not set the `mana` field explicitly, so we get the |
93 | | - // default value. |
94 | | - assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150") |
95 | | - assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300") |
96 | | - assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()), |
97 | | - "\"Orc\"") |
98 | | - assert(monster.Color() == sample.ColorRed, "`monster.Color()`", |
99 | | - strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed))) |
100 | | - |
101 | | - // Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object |
102 | | - // gets created. If your code is very performance sensitive, you can pass in a pointer to an |
103 | | - // existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce |
104 | | - // the amount of object allocation/garbage collection. |
105 | | - assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`", |
106 | | - strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0") |
107 | | - assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`", |
108 | | - strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0") |
109 | | - assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`", |
110 | | - strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0") |
111 | | - |
112 | | - // For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used |
113 | | - // to query the length of the vector. You can index the vector by passing an index value |
114 | | - // into the accessor. |
115 | | - for i := 0; i < monster.InventoryLength(); i++ { |
116 | | - assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`", |
117 | | - strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i)))) |
118 | | - } |
119 | | - |
120 | | - expectedWeaponNames := []string{"Sword", "Axe"} |
121 | | - expectedWeaponDamages := []int{3, 5} |
122 | | - weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()` |
123 | | - // to capture the output of that function. |
124 | | - for i := 0; i < monster.WeaponsLength(); i++ { |
125 | | - if monster.Weapons(weapon, i) { |
126 | | - assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`", |
127 | | - string(weapon.Name()), expectedWeaponNames[i]) |
128 | | - assert(int(weapon.Damage()) == expectedWeaponDamages[i], |
129 | | - "`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())), |
130 | | - strconv.Itoa(expectedWeaponDamages[i])) |
131 | | - } |
132 | | - } |
133 | | - |
134 | | - // For FlatBuffer `union`s, you can get the type of the union, as well as the union |
135 | | - // data itself. |
136 | | - assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`", |
137 | | - strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon))) |
138 | | - |
139 | | - unionTable := new(flatbuffers.Table) |
140 | | - if monster.Equipped(unionTable) { |
141 | | - // An example of how you can appropriately convert the table depending on the |
142 | | - // FlatBuffer `union` type. You could add `else if` and `else` clauses to handle |
143 | | - // other FlatBuffer `union` types for this field. (Similarly, this could be |
144 | | - // done in a switch statement.) |
145 | | - if monster.EquippedType() == sample.EquipmentWeapon { |
146 | | - unionWeapon := new(sample.Weapon) |
147 | | - unionWeapon.Init(unionTable.Bytes, unionTable.Pos) |
148 | | - |
149 | | - assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`", |
150 | | - string(unionWeapon.Name()), "Axe") |
151 | | - assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`", |
152 | | - strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5)) |
153 | | - } |
154 | | - } |
155 | | - |
156 | | - fmt.Printf("The FlatBuffer was successfully created and verified!\n") |
| 30 | + builder := flatbuffers.NewBuilder(0) |
| 31 | + |
| 32 | + // Create some weapons for our Monster ("Sword" and "Axe"). |
| 33 | + weaponOne := builder.CreateString("Sword") |
| 34 | + weaponTwo := builder.CreateString("Axe") |
| 35 | + |
| 36 | + sample.WeaponStart(builder) |
| 37 | + sample.WeaponAddName(builder, weaponOne) |
| 38 | + sample.WeaponAddDamage(builder, 3) |
| 39 | + sword := sample.WeaponEnd(builder) |
| 40 | + |
| 41 | + sample.WeaponStart(builder) |
| 42 | + sample.WeaponAddName(builder, weaponTwo) |
| 43 | + sample.WeaponAddDamage(builder, 5) |
| 44 | + axe := sample.WeaponEnd(builder) |
| 45 | + |
| 46 | + // Serialize the FlatBuffer data. |
| 47 | + name := builder.CreateString("Orc") |
| 48 | + |
| 49 | + sample.MonsterStartInventoryVector(builder, 10) |
| 50 | + // Note: Since we prepend the bytes, this loop iterates in reverse. |
| 51 | + for i := 9; i >= 0; i-- { |
| 52 | + builder.PrependByte(byte(i)) |
| 53 | + } |
| 54 | + inv := builder.EndVector(10) |
| 55 | + |
| 56 | + sample.MonsterStartWeaponsVector(builder, 2) |
| 57 | + // Note: Since we prepend the weapons, prepend in reverse order. |
| 58 | + builder.PrependUOffsetT(axe) |
| 59 | + builder.PrependUOffsetT(sword) |
| 60 | + weapons := builder.EndVector(2) |
| 61 | + |
| 62 | + pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0) |
| 63 | + |
| 64 | + sample.MonsterStart(builder) |
| 65 | + sample.MonsterAddPos(builder, pos) |
| 66 | + sample.MonsterAddHp(builder, 300) |
| 67 | + sample.MonsterAddName(builder, name) |
| 68 | + sample.MonsterAddInventory(builder, inv) |
| 69 | + sample.MonsterAddColor(builder, sample.ColorRed) |
| 70 | + sample.MonsterAddWeapons(builder, weapons) |
| 71 | + sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon) |
| 72 | + sample.MonsterAddEquipped(builder, axe) |
| 73 | + orc := sample.MonsterEnd(builder) |
| 74 | + |
| 75 | + builder.Finish(orc) |
| 76 | + |
| 77 | + // We now have a FlatBuffer that we could store on disk or send over a network. |
| 78 | + |
| 79 | + // ...Saving to file or sending over a network code goes here... |
| 80 | + |
| 81 | + // Instead, we are going to access this buffer right away (as if we just received it). |
| 82 | + |
| 83 | + buf := builder.FinishedBytes() |
| 84 | + |
| 85 | + // Note: We use `0` for the offset here, since we got the data using the |
| 86 | + // `builder.FinishedBytes()` method. This simulates the data you would store/receive in your |
| 87 | + // FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to |
| 88 | + // pass in the offset of `builder.Head()`, as the builder actually constructs the buffer |
| 89 | + // backwards. |
| 90 | + monster := sample.GetRootAsMonster(buf, 0) |
| 91 | + |
| 92 | + // Note: We did not set the `mana` field explicitly, so we get the |
| 93 | + // default value. |
| 94 | + assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150") |
| 95 | + assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300") |
| 96 | + assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()), |
| 97 | + "\"Orc\"") |
| 98 | + assert(monster.Color() == sample.ColorRed, "`monster.Color()`", |
| 99 | + strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed))) |
| 100 | + |
| 101 | + // Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object |
| 102 | + // gets created. If your code is very performance sensitive, you can pass in a pointer to an |
| 103 | + // existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce |
| 104 | + // the amount of object allocation/garbage collection. |
| 105 | + assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`", |
| 106 | + strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0") |
| 107 | + assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`", |
| 108 | + strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0") |
| 109 | + assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`", |
| 110 | + strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0") |
| 111 | + |
| 112 | + // For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used |
| 113 | + // to query the length of the vector. You can index the vector by passing an index value |
| 114 | + // into the accessor. |
| 115 | + for i := 0; i < monster.InventoryLength(); i++ { |
| 116 | + assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`", |
| 117 | + strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i)))) |
| 118 | + } |
| 119 | + |
| 120 | + expectedWeaponNames := []string{"Sword", "Axe"} |
| 121 | + expectedWeaponDamages := []int{3, 5} |
| 122 | + weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()` |
| 123 | + // to capture the output of that function. |
| 124 | + for i := 0; i < monster.WeaponsLength(); i++ { |
| 125 | + if monster.Weapons(weapon, i) { |
| 126 | + assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`", |
| 127 | + string(weapon.Name()), expectedWeaponNames[i]) |
| 128 | + assert(int(weapon.Damage()) == expectedWeaponDamages[i], |
| 129 | + "`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())), |
| 130 | + strconv.Itoa(expectedWeaponDamages[i])) |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + // For FlatBuffer `union`s, you can get the type of the union, as well as the union |
| 135 | + // data itself. |
| 136 | + assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`", |
| 137 | + strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon))) |
| 138 | + |
| 139 | + unionTable := new(flatbuffers.Table) |
| 140 | + if monster.Equipped(unionTable) { |
| 141 | + // An example of how you can appropriately convert the table depending on the |
| 142 | + // FlatBuffer `union` type. You could add `else if` and `else` clauses to handle |
| 143 | + // other FlatBuffer `union` types for this field. (Similarly, this could be |
| 144 | + // done in a switch statement.) |
| 145 | + if monster.EquippedType() == sample.EquipmentWeapon { |
| 146 | + unionWeapon := new(sample.Weapon) |
| 147 | + unionWeapon.Init(unionTable.Bytes, unionTable.Pos) |
| 148 | + |
| 149 | + assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`", |
| 150 | + string(unionWeapon.Name()), "Axe") |
| 151 | + assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`", |
| 152 | + strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5)) |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + fmt.Printf("The FlatBuffer was successfully created and verified!\n") |
157 | 157 | } |
158 | 158 |
|
159 | 159 | // A helper function to print out if an assertion failed. |
160 | 160 | func assert(assertPassed bool, codeExecuted string, actualValue string, expectedValue string) { |
161 | | - if assertPassed == false { |
162 | | - panic("Assert failed! " + codeExecuted + " (" + actualValue + |
163 | | - ") was not equal to " + expectedValue + ".") |
164 | | - } |
| 161 | + if assertPassed == false { |
| 162 | + panic("Assert failed! " + codeExecuted + " (" + actualValue + |
| 163 | + ") was not equal to " + expectedValue + ".") |
| 164 | + } |
165 | 165 | } |
0 commit comments