diff --git a/assets/Data/entity/items.json b/assets/Data/entity/items.json index 85ae59ea..6a7fa830 100644 --- a/assets/Data/entity/items.json +++ b/assets/Data/entity/items.json @@ -373,7 +373,8 @@ "path" : "Models/basic/geometry/unitcapsule.glb" } }, - "clientSidePrimary": "OPEN_SPAWN_PALETTE", + "clientSidePrimary": "LEVEL_EDIT_SPAWN", + "clientSideSecondary": "OPEN_SPAWN_SELECT", "collidable": { "type" : "CUBE", "dimension1" : 0.1, diff --git a/assets/Scripts/client/clienthooks.ts b/assets/Scripts/client/clienthooks.ts index 9f29ee61..76fcc6dd 100644 --- a/assets/Scripts/client/clienthooks.ts +++ b/assets/Scripts/client/clienthooks.ts @@ -16,5 +16,17 @@ export const clientHooks: Hook[] = [ callback: (engine: Engine) => { engine.classes.voxelUtils.static.applyEdit() } + }, + { + signal: "OPEN_SPAWN_SELECT", + callback: (engine: Engine) => { + engine.classes.menuUtils.static.openSpawnSelection() + } + }, + { + signal: "LEVEL_EDIT_SPAWN", + callback: (engine: Engine) => { + engine.classes.levelEditorUtils.static.spawnEntity() + } } ] \ No newline at end of file diff --git a/assets/Scripts/types/host/client/client-level-editor-utils.ts b/assets/Scripts/types/host/client/client-level-editor-utils.ts new file mode 100644 index 00000000..5aaa9923 --- /dev/null +++ b/assets/Scripts/types/host/client/client-level-editor-utils.ts @@ -0,0 +1,11 @@ +/** + * Utilities for editing levels + */ +export interface ClientLevelEditorUtils { + + /** + * Spawns the selected entity + */ + readonly spawnEntity: () => void + +} \ No newline at end of file diff --git a/assets/Scripts/types/host/renderer/ui/menus.ts b/assets/Scripts/types/host/renderer/ui/menus.ts index e19d27cc..bd5c8a91 100644 --- a/assets/Scripts/types/host/renderer/ui/menus.ts +++ b/assets/Scripts/types/host/renderer/ui/menus.ts @@ -8,4 +8,9 @@ export interface MenuUtils { */ readonly openVoxel: () => void + /** + * Opens the menu to select what to spawn + */ + readonly openSpawnSelection: () => void + } \ No newline at end of file diff --git a/assets/Scripts/types/host/static-classes.ts b/assets/Scripts/types/host/static-classes.ts index e7ad3098..0b927875 100644 --- a/assets/Scripts/types/host/static-classes.ts +++ b/assets/Scripts/types/host/static-classes.ts @@ -1,3 +1,4 @@ +import { ClientLevelEditorUtils } from "/Scripts/types/host/client/client-level-editor-utils"; import { ClientVoxelUtils } from "/Scripts/types/host/client/client-voxel-utils"; import { Entity } from "/Scripts/types/host/entity/entity"; import { MenuUtils } from "/Scripts/types/host/renderer/ui/menus"; @@ -40,6 +41,11 @@ export interface StaticClasses { */ readonly voxelUtils?: Class, + /** + * Utilities for level editing + */ + readonly levelEditorUtils?: Class, + } /** diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 8615b3ff..a420f4c2 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -860,7 +860,7 @@ Toolbar scrolling Items executing script engine hooks on usage Fix server attack tree regressions Editing voxels hook and extensions for voxel palette item - +Entity spawning palette item actually working via hooks # TODO diff --git a/src/main/java/electrosphere/client/ui/menu/WindowStrings.java b/src/main/java/electrosphere/client/ui/menu/WindowStrings.java index c2b0d568..7cac4c25 100644 --- a/src/main/java/electrosphere/client/ui/menu/WindowStrings.java +++ b/src/main/java/electrosphere/client/ui/menu/WindowStrings.java @@ -35,6 +35,9 @@ public class WindowStrings { //the voxel type selection menu public static final String VOXEL_TYPE_SELECTION = "voxelTypeSelection"; + //the voxel type selection menu + public static final String SPAWN_TYPE_SELECTION = "spawnTypeSelection"; + //the tutorial popup public static final String TUTORIAL_POPUP = "tutorialPopup"; diff --git a/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsLevelEditor.java b/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsLevelEditor.java index ea34aa51..61f1c4ce 100644 --- a/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsLevelEditor.java +++ b/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsLevelEditor.java @@ -288,9 +288,9 @@ public class MenuGeneratorsLevelEditor { fillInDefaultContent(scrollable); })); - //button for spawning all foliage types + //button for spawning all object types for(CommonEntityType object : Globals.gameConfigCurrent.getObjectTypeMap().getTypes()){ - //spawn foliage button + //spawn object button scrollable.addChild(Button.createButton("Spawn " + object.getId(), () -> { LoggerInterface.loggerEngine.INFO("spawn " + object.getId() + "!"); Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); diff --git a/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsTerrainEditing.java b/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsTerrainEditing.java index 482f2f5f..914c4999 100644 --- a/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsTerrainEditing.java +++ b/src/main/java/electrosphere/client/ui/menu/ingame/MenuGeneratorsTerrainEditing.java @@ -8,8 +8,10 @@ import electrosphere.client.ui.menu.WindowUtils; import electrosphere.controls.ControlHandler.ControlsState; import electrosphere.engine.Globals; import electrosphere.engine.signal.Signal.SignalType; +import electrosphere.game.data.common.CommonEntityType; import electrosphere.game.data.voxel.VoxelData; import electrosphere.game.data.voxel.VoxelType; +import electrosphere.renderer.ui.components.SpawnSelectionPanel; import electrosphere.renderer.ui.elements.Button; import electrosphere.renderer.ui.elements.Div; import electrosphere.renderer.ui.elements.ImagePanel; @@ -33,6 +35,7 @@ import electrosphere.renderer.ui.events.NavigationEvent; public class MenuGeneratorsTerrainEditing { static Window terrainEditingSidePanelWindow; + static Window entitySelectionWindow; //text input static final int TEXT_INPUT_HEIGHT = 50; @@ -190,4 +193,37 @@ public class MenuGeneratorsTerrainEditing { } } + /** + * Creates the entity type selection window + * @return + */ + public static Window createEntityTypeSelectionPanel(){ + //setup window + entitySelectionWindow = Window.create(Globals.renderingEngine.getOpenGLState(), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, true); + entitySelectionWindow.setParentAlignContent(YogaAlignment.Center); + entitySelectionWindow.setParentJustifyContent(YogaJustification.Center); + entitySelectionWindow.setParentAlignItem(YogaAlignment.Center); + entitySelectionWindow.setAlignContent(YogaAlignment.Center); + entitySelectionWindow.setAlignItems(YogaAlignment.Center); + entitySelectionWindow.setJustifyContent(YogaJustification.Center); + entitySelectionWindow.setFlexDirection(YogaFlexDirection.Column); + + //nav logic + entitySelectionWindow.setOnNavigationCallback(new NavigationEventCallback() {public boolean execute(NavigationEvent event){ + WindowUtils.closeWindow(WindowStrings.SPAWN_TYPE_SELECTION); + Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME); + MenuGeneratorsLevelEditor.voxelWindowOpen = false; + return false; + }}); + + //attach scrollable after search input for organzation purposes + entitySelectionWindow.addChild(SpawnSelectionPanel.createEntityTypeSelectionPanel((CommonEntityType type) -> { + Globals.selectedSpawntype = type; + })); + + Globals.signalSystem.post(SignalType.YOGA_APPLY,entitySelectionWindow); + + return entitySelectionWindow; + } + } diff --git a/src/main/java/electrosphere/client/ui/menu/mainmenu/MenuGeneratorsUITesting.java b/src/main/java/electrosphere/client/ui/menu/mainmenu/MenuGeneratorsUITesting.java index 702696cc..3a3884e3 100644 --- a/src/main/java/electrosphere/client/ui/menu/mainmenu/MenuGeneratorsUITesting.java +++ b/src/main/java/electrosphere/client/ui/menu/mainmenu/MenuGeneratorsUITesting.java @@ -16,6 +16,7 @@ import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.state.inventory.InventoryUtils; import electrosphere.entity.state.inventory.RelationalInventoryState; import electrosphere.entity.state.inventory.UnrelationalInventoryState; +import electrosphere.game.data.common.CommonEntityType; import electrosphere.game.data.creature.type.equip.EquipPoint; import electrosphere.game.data.voxel.VoxelType; import electrosphere.renderer.actor.ActorUtils; @@ -23,6 +24,7 @@ import electrosphere.renderer.ui.components.CharacterCustomizer; import electrosphere.renderer.ui.components.EquipmentInventoryPanel; import electrosphere.renderer.ui.components.InputMacros; import electrosphere.renderer.ui.components.NaturalInventoryPanel; +import electrosphere.renderer.ui.components.SpawnSelectionPanel; import electrosphere.renderer.ui.elements.ActorPanel; import electrosphere.renderer.ui.elements.Button; import electrosphere.renderer.ui.elements.FormElement; @@ -60,6 +62,7 @@ public class MenuGeneratorsUITesting { "NaturalInventoryPanel", "EquipInventoryPanel", "VoxelPicker", + "EntitySpawnPicker", }), (ValueChangeEvent event) -> { attachComponent(rVal,event.getAsString()); @@ -140,6 +143,12 @@ public class MenuGeneratorsUITesting { } break; case "VoxelPicker": { formEl.addChild(MenuGeneratorsTerrainEditing.createVoxelTypeSelectionPanel((VoxelType voxelType) -> { + System.out.println(voxelType.getName()); + })); + } break; + case "EntitySpawnPicker": { + formEl.addChild(SpawnSelectionPanel.createEntityTypeSelectionPanel((CommonEntityType entType) -> { + System.out.println(entType.getId()); })); } break; } diff --git a/src/main/java/electrosphere/client/ui/menu/script/ScriptLevelEditorUtils.java b/src/main/java/electrosphere/client/ui/menu/script/ScriptLevelEditorUtils.java new file mode 100644 index 00000000..eaf74a7c --- /dev/null +++ b/src/main/java/electrosphere/client/ui/menu/script/ScriptLevelEditorUtils.java @@ -0,0 +1,69 @@ +package electrosphere.client.ui.menu.script; + +import java.util.Random; + +import org.graalvm.polyglot.HostAccess.Export; +import org.joml.Vector3d; + +import electrosphere.client.entity.camera.CameraEntityUtils; +import electrosphere.collision.CollisionEngine; +import electrosphere.engine.Globals; +import electrosphere.entity.types.common.CommonEntityUtils; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.types.foliage.FoliageUtils; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.game.data.creature.type.CreatureData; +import electrosphere.game.data.foliage.type.FoliageType; +import electrosphere.game.data.item.type.Item; +import electrosphere.logger.LoggerInterface; +import electrosphere.server.datacell.Realm; + +/** + * Utilities for editing levels + */ +public class ScriptLevelEditorUtils { + + //vertical offset from cursor position to spawn things at + static final Vector3d cursorVerticalOffset = new Vector3d(0,0.05,0); + + /** + * Spawns the selected entity + */ + @Export + public static void spawnEntity(){ + if(Globals.selectedSpawntype instanceof CreatureData){ + LoggerInterface.loggerEngine.INFO("spawn " + Globals.selectedSpawntype.getId() + "!"); + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); + Realm realm = Globals.realmManager.getRealms().iterator().next(); + CollisionEngine clientCollisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); //using client collision engine so ray doesn't collide with player entity + Vector3d cursorPos = clientCollisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset); + CreatureUtils.serverSpawnBasicCreature(realm, cursorPos, Globals.selectedSpawntype.getId(), null); + } else if(Globals.selectedSpawntype instanceof Item){ + LoggerInterface.loggerEngine.INFO("spawn " + Globals.selectedSpawntype.getId() + "!"); + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); + Realm realm = Globals.realmManager.getRealms().iterator().next(); + CollisionEngine clientCollisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); //using client collision engine so ray doesn't collide with player entity + Vector3d cursorPos = clientCollisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset); + ItemUtils.serverSpawnBasicItem(realm, cursorPos, Globals.selectedSpawntype.getId()); + } else if(Globals.selectedSpawntype instanceof FoliageType){ + LoggerInterface.loggerEngine.INFO("spawn " + Globals.selectedSpawntype.getId() + "!"); + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); + Realm realm = Globals.realmManager.getRealms().iterator().next(); + CollisionEngine clientCollisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); //using client collision engine so ray doesn't collide with player entity + Vector3d cursorPos = clientCollisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset); + FoliageUtils.serverSpawnTreeFoliage(realm, cursorPos, Globals.selectedSpawntype.getId(), new Random().nextLong()); + } else { + LoggerInterface.loggerEngine.INFO("spawn " + Globals.selectedSpawntype.getId() + "!"); + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); + Realm realm = Globals.realmManager.getRealms().iterator().next(); + CollisionEngine clientCollisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); //using client collision engine so ray doesn't collide with player entity + Vector3d cursorPos = clientCollisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset); + CommonEntityUtils.serverSpawnBasicObject(realm, cursorPos, Globals.selectedSpawntype.getId()); + } + } + +} diff --git a/src/main/java/electrosphere/client/ui/menu/script/ScriptMenuUtils.java b/src/main/java/electrosphere/client/ui/menu/script/ScriptMenuUtils.java index be80eb24..dea17a61 100644 --- a/src/main/java/electrosphere/client/ui/menu/script/ScriptMenuUtils.java +++ b/src/main/java/electrosphere/client/ui/menu/script/ScriptMenuUtils.java @@ -22,4 +22,13 @@ public class ScriptMenuUtils { Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU); } + /** + * Opens the menu to select what to spawn + */ + @Export + public static void openSpawnSelection(){ + WindowUtils.replaceWindow(WindowStrings.SPAWN_TYPE_SELECTION,MenuGeneratorsTerrainEditing.createEntityTypeSelectionPanel()); + Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU); + } + } diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 1d78d354..604d987e 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -258,6 +258,7 @@ public class ControlHandler { static String[] controlBlockingWindows = new String[]{ WindowStrings.LEVEL_EDTIOR_SIDE_PANEL, WindowStrings.VOXEL_TYPE_SELECTION, + WindowStrings.SPAWN_TYPE_SELECTION, WindowStrings.WINDOW_CHARACTER, WindowStrings.WINDOW_DEBUG, WindowStrings.WINDOW_MENU_INGAME_MAIN, diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index 0316f900..c3cea466 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -43,6 +43,7 @@ import electrosphere.engine.time.Timekeeper; import electrosphere.entity.Entity; import electrosphere.entity.scene.Scene; import electrosphere.game.config.UserSettings; +import electrosphere.game.data.common.CommonEntityType; import electrosphere.game.data.particle.ParticleDefinition; import electrosphere.game.data.voxel.VoxelType; import electrosphere.game.server.structure.virtual.StructureManager; @@ -389,6 +390,8 @@ public class Globals { //client current selected voxel type public static VoxelType clientSelectedVoxelType = null; + //the selected type of entity to spawn + public static CommonEntityType selectedSpawntype = null; //skybox entity public static Entity skybox; diff --git a/src/main/java/electrosphere/renderer/ui/components/SpawnSelectionPanel.java b/src/main/java/electrosphere/renderer/ui/components/SpawnSelectionPanel.java new file mode 100644 index 00000000..6ef605ba --- /dev/null +++ b/src/main/java/electrosphere/renderer/ui/components/SpawnSelectionPanel.java @@ -0,0 +1,120 @@ +package electrosphere.renderer.ui.components; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.Consumer; + +import electrosphere.engine.Globals; +import electrosphere.game.data.common.CommonEntityType; +import electrosphere.renderer.ui.elements.Button; +import electrosphere.renderer.ui.elements.Div; +import electrosphere.renderer.ui.elements.Label; +import electrosphere.renderer.ui.elements.TextInput; +import electrosphere.renderer.ui.elements.VirtualScrollable; +import electrosphere.renderer.ui.elementtypes.ClickableElement.ClickEventCallback; +import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaAlignment; +import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaFlexDirection; +import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaJustification; +import electrosphere.renderer.ui.elementtypes.KeyEventElement.KeyboardEventCallback; +import electrosphere.renderer.ui.events.ClickEvent; +import electrosphere.renderer.ui.events.KeyboardEvent; + +/** + * A panel for selecting an entity to spawn + */ +public class SpawnSelectionPanel { + + //text input + static final int TEXT_INPUT_HEIGHT = 50; + static final int TEXT_INPUT_WIDTH = 200; + + //type selection + static final int SELECTION_SCROLLABLE_WIDTH = 500; + static final int SELECTION_SCROLLABLE_HEIGHT = 500; + + //single listing + static final int MARGIN_EACH_SIDE = 5; + + /** + * Creates the spawning menu selection panel + * @return + */ + public static Div createEntityTypeSelectionPanel(Consumer onSelectType){ + //setup window + Div rVal = Div.createDiv(); + rVal.setAlignContent(YogaAlignment.Center); + rVal.setAlignItems(YogaAlignment.Center); + rVal.setJustifyContent(YogaJustification.Center); + rVal.setFlexDirection(YogaFlexDirection.Column); + + //scrollable that contains all the voxel types + VirtualScrollable scrollable = new VirtualScrollable(SELECTION_SCROLLABLE_WIDTH, SELECTION_SCROLLABLE_HEIGHT); + scrollable.setFlexDirection(YogaFlexDirection.Column); + scrollable.setAlignItems(YogaAlignment.Start); + + //search input + TextInput searchInput = TextInput.createTextInput(); + searchInput.setWidth(TEXT_INPUT_WIDTH); + searchInput.setMinWidth(TEXT_INPUT_WIDTH); + searchInput.setMinHeight(20); + searchInput.setOnPress(new KeyboardEventCallback() {public boolean execute(KeyboardEvent event){ + boolean rVal = searchInput.defaultKeyHandling(event); + fillInEntitySelectors(scrollable, searchInput.getText(), onSelectType); + return rVal; + }}); + rVal.addChild(searchInput); + + + //attach scrollable after search input for organzation purposes + rVal.addChild(scrollable); + + //final step + fillInEntitySelectors(scrollable, searchInput.getText(), onSelectType); + + return rVal; + } + + /** + * Fills in the types to display based on the contents of the search string + * @param scrollable the scrollable to drop selection buttons in to + * @param searchString the string to search based on + */ + static void fillInEntitySelectors(VirtualScrollable scrollable, String searchString, Consumer onSelectType){ + scrollable.clearChildren(); + + //get relevant types + List types = new LinkedList(); + types.addAll(Globals.gameConfigCurrent.getCreatureTypeLoader().getTypes()); + types.addAll(Globals.gameConfigCurrent.getFoliageMap().getFoliageList()); + types.addAll(Globals.gameConfigCurrent.getItemMap().getItems()); + types.addAll(Globals.gameConfigCurrent.getObjectTypeMap().getTypes()); + types = types.stream().filter((type)->type.getId().toLowerCase().contains(searchString.toLowerCase())).toList(); + + //generate ui elements + for(CommonEntityType type : types){ + Div containerDiv = Div.createDiv(); + containerDiv.setMinWidthPercent(25.0f); + scrollable.addChild(containerDiv); + + Button newButton = new Button(); + newButton.setAlignItems(YogaAlignment.Center); + //margin + newButton.setMarginBottom(MARGIN_EACH_SIDE); + newButton.setMarginLeft(MARGIN_EACH_SIDE); + newButton.setMarginRight(MARGIN_EACH_SIDE); + newButton.setMarginTop(MARGIN_EACH_SIDE); + //label + Label voxelLabel = Label.createLabel(type.getId()); + //button handling + newButton.addChild(voxelLabel); + newButton.setOnClick(new ClickEventCallback() {public boolean execute(ClickEvent event){ + //set voxel type to this type + onSelectType.accept(type); + Globals.selectedSpawntype = type; + return false; + }}); + containerDiv.addChild(newButton); + } + } + +} diff --git a/src/main/java/electrosphere/script/ScriptEngine.java b/src/main/java/electrosphere/script/ScriptEngine.java index ebd784db..f37e207d 100644 --- a/src/main/java/electrosphere/script/ScriptEngine.java +++ b/src/main/java/electrosphere/script/ScriptEngine.java @@ -14,6 +14,7 @@ import org.graalvm.polyglot.Source.Builder; import org.graalvm.polyglot.Value; import electrosphere.client.script.ScriptClientVoxelUtils; +import electrosphere.client.ui.menu.script.ScriptLevelEditorUtils; import electrosphere.client.ui.menu.script.ScriptMenuUtils; import electrosphere.client.ui.menu.tutorial.TutorialMenus; import electrosphere.engine.Globals; @@ -96,6 +97,7 @@ public class ScriptEngine { {"serverUtils",JSServerUtils.class}, {"menuUtils",ScriptMenuUtils.class}, {"voxelUtils",ScriptClientVoxelUtils.class}, + {"levelEditorUtils",ScriptLevelEditorUtils.class}, }; //singletons from the host that are provided to the javascript context