From d2fcb1aa8593cd834682cace453631fbda8ebdef Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 6 Apr 2021 00:34:29 +0300 Subject: [PATCH 1/6] Update changelogs --- docs_md/changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index e610f16..4a8d367 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -136,7 +136,7 @@ Also check _component.template.lua_ what you can use for your own custom compone Hey! Are you tired from **Druid** updates? _(It's a joke)_ -Finally, got a time to release component to process huge amount of data. So introducing: **DataList** component. I can't say what it's "infinity" scroll, but it can help to solve your problem with `GUI nodes limit reached` and helps with scroll optimization. Give feedback about it! +Finally, got a time to release component to process huge amount of data. So introducing: **DataList** component. It can help solve your problem with `GUI nodes limit reached` and helps with scroll optimization. Give feedback about it! The next important stuff is **EmmyLua** docs. I'm implemented EmmyLua doc generator from LuaDoc and Protofiles, so now you can use EmmyLua annotations inside your IDE instead of website API looking or source code scanning. @@ -144,7 +144,7 @@ Also the **Druid examples** is reworked, so each example will be in separate col Input priority got reworked too. Now instead of two input stacks: usual and high, Druid use simple input priority value. -And I should note here is several breaking changes, take a look in changelogs. +And I should note here are several breaking changes, take a look in changelogs. Wanna something more? [Add an issues!](https://github.com/Insality/druid/issues) Have a good day. From 40c360916298e1da9b79a762d7f8191dab51c077 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 8 Apr 2021 00:29:16 +0300 Subject: [PATCH 2/6] Update docs --- README.md | 2 ++ docs_md/01-components.md | 66 ++++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 1642bd5..e58b705 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,8 @@ druid.on_window_callback(event) - **[Dynamic Grid](docs_md/01-components.md#dynamic-grid)** - Component to manage node positions with different sizes. Only in one row or column +- **[Dynamic Grid](docs_md/01-components.md#data-list)** - Component to manage data for huge dataset in scroll + - **[Input](docs_md/01-components.md#input)** - User text input component - **[Lang text](docs_md/01-components.md#lang-text)** - Wrap on Text component to handle localization diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 384edcc..f0a833c 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -4,7 +4,7 @@ ## Button -[Button API here](https://insality.github.io/druid/modules/druid.button.html) +[Button API here](https://insality.github.io/druid/modules/Button.html) ### Overview Basic Druid input component. Handle input on node and provide different callbacks on touch events. @@ -36,7 +36,7 @@ _fill example usecases_ ## Text -[Text API here](https://insality.github.io/druid/modules/druid.text.html) +[Text API here](https://insality.github.io/druid/modules/Text.html) ### Overview Basic Druid text component. Text components by default have the text size adjusting. @@ -55,7 +55,7 @@ Create text node with druid: `text = druid:new_text(node_name, [initial_value], ## Blocker -[Blocker API here](https://insality.github.io/druid/modules/druid.blocker.html) +[Blocker API here](https://insality.github.io/druid/modules/Blocker.html) ### Overview Druid component for block input. Use it to block input in special zone. @@ -75,7 +75,7 @@ So you can do the safe zones, when you have the big buttons ## Back Handler -[Back handler API here](https://insality.github.io/druid/modules/druid.back_handler.html) +[Back handler API here](https://insality.github.io/druid/modules/BackHandler.html) ### Overview Component to handle back button. It handle Android back button and Backspace key. Key triggers in `input.binding` should be setup for correct working. @@ -87,7 +87,7 @@ Setup callback with `druid:new_back_handler(callback)` ## Lang text -[Lang text API here](https://insality.github.io/druid/modules/druid.lang_text.html) +[Lang text API here](https://insality.github.io/druid/modules/LangText.html) ### Overview Wrap on Text component to handle localization. It uses druid get_text_function to set text by it's id @@ -99,7 +99,7 @@ Create lang text component with druid `text = druid:new_lang_text(node_name, loc ## Scroll -[Scroll API here](https://insality.github.io/druid/modules/druid.scroll.html) +[Scroll API here](https://insality.github.io/druid/modules/Scroll.html) ### Overview Basic Druid scroll component. Handle all scrolling stuff in druid GUI @@ -120,7 +120,7 @@ Usually, Place _view_node_ and as children add _content_node_: *Here content_node below view_node, in game content_node be able to scroll left until end* ### Notes -- Scroll by default style have inertion and extra size for strecthing effect. It can be adjust via scroll [style settings](https://insality.github.io/druid/modules/druid.scroll.html#Style) +- Scroll by default style have inertion and extra size for strecthing effect. It can be adjust via scroll [style settings](https://insality.github.io/druid/modules/Scroll.html#Style) - You can setup "points of interest". Scroll always will be centered on closes point of interest. It is able to create slider without inertion and points of interest on each scroll element. - Scroll have next events: - *on_scroll* (self, position) On scroll move callback @@ -133,7 +133,7 @@ Usually, Place _view_node_ and as children add _content_node_: ## Progress -[Progress API here](https://insality.github.io/druid/modules/druid.progress.html) +[Progress API here](https://insality.github.io/druid/modules/Progress.html) ### Overview Basic Druid progress bar component @@ -151,7 +151,7 @@ Key is value from druid const: const.SIDE.X (or just "x") or const.SIDE.Y (or ju ## Slider -[Slider API here](https://insality.github.io/druid/modules/druid.slider.html) +[Slider API here](https://insality.github.io/druid/modules/Slider.html) ### Overview Basic Druid slider component @@ -167,7 +167,7 @@ Pin node (node_name in params) should be placed in zero position (initial). It w ## Input -[Input API here](https://insality.github.io/druid/modules/druid.input.html) +[Input API here](https://insality.github.io/druid/modules/Input.html) ### Overview Basic Druid text input component @@ -187,7 +187,7 @@ Create input component with druid: `input = druid:new_input(button_node_name, te ## Checkbox -[Checkbox API here](https://insality.github.io/druid/modules/druid.checkbox.html) +[Checkbox API here](https://insality.github.io/druid/modules/Checkbox.html) ### Overview Basic Druid checkbox component. @@ -201,7 +201,7 @@ Create checkbox component with druid: `checkbox = druid:new_checkbox(node, callb ## Checkbox group -[Checkbox group API here](https://insality.github.io/druid/modules/druid.checkbox_group.html) +[Checkbox group API here](https://insality.github.io/druid/modules/CheckboxGroup.html) ### Overview Several checkboxes in one group @@ -215,7 +215,7 @@ Create checkbox_group component with druid: `group = druid:new_checkbox_group(no ## Radio group -[Radio group API here](https://insality.github.io/druid/modules/druid.radio_group.html) +[Radio group API here](https://insality.github.io/druid/modules/RadioGroup.html) ### Overview Several checkboxes in one group with single choice @@ -230,7 +230,7 @@ Create radio_group component with druid: `group = druid:new_radio_group(nodes[], ## Timer -[Timer API here](https://insality.github.io/druid/modules/druid.timer.html) +[Timer API here](https://insality.github.io/druid/modules/Timer.html) ### Overview Handle timer work on gui text node @@ -245,7 +245,7 @@ Create timer component with druid: `timer = druid:new_timer(text_node, from_seco ## Static Grid -[Static Grid API here](https://insality.github.io/druid/modules/druid.static_grid.html) +[Static Grid API here](https://insality.github.io/druid/modules/StaticGrid.html) ### Overview Component for manage node positions. @@ -266,7 +266,7 @@ Create component with druid: `grid = druid:new_static_grid(parent_node, prefab_ ## Dynamic Grid -[Dynamic Grid API here](https://insality.github.io/druid/modules/druid.dynamic_grid.html) +[Dynamic Grid API here](https://insality.github.io/druid/modules/DynamicGrid.html) ### Overview Component for manage node positions with different node sizes. @@ -276,7 +276,7 @@ Dynamic Grid can't have gaps between elements Dynamic Grid should have __West__, __East__, __South__ or __North__ pivot (vertical or horizontal element placement) ### Setup -Create component with druid: `grid = druid:new_dynamic_grid(parent_node)` +Create component with druid: `grid = druid:new_dynamic_grid(parent_node)` Check the _parent_node_ have correct pivot point. You will get the error otherwise. @@ -290,8 +290,34 @@ Check the _parent_node_ have correct pivot point. You will get the error otherwi - First node placed at Grid pivot point. Other nodes placed nearby of other nodes. - On *add/remove* nodes always shifted. You can point the shift side in this functions (*is_shift_left* boolean argumentp + +## Data List +[Data List API here](https://insality.github.io/druid/modules/DataList.html) + +### Overview +Component to manage data for huge dataset in scroll. DataList create elements only in scroll view. +It requires Druid Scroll and Druid Grid (Static or Dynamic) components + + +### Setup +Create component with druid: `grid = druid:new_data_list(scroll, grid, create_callback)` +- scroll - already created Scroll component +- grid - already created StaticGrid or DynamicGrid component +- create_function - your function to create node instances. This callback have next parameters: fun(self, data, index, data_list) + - self - Script/Druid context + - data- your element data + - index - element index + - data_list - current DataList component + +Create function should return root node and optionaly, Druid component. It’s required to manage create/remove lifecycle. + +### Notes +- Set data with `data_list:set_data({...})` after component initialize +- You can use `data_list:scroll_to_index()` function to show data element + + ## Hover -[Hover API here](https://insality.github.io/druid/modules/druid.hover.html) +[Hover API here](https://insality.github.io/druid/modules/Hover.html) ### Overview System Druid component, handle hover node state. @@ -306,7 +332,7 @@ Create hover component with druid: `hover = druid:new_hover(node, callback)` ## Swipe -[Swipe API here](https://insality.github.io/druid/modules/druid.swipe.html) +[Swipe API here](https://insality.github.io/druid/modules/Swipe.html) ### Overview System Druid component, handle swipe actions on node @@ -327,7 +353,7 @@ Create swipe component with druid: `hover = druid:new_swipe(node, swipe_callback ## Drag -[Drag API here](https://insality.github.io/druid/modules/druid.drag.html) +[Drag API here](https://insality.github.io/druid/modules/Drag.html) ### Overview System Druid component, handle drag actions on node From 63a6af3faa643d13119c5f35085b601c4543d4e0 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 8 Apr 2021 00:29:57 +0300 Subject: [PATCH 3/6] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e58b705..b09f6a6 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ druid.on_window_callback(event) - **[Dynamic Grid](docs_md/01-components.md#dynamic-grid)** - Component to manage node positions with different sizes. Only in one row or column -- **[Dynamic Grid](docs_md/01-components.md#data-list)** - Component to manage data for huge dataset in scroll +- **[Data List](docs_md/01-components.md#data-list)** - Component to manage data for huge dataset in scroll - **[Input](docs_md/01-components.md#input)** - User text input component From 271fdd2b575216662225e5d9126a4447f3035379 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 23 May 2021 21:10:09 +0300 Subject: [PATCH 4/6] #132 Add example: add/remove grid with animations --- example/example.collection | 63 ++ example/example.gui_script | 1 + .../grid_animations.collection | 37 ++ .../grid/grid_animations/grid_animations.gui | 626 ++++++++++++++++++ .../grid_animations.gui_script | 65 ++ 5 files changed, 792 insertions(+) create mode 100644 example/examples/grid/grid_animations/grid_animations.collection create mode 100644 example/examples/grid/grid_animations/grid_animations.gui create mode 100644 example/examples/grid/grid_animations/grid_animations.gui_script diff --git a/example/example.collection b/example/example.collection index f638aa2..4baed06 100644 --- a/example/example.collection +++ b/example/example.collection @@ -869,3 +869,66 @@ embedded_instances { z: 1.0 } } +embedded_instances { + id: "grid_animations" + data: "components {\n" + " id: \"screen_factory\"\n" + " component: \"/monarch/screen_factory.script\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + " properties {\n" + " id: \"screen_id\"\n" + " value: \"grid_animations\"\n" + " type: PROPERTY_TYPE_HASH\n" + " }\n" + " properties {\n" + " id: \"popup\"\n" + " value: \"true\"\n" + " type: PROPERTY_TYPE_BOOLEAN\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"collectionfactory\"\n" + " type: \"collectionfactory\"\n" + " data: \"prototype: \\\"/example/examples/grid/grid_animations/grid_animations.collection\\\"\\n" + "load_dynamically: false\\n" + "\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" + "" + position { + x: 0.0 + y: 0.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} diff --git a/example/example.gui_script b/example/example.gui_script index dcb012c..25a65fd 100644 --- a/example/example.gui_script +++ b/example/example.gui_script @@ -113,6 +113,7 @@ local function init_lobby(self) self.lobby_grid:add(get_button_disabled(self, "Static grid", "scroll_scene")) self.lobby_grid:add(get_button_disabled(self, "Dynamic grid", "scroll_scene")) self.lobby_grid:add(get_button_disabled(self, "Scroll binding", "scroll_scene")) + self.lobby_grid:add(get_button(self, "Add/Remove animations", "grid_animations")) self.lobby_grid:add(get_title(self, "Data list / Infinity scroll")) self.lobby_grid:add(get_button(self, "With static grid", "data_list_static_grid")) diff --git a/example/examples/grid/grid_animations/grid_animations.collection b/example/examples/grid/grid_animations/grid_animations.collection new file mode 100644 index 0000000..76f1b4e --- /dev/null +++ b/example/examples/grid/grid_animations/grid_animations.collection @@ -0,0 +1,37 @@ +name: "grid_animations" +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"grid_animations\"\n" + " component: \"/example/examples/grid/grid_animations/grid_animations.gui\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" + "" + position { + x: 0.0 + y: 0.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} diff --git a/example/examples/grid/grid_animations/grid_animations.gui b/example/examples/grid/grid_animations/grid_animations.gui new file mode 100644 index 0000000..b2d39c0 --- /dev/null +++ b/example/examples/grid/grid_animations/grid_animations.gui @@ -0,0 +1,626 @@ +script: "/example/examples/grid/grid_animations/grid_animations.gui_script" +fonts { + name: "game" + font: "/example/assets/fonts/game.font" +} +textures { + name: "kenney" + texture: "/example/assets/images/kenney.atlas" +} +background_color { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 +} +nodes { + position { + x: 300.0 + y: 415.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 600.0 + y: 830.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "root" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: -100.0 + y: -200.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 200.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEMPLATE + id: "button_add" + parent: "root" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 130.0 + y: 60.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/button_blue" + id: "button_add/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_add" + layer: "image" + inherit_alpha: true + slice9 { + x: 15.0 + y: 15.0 + z: 15.0 + w: 15.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: true + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: 0.0 + y: 7.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.7 + y: 0.7 + z: 1.0 + w: 1.0 + } + size { + x: 200.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Add\n" + "" + font: "game" + id: "button_add/text" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + shadow { + x: 0.101960786 + y: 0.2 + z: 0.6 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "button_add/button" + layer: "text" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.78 + overridden_fields: 8 + template_node_child: true + text_leading: 1.0 + text_tracking: 0.0 +} +nodes { + position { + x: 100.0 + y: -200.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 200.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEMPLATE + id: "button_remove" + parent: "root" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 130.0 + y: 60.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/button_blue" + id: "button_remove/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_remove" + layer: "image" + inherit_alpha: true + slice9 { + x: 15.0 + y: 15.0 + z: 15.0 + w: 15.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: true + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: 0.0 + y: 7.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.7 + y: 0.7 + z: 1.0 + w: 1.0 + } + size { + x: 200.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Remove\n" + "" + font: "game" + id: "button_remove/text" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + shadow { + x: 0.101960786 + y: 0.2 + z: 0.6 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "button_remove/button" + layer: "text" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.78 + overridden_fields: 8 + template_node_child: true + text_leading: 1.0 + text_tracking: 0.0 +} +nodes { + position { + x: 0.0 + y: 108.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 600.0 + y: 200.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "grid" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 80.0 + y: 110.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "prefab" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 80.0 + y: 110.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/button_green" + id: "prefab_icon" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "prefab" + layer: "" + inherit_alpha: true + slice9 { + x: 10.0 + y: 10.0 + z: 10.0 + w: 10.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: -2.0 + y: 8.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.5 + y: 1.5 + z: 1.0 + w: 1.0 + } + size { + x: 30.0 + y: 30.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 0.9019608 + z: 0.6 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "1" + font: "game" + id: "prefab_text" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + shadow { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "prefab_icon" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.5 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 +} +layers { + name: "image" +} +layers { + name: "text" +} +material: "/builtins/materials/gui.material" +adjust_reference: ADJUST_REFERENCE_PARENT +max_nodes: 512 diff --git a/example/examples/grid/grid_animations/grid_animations.gui_script b/example/examples/grid/grid_animations/grid_animations.gui_script new file mode 100644 index 0000000..2a2ea12 --- /dev/null +++ b/example/examples/grid/grid_animations/grid_animations.gui_script @@ -0,0 +1,65 @@ +local druid = require("druid.druid") + + +local function add_element(self) + -- Limit up to 10 nodes in this example + if #self.grid.nodes >= 10 then + return + end + + -- Make new element to insert into the grid + local nodes = gui.clone_tree(self.prefab) + gui.set_enabled(nodes["prefab"], true) + self.grid:add(nodes["prefab"]) + gui.set_text(nodes["prefab_text"], #self.grid.nodes) + + -- Animate new element after _grid:add_ + -- Note, what Grid component take care of node position, so we can't + -- animate position of the root node. We need insert one more anchor node to make + -- it possible. In this example it is "prefab_icon" + gui.animate(nodes["prefab_icon"], "position.y", 20, gui.EASING_OUTSINE, 0.4, 0, nil, gui.PLAYBACK_ONCE_BACKWARD) + gui.animate(nodes["prefab_icon"], "color.w", 0, gui.EASING_OUTSINE, 0.3, 0, nil, gui.PLAYBACK_ONCE_BACKWARD) +end + + +local function remove_element(self) + if #self.grid.nodes > 0 then + local root = self.grid:remove(#self.grid.nodes) + -- We should instant remove element from the grid, but node itself delete after the animation + gui.animate(root, "color.w", 0, gui.EASING_OUTSINE, 0.2, 0, function() + gui.delete_node(root) + end) + end +end + + +function init(self) + self.druid = druid.new(self) + self.grid = self.druid:new_grid("grid", "prefab", 5) + + self.prefab = gui.get_node("prefab") + gui.set_enabled(self.prefab, false) + + self.druid:new_button("button_add/button", add_element) + self.druid:new_button("button_remove/button", remove_element) +end + + +function final(self) + self.druid:final() +end + + +function update(self, dt) + self.druid:update(dt) +end + + +function on_message(self, message_id, message, sender) + self.druid:on_message(message_id, message, sender) +end + + +function on_input(self, action_id, action) + return self.druid:on_input(action_id, action) +end From ffa3bafa002c561f6f4a31e8bbca228c3606b1cc Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 30 May 2021 11:50:37 +0300 Subject: [PATCH 5/6] Add deep linking for exampes in html --- .luacheckrc | 1 + example/example.gui_script | 20 +++++++++++++++++++ .../grid_animations.gui_script | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.luacheckrc b/.luacheckrc index a99ebbd..82ec63c 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -48,4 +48,5 @@ globals = { "buffer", "resource", "defos", + "html5", } diff --git a/example/example.gui_script b/example/example.gui_script index 25a65fd..0c56e51 100644 --- a/example/example.gui_script +++ b/example/example.gui_script @@ -17,6 +17,8 @@ end local function show_scene(self, scene_name, text_header) + print("Show scene:", scene_name) + monarch.show(scene_name) gui.set_enabled(gui.get_node("C_Anchor"), false) gui.set_enabled(self.button_menu.node, true) @@ -60,6 +62,9 @@ local function get_button(self, text, scene_name) local nodes = gui.clone_tree(prefab) local root = nodes["prefab_button"] gui.set_enabled(root, true) + + self.scene_names[scene_name] = text + self.druid:new_button(root, function() show_scene(self, scene_name, text) end):set_click_zone(self.lobby_scroll.view_node) @@ -84,6 +89,7 @@ end local function init_lobby(self) gui.set_enabled(gui.get_node("prefabs"), false) + self.scene_names = {} self.lobby_scroll = self.druid:new_scroll("lobby_view", "lobby_content") self.lobby_grid = self.druid:new_dynamic_grid("lobby_content") @@ -130,6 +136,18 @@ local function init_lobby(self) end +local function check_url(self) + if not html5 then + return + end + local example_arg = html5.run("new URLSearchParams(window.location.search).get('example')") + if example_arg and self.scene_names[example_arg] then + print("Start example: ", example_arg) + show_scene(self, example_arg, self.scene_names[example_arg] or "unknown") + end +end + + function init(self) -- Main lobby have more render priority (top panel) gui.set_render_order(10) @@ -140,6 +158,8 @@ function init(self) init_top_panel(self) init_lobby(self) + + timer.delay(0, false, check_url) end diff --git a/example/examples/grid/grid_animations/grid_animations.gui_script b/example/examples/grid/grid_animations/grid_animations.gui_script index 2a2ea12..a1b6e38 100644 --- a/example/examples/grid/grid_animations/grid_animations.gui_script +++ b/example/examples/grid/grid_animations/grid_animations.gui_script @@ -35,7 +35,7 @@ end function init(self) self.druid = druid.new(self) - self.grid = self.druid:new_grid("grid", "prefab", 5) + self.grid = self.druid:new_static_grid("grid", "prefab", 5) self.prefab = gui.get_node("prefab") gui.set_enabled(self.prefab, false) From 305c300f31ffba8d768e34ea2047be164cc5d4e1 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 30 May 2021 11:52:56 +0300 Subject: [PATCH 6/6] Update example --- docs/druid/archive/archive_files.json | 2 +- docs/druid/archive/game.arcd0 | Bin 384566 -> 388522 bytes docs/druid/archive/game.arci0 | Bin 10608 -> 11568 bytes docs/druid/archive/game.dmanifest0 | Bin 23386 -> 25565 bytes docs/druid/archive/game.projectc0 | 8 ++++---- docs/druid/archive/game.public.der0 | Bin 162 -> 162 bytes docs/druid/index.html | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/druid/archive/archive_files.json b/docs/druid/archive/archive_files.json index f4a864f..7e82320 100644 --- a/docs/druid/archive/archive_files.json +++ b/docs/druid/archive/archive_files.json @@ -1 +1 @@ -{"content":[{"name":"game.projectc","size":3432,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":10608,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":384566,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":23386,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]} \ No newline at end of file +{"content":[{"name":"game.projectc","size":3432,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":11568,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":388522,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":25565,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]} \ No newline at end of file diff --git a/docs/druid/archive/game.arcd0 b/docs/druid/archive/game.arcd0 index 71e577029948a5e8cd61c4bc29f8148a25b9ff26..0752c11d5500c95742282806fe925da0a28c52cc 100644 GIT binary patch delta 5081 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 z z^=QP{U#lG@p!v7+moG5%f7@5*Q)fX zf*sB37g#KVFwL&ZKGCu+p?GHav5usoOZ$uBKZQygS@B^>Wo6RKe(;Q`$x)@*D=N8P z=pOnU9OaX`*J^3aW42FB^ilF6A)A>6BuEPU+UcpQZqju<_ywA(c0< zbtkagP3*3^e*P5KP%3jzs#kLH9YV{ss(_;Nn||SI_wcp0C$%b`9p7^0e6Ot{o*!JK z#O~tLB7MCSk<#g4B-dkt%{6oLd^6a+K@}-vb=-MgKzLa$J{6%#2|y)Ln4+@ce*k3( B+~xoP delta 2182 zcmV;12zmFa+ZVRH7qI;#vlTJza+5NYE3;XqDGCMG(i5{plUqun@;RJ8B0(c5KxdHV{GoS-K#JPY^JH4J=GRS+??0~H` z!pWwaZ~_`Tzd$PUP)ANl*o6to{rnX5W)etjE}_7IWpF86=A%Czh56EbR3n$?+D&Ki zvQJzL)TtTHKC{YAr1B~0e}4qW4+;^E??%fb(te;AJ`+x6b?>&cK zB|h`g^Rs*>2=K%ZmT9hh%LrVT~-yh^Rkxb@aS`Y>^A6!HGeP}SRB3Q(55`J zfK(EJwhz)Ci}h>9EYBBu-%u@`Ew!H_&hK)toF)SVv%6zg<=`l=CAdV~0sq|Bn$eCr zncw8|yK`r3@@k=^op4dfSp8aOH&}jn+1C{!Ke?f zx)%RQB8SU^%&l^Q>Pc8Uz=LPnc=$1Y)QQV`v}K^+p(`+&V2s~!=0~GdE^WcLoP5q& zNM+e_^4<&w0)?0YQE{!gm{^iyDuSw0{5yvXYRk0bXa6Ccc%wHdxmz z!J~CWx=BpNiuo1Fs9kCtP13vpC=4DHs+PbO;z1GNF^!z5gc{A`8%XRyvn~k0{@y)t zP9W%f#6mk!Xh-yc__C)kslXPcD@ms}R;v;$ z7+(;ziw~Z6x%zFo38vY;Wrs3H z9*pc`H<_sF_y*;X;!1UYi=4wAg+1Ak`*5QgUun~$fAxA3yDsM-?KQ?g>qT?$Xl;|T zpV7b{LX=f}w@-XAkCI7GOP_x&yZdx&%~r1Q`MW(zjnR1ug@BS2^KlkG2uQ=jqN8;kM0@ z&e8e9DUrK)^O%D*W&z{Yix5LIWB#r7g+rNh}#aUm@7*W zLd**9iR1W70CdMY&7GGJ(O5~Z8LdmK$e0Vd0tilBZU+duVF81w;3?RS1 zIDe93b!}a4riv^Nv_RY7E;n zu71-oJP|ZEY68cGrYwycD;a$==8p-BsV%at%Wy7;(fm_4Wgth=#UGk>*&qNm zK```x%UdyBV95Nnc&o-K;f89Jr|)<*%c($9HSkR%2-VSZ&8BD;PIaqis{ z{~>Umod)pmet)yiQWnCqcvhes(K|8i%Uf+6S1$OE*pY?9nnMKS3V)rMT$qg~8pAN0 z?l9KN+OQU_g`}VsvdZw!$;BM{bQt-?^g48Zpu)w-UeirRx`A)8qVmJB(I_!T@rU?9 zFXMZ>Npy&}kT>C5=WNwMnN;M=<`CaQLPWH{8uu{~x;&IMXjz~OrheS~ELMg~wVY5; z7vd>2zcOZh(W#HeR;*Q?SH|lnJ*X+lkP-rAqO1TF_6lhq0fNUxk<8ZT5L7NrVgszV I2sZ_yw*9y{I{*Lx diff --git a/docs/druid/archive/game.arci0 b/docs/druid/archive/game.arci0 index a01080154a3727ea4d3d5403fcf6e635469f200a..1d3e5e0e8d4feaa5cb9e073b43254f4be03e28df 100644 GIT binary patch delta 2863 zcmYk74N#U<7RS%~@$kO#k&ur{VevZBD5dp+6uPKOX$eMV3VxD-DP|$Py6Yy1^5T}V zX^NvxN`9bVfs!#J1!hiP)5HWimSLu0lDlO_#_ZOvtf~7u&jT%I=6~<~-*fK0=bU@) z^K?$Fo9!17H|Q;8B5^veFwgDu?t63W-Zf30OJ_RnE%0m#1kLatr=0VifA7kZYyXnA z^pD0@uYOy;aC6jP-=>`KO`Z4m%Sr!l+^QAlV@HG?jQ5W(__6JHT(|a+-;wGvhg^NL z|KWv+wJ`;&+t)1Z_-pcwMQ`*N1l;dC%;C@9h`1Ub@yY6aMZ@cYlk&2IM=y69RQf|4 zX3{aE^U?Rd%|CQ(f9{1z2fe2@whidn!0$TN6`K|I+$B?dv&pvRuHEHL|j~n$p`cCu{k8Cr>f5v4AC_uPAM;V%*9)eFRrxY9WAdi1 zX!bul^!N2)sZR5mV=KSOzIjPmV%iB`;lde-=FlHXdJH-vf}v*hr-?tL6ty+P)$K{I zX)ixAZvQWR>TRyrX(nw?U;p#%UgZ@Taad*Mcw3 zk34r~dEJhqHGvt;zw2*vn%~8LTylB(_2-WMbTv99e{@9p?9j%Z1N^ZLXR++f;r>%V zB0wtZX`TcRD-)?o5^AJUMx~wO+OiO5g;4$MMA%}58(ir<6{y#$pgq79FQkKhB7hw*U{pT zGyv@P==^Aq0MI}1i%1x7eFa0m?l<~n;4z^4?ij`VgA6!S#i$io4{kXHVS&Gj{#6hF zNJ$ILBJhYZF*346JPe#WXvoNM9E@s2LFRP*k_z}99QYN^bXC4cCi~xfLC)L774iw ze-6(68jm~#Mq2TUy!I6HQ<>;c4cXZy;@ytNF%TB4oFEcGJ-AJqS8FCTV`NTc7mhfv zk+T++`1AA|z%v#%$_XI;8rOOooPbZhOCPT_qWMSeBz1kfczDI;X*eLO!9ttAgDz&6 zNHl3vxg!mG4shx{BeiZC<|J7eH4x++jj&Cb7=9nN9Pa4O=z%6?)xMZCtIQ!~v2T#3 z{Wc$`T`owsxRH`6GLS3sRKUqd<9x<58CF?(NhiYLUosbB^ATGZQ)I3P+kQP6>T`d0 zMsaAy`yxX>Y%;=JA+2+1jf@qDnO>Y38)|Y=^C~ffa3#K@)V@qnG%qt zDqdU}O(oE(#kQoDlzu`HJ`Tg-6@!SVfb}n1Tzohf@)8GX&9Glh6WwIS7XjkLK~E!k z9MSdn{ld6-AmbWqLZ)Pr0X{75f7yHy#!>_p0Hlx<-W1Lvbrh*3@+e-2TO-H8$yfN1 zl97-Um_yvx(C6`rqV=ibP{~aCEkHT;ANsiexVwo$iwuLEY}ETh^ks*5Wf;{?)QIsZ z4j2YDc&_%z@6ziF$^*#jrA+H*`yUpS-8t}Hui!{3&Sc}Dz6#cl3a~ngNf%jAsYs>i zRWw`tWTYN_yK2QaRVC7TfT%~w3=UF*&vGrhExnQ3Lcups zWL*}QZ6=4`#UA=~W&Qp-`mq2fRGu#OX$vv{68i$pUa&zKDT<@%<@$(MbE*|% zD_7E&C+0p6qo`Ka@@i&r;B|}3zBH!wdM^NEhnFT9*w4}^z7!47sK)`MBEW(P4D3&- zF{*;i|IXYu%n`waAfM4b%=NeVVh;3hfNPA+vp7&n!6JZz4O6(n7W6;ESYH?98Lnjw zd%}yQri{UOpk5)Bf2JAt|Nr;r^+Ys-okm$|NxI0mgXeS-PQ;6wL@iw7_rFgwpwZh!B>@hQbwIBL8J8h4#7&VUS=7j)_prvP yHbj(#gVv{7-#Ys)Ct_~}`eqpV&GYGB0e=GMPqM#@d53=ZqQEX6jTVIE!2bZGh5bwb delta 2334 zcmYk7dr;I>6vxkRcYn)@plFzg8IqVdP%b_(QP=VTg;GYP4lfH03tuE;rR`cel3Iw1 zA_5bMGv=dWT4#KWlTa4U!ENuZSE@+SQ)lQP;TTQ(t^h@zII_ zYqNv>k`k+ndRKb`)!}KOmBv(ODC}xAn!|1*u0vbpADXv)f`yfdd&S%Rj{I&EuW;PJrLC?ROP3pTqo`+WSS`%oT~eXggJh zIUajm7OMfAfKmvum5J%j;Fkl)VSxSiv5XTz8bCiLAkzB={(gX=_miNMgC_v8btua- zm=IIri+NCF3mEi0gbn3~7?*(A0Cff@jbP$v;Kva2M65`^BPcX5_KPav?-B4XILkFR zMRM`i|7S~YrbJ=(D)TcIm#0gJMG_I?H9iiOx=@sX#{p6o!_Q=(0dRP(2;(*m@QBS9 zQ$qK3_{(ti?@VHt%e>Rl%aVYIr;Y;+w)HDhMWSh+i-W8EF1Tm~(yjbOwxzQ^orMd4 zfSb;VjQp3j41tmH$xOzP-963-z~2DR17v@V$lzp=xPvxtY-Q9v6KuYnjE$MhFIn6i zik$=B#(1qiCu&^Js2jAmNX~JQgb&Dazs=LGF)jpI7B^EaiwvZs5lwLRPo`3-XW?#3 zF98zjHLa@xB$SygGU96zinQ&AlWf0S^!~T(4M8nU_a%~2?ezx0$r1AtJwSH_%r9t> zV;-^Zwe+&}Hsd%j%H{<)_wYiTQ*6Eu|L#|?*M#wRzC$D`ME{-IHx?%3iNtU^b2E&L zlGI@V(5fJ{dH}tU8Op@`{40K+1U`Udb&}Ct1k^p~-8ZPvT3$jN41X%7*>#8D8(Ude zr~Q9QRU%cZ`Dq4vsjw}hgc0prntT{{;KldJXc-RPwzv${j5ZNa?*I<#X<_%f#*Pw4 z96?`V?;jChJ`kIIw*7Pxi7F(%>rZ6z|bKNhrOlYIZq6|%^nAxKim)Y3_FJkXeI6dzl#hqJD8{W0~TrwDSm`iob z;zv1^Kc+^}t;j>N{8D@>D{*%j(d z_0sc`1*Wa_}R-D|A+(vFeIQC7}2-&7+O)!v2-- zefwL&I>(aNGm2{mNZdNCx^#k|(Zx4<#4=6*n6Yi=(Hp7ms~JyEpE}cl=lc?VrOAP6(wlE_1u*L1ayZZH zfO{Md_Www3FY_p}XT3T5(X8~z8EP_1ut;u`5X=#nlh6b;+n1;RYCKsruhzKQk z{!*!{eju;Qy-w4>Iq&t|b1IWRdiZQUB?vSQIh2tD**VF4>#VDc%0IntJH5MVGPgID zb<1W04IQS*stO{T)kJw1b+E+)$k$;uhgI&R26Hb_@ClJl3#vYCkgq;D(c5Eknb_jV zv8oD;rjr#F73vpXeck_b#_AoCpu~hLWO0QNu28_`9Za_}0TYdwcnS;l@Nv+R*t|@- zhKpqmBbVF6MB)0P%oP1}AQ7LKmzkSbl9``ZjLwfwPt8j$N-RlDi8laem;DotEW7$_ z^5STa53$7$D73HzG-fEWL4#3VEfs63+Pu)+h7qe*Hh=Wk&9r&3mMAlGC6_hOD;Y$1 zMK8THGg;utt_i=^uQ@y?2jqU@+zD}}2BTC3m(^qiWtqtVfl`}4>KCdP|01I?bi(NfYG?D*?X+78dS z^EdN0(DjEW$EnJ1zGd*5k!2+#mle?AP{UQTx@JH4wBY0Y1yjN1(k^|z zY@9sbT5)oRqsZj%MwQHo$gYr_%+JE3`Rm?<311qPG)@P*1T%$$eX@}e9PY%VU%lk~ zoSf8TP})uw__J-4^6OQz2pi#`U zIl^3(n`J5^mmMN1Bqp{92JPzo^Xt)y14|Eqok@AA01Wjir+g^|k^QgYY{Ztn28%ZAmr!1~Z+^4j18>_whp z$a1#&B@A%}mshXI$Zj;B{{G$nTQB~6IqZMi$;+*Bg}Hk*N6pD6GwMEVO<3AIpX&rm zu;FS}R^wWO|I=^XFw-+-)IhL-sUDS4h{nf2E Hrg`iDaiR@k delta 674 zcmcb6oblE+MrN*qTPHH>irlhX{4Orro7X6G|NE&45);v-&wnR9y% zIY=d>>?{+l^_jdez-P0MFi?fFtjOjKA|}j}RfAn7M@TH*d_Xdh1-qUzaT1$-Q#L31+c07^V)Mp;-AtQb>WVTmS8!QPUSJ?I*)BqI^G3s?jGG@A zvocOD@>1AbY5JORGK-VkWIc=C$;oc=n?G7QF^XdIh0-(6zdoxkK-= zVKrg$pXe!Ay$lR#nau}cy4mXOp4c5;!JDxCPv5h5hYm>}OXZrkgLT?RL6M>lhv!;x zKXUsr<%m=M*@@;3%S+m4oLs+pN7?T$TfEyQrg6r+vN2APKEby!-W1{>}|oZob=AmEO5>+a+7cZHp(}E19mcsA2x+%G3?Q Y_oM_Q@+z#RF7Ce_QS$NmUA2b{0L!W=!rq?; - druid 0.6.459 + druid 0.6.466