| /* | |
| * Copyright 2015 Google Inc. All rights reserved. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| // To run, use the `go_sample.sh` script. | |
| package main | |
| import ( | |
| "fmt" | |
| flatbuffers "github.com/google/flatbuffers/go" | |
| sample "github.com/google/flatbuffers/samples/MyGame/Sample" | |
| "strconv" | |
| ) | |
| // Example how to use Flatbuffers to create and read binary buffers. | |
| func main() { | |
| builder := flatbuffers.NewBuilder(0) | |
| // Create some weapons for our Monster ("Sword" and "Axe"). | |
| weaponOne := builder.CreateString("Sword") | |
| weaponTwo := builder.CreateString("Axe") | |
| sample.WeaponStart(builder) | |
| sample.WeaponAddName(builder, weaponOne) | |
| sample.WeaponAddDamage(builder, 3) | |
| sword := sample.WeaponEnd(builder) | |
| sample.WeaponStart(builder) | |
| sample.WeaponAddName(builder, weaponTwo) | |
| sample.WeaponAddDamage(builder, 5) | |
| axe := sample.WeaponEnd(builder) | |
| // Serialize the FlatBuffer data. | |
| name := builder.CreateString("Orc") | |
| sample.MonsterStartInventoryVector(builder, 10) | |
| // Note: Since we prepend the bytes, this loop iterates in reverse. | |
| for i := 9; i >= 0; i-- { | |
| builder.PrependByte(byte(i)) | |
| } | |
| inv := builder.EndVector(10) | |
| sample.MonsterStartWeaponsVector(builder, 2) | |
| // Note: Since we prepend the weapons, prepend in reverse order. | |
| builder.PrependUOffsetT(axe) | |
| builder.PrependUOffsetT(sword) | |
| weapons := builder.EndVector(2) | |
| pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0) | |
| sample.MonsterStart(builder) | |
| sample.MonsterAddPos(builder, pos) | |
| sample.MonsterAddHp(builder, 300) | |
| sample.MonsterAddName(builder, name) | |
| sample.MonsterAddInventory(builder, inv) | |
| sample.MonsterAddColor(builder, sample.ColorRed) | |
| sample.MonsterAddWeapons(builder, weapons) | |
| sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon) | |
| sample.MonsterAddEquipped(builder, axe) | |
| orc := sample.MonsterEnd(builder) | |
| builder.Finish(orc) | |
| // We now have a FlatBuffer that we could store on disk or send over a network. | |
| // ...Saving to file or sending over a network code goes here... | |
| // Instead, we are going to access this buffer right away (as if we just received it). | |
| buf := builder.FinishedBytes() | |
| // Note: We use `0` for the offset here, since we got the data using the | |
| // `builder.FinishedBytes()` method. This simulates the data you would store/receive in your | |
| // FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to | |
| // pass in the offset of `builder.Head()`, as the builder actually constructs the buffer | |
| // backwards. | |
| monster := sample.GetRootAsMonster(buf, 0) | |
| // Note: We did not set the `mana` field explicitly, so we get the | |
| // default value. | |
| assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150") | |
| assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300") | |
| assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()), | |
| "\"Orc\"") | |
| assert(monster.Color() == sample.ColorRed, "`monster.Color()`", | |
| strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed))) | |
| // Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object | |
| // gets created. If your code is very performance sensitive, you can pass in a pointer to an | |
| // existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce | |
| // the amount of object allocation/garbage collection. | |
| assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`", | |
| strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0") | |
| assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`", | |
| strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0") | |
| assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`", | |
| strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0") | |
| // For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used | |
| // to query the length of the vector. You can index the vector by passing an index value | |
| // into the accessor. | |
| for i := 0; i < monster.InventoryLength(); i++ { | |
| assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`", | |
| strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i)))) | |
| } | |
| expectedWeaponNames := []string{"Sword", "Axe"} | |
| expectedWeaponDamages := []int{3, 5} | |
| weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()` | |
| // to capture the output of that function. | |
| for i := 0; i < monster.WeaponsLength(); i++ { | |
| if monster.Weapons(weapon, i) { | |
| assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`", | |
| string(weapon.Name()), expectedWeaponNames[i]) | |
| assert(int(weapon.Damage()) == expectedWeaponDamages[i], | |
| "`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())), | |
| strconv.Itoa(expectedWeaponDamages[i])) | |
| } | |
| } | |
| // For FlatBuffer `union`s, you can get the type of the union, as well as the union | |
| // data itself. | |
| assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`", | |
| strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon))) | |
| unionTable := new(flatbuffers.Table) | |
| if monster.Equipped(unionTable) { | |
| // An example of how you can appropriately convert the table depending on the | |
| // FlatBuffer `union` type. You could add `else if` and `else` clauses to handle | |
| // other FlatBuffer `union` types for this field. (Similarly, this could be | |
| // done in a switch statement.) | |
| if monster.EquippedType() == sample.EquipmentWeapon { | |
| unionWeapon := new(sample.Weapon) | |
| unionWeapon.Init(unionTable.Bytes, unionTable.Pos) | |
| assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`", | |
| string(unionWeapon.Name()), "Axe") | |
| assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`", | |
| strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5)) | |
| } | |
| } | |
| fmt.Printf("The FlatBuffer was successfully created and verified!\n") | |
| } | |
| // A helper function to print out if an assertion failed. | |
| func assert(assertPassed bool, codeExecuted string, actualValue string, expectedValue string) { | |
| if assertPassed == false { | |
| panic("Assert failed! " + codeExecuted + " (" + actualValue + | |
| ") was not equal to " + expectedValue + ".") | |
| } | |
| } |