Einlander
-
Posts
778 -
Joined
-
Last visited
Content Type
Blogs
Forums
Store
Gallery
Videos
Posts posted by Einlander
-
-
It doesn't interface with leadwerks at all. It exploits how leadwerks likes to convert fbx files automatically. So my program sits there and waits until you save something. When that happens it automatically converts the file to a fbx file. Leadwerks sees a new updated fbx file and and converts it to a mdl. No actual integration at all.
-
Nope, I included the parts that it needed. You can install it if you want though, It will not use it.
- 2
-
2 minutes ago, Yue said:
There's something strange going on here. When I put a polymesh the force of gravity does not attract it even though it has 2000 mass. If I put another body type, if it's attracted to gravity. Something strange is that it only happens in the rear of the vehicle in the front if it goes downwards, without any problem, gives the impression that automatically the center of gravity is in the front, and I don't know how to change that point of gravity to my needs.
Polymeshes do no move at all. Even with large mass. Use any option, but not polymesh when you want something to move.
- 1
-
Is it a polymesh? Those dont move.
Does it have mass? If not it wont move.
I don't see it's collision shape, so you might want to take a look at that.
- 1
-
I wrote a helper program that will assist in importing 3ds, obj, dae, and dxf files. It uses part of the Autodesk FBX converter. It watches for when you save, change or rename a file in your leadwerks project folder.
- 8
- 1
-
What are you converting?
-
This is a simple script that will let you get the desktops current resolution. It has not been tested in linux.
It creates a hidden window, Maximizes it, and gets the window size. That's it.
It returns a Vec2(). DO NOT USE IF THE PROGRAM IS ALREADY FULLSCREEN. It will cause you some annoyances.
function GetDesktopResolution() --Vec2() -- get current desktop resolution ; Super quick and dirty method, works on windows dont know about linux local launchertestwindow = Window:Create(System.AppName,0,0,1024,768,Window.Tool) launchertestwindow:Maximize() local desktopres = Vec2(launchertestwindow:GetWidth(),launchertestwindow:GetHeight()) launchertestwindow:Release() return desktopres end
- 1
-
Yes, It's in the Window Mode option.
-
@DoomSlayer This is a work around that I created
- 1
-
This is a launcher that starts before your game allowing players to set the game's graphical options. This was created to solve the issue of Leadwerks starting at the highest resolution of the monitor, instead of the current desktop settings. It uses a quick and dirty method to get the desktop resolution. THIS HAS NOT BEEN TESTED ON LINUX!! If this works on linux let me know, or if you made any changes to make it work.
The script is to be loaded with your game and launched before the main window is created. There are some modifications to main.lua but they are very simple.
Here is the script. Save it as Launcher.lua in the same folder as Menu.lua
-- Settings Launcher by Einlander function LauncherMenu() -- It provides it's own context local LauncherMenu = {} local LauncherWindow = Window:Create(((title ~= nil) and title or System.AppName),0,0,400,650,Window.Titlebar + Window.Center) local LauncherContext = Context:Create(LauncherWindow) local LauncherScale = 1 local LauncherBorder = 10 local LauncherMenu = GUI:Create(LauncherContext) local LauncherMenuClosed = false LauncherMenu:SetScale(LauncherScale) LauncherMenu:GetBase():SetScript("Scripts/GUI/Panel.lua") LauncherMenu.tabber = Widget:Tabber(LauncherBorder,LauncherBorder,LauncherMenu:GetBase():GetClientSize().x-(LauncherBorder*2),LauncherMenu:GetBase():GetClientSize().y-(LauncherBorder*2)-28,LauncherMenu:GetBase()) LauncherMenu.tabber:AddItem("Options",true) LauncherMenu.panel = Widget:Panel(0,0,LauncherMenu.tabber:GetClientSize().x,LauncherMenu.tabber:GetClientSize().y,LauncherMenu.tabber) local y=LauncherBorder local sep=40 LauncherMenu.screenreslabel = Widget:Label("Screen Resolution",20,y,200,16,LauncherMenu.panel) y=y+LauncherMenu.screenreslabel:GetSize().y LauncherMenu.screenres = Widget:ChoiceBox(20,y,200,30,LauncherMenu.panel) local count = System:CountGraphicsModes() for n=0,count-1 do local gfx = System:GetGraphicsMode(n) local selected=false LauncherMenu.screenres:AddItem( gfx.x.."x"..gfx.y,selected) end y=y+sep --Antialias LauncherMenu.aalabel = Widget:Label("Antialias",20,y,200,16,LauncherMenu.panel) y=y+LauncherMenu.aalabel:GetSize().y LauncherMenu.antialias = Widget:ChoiceBox(20,y,200,30,LauncherMenu.panel) LauncherMenu.antialias:AddItem("None") LauncherMenu.antialias:AddItem("2x") LauncherMenu.antialias:AddItem("4x") y=y+sep --Texture quality LauncherMenu.texturequalitylabel = Widget:Label("Texture Detail",20,y,200,16,LauncherMenu.panel) y=y+16 LauncherMenu.texturequality = Widget:ChoiceBox(20,y,200,30,LauncherMenu.panel) LauncherMenu.texturequality:AddItem("Low") LauncherMenu.texturequality:AddItem("Medium") LauncherMenu.texturequality:AddItem("High") LauncherMenu.texturequality:AddItem("Very High") y=y+sep --Lighting quality LauncherMenu.lightqualitylabel = Widget:Label("Lighting Quality",20,y,200,16,LauncherMenu.panel) y=y+16 LauncherMenu.lightquality = Widget:ChoiceBox(20,y,200,30,LauncherMenu.panel) LauncherMenu.lightquality:AddItem("Low") LauncherMenu.lightquality:AddItem("Medium") LauncherMenu.lightquality:AddItem("High") y=y+sep --Terrain quality LauncherMenu.terrainqualitylabel = Widget:Label("Terrain Quality",20,y,200,16,LauncherMenu.panel) y=y+16 LauncherMenu.terrainquality = Widget:ChoiceBox(20,y,200,30,LauncherMenu.panel) LauncherMenu.terrainquality:AddItem("Low") LauncherMenu.terrainquality:AddItem("Medium") LauncherMenu.terrainquality:AddItem("High") y=y+sep --Water quality LauncherMenu.waterqualitylabel = Widget:Label("Water Quality",20,y,200,16,LauncherMenu.panel) y=y+16 LauncherMenu.waterquality = Widget:ChoiceBox(20,y,200,30,LauncherMenu.panel) LauncherMenu.waterquality:AddItem("Low") LauncherMenu.waterquality:AddItem("Medium") LauncherMenu.waterquality:AddItem("High") y=y+sep --Anisotropy LauncherMenu.afilterlabel = Widget:Label("Anisotropic Filter",20,y,200,16,LauncherMenu.panel) y=y+16 LauncherMenu.afilter = Widget:ChoiceBox(20,y,200,30,LauncherMenu.panel) LauncherMenu.afilter:AddItem("None") LauncherMenu.afilter:AddItem("2x") LauncherMenu.afilter:AddItem("4x") LauncherMenu.afilter:AddItem("8x") LauncherMenu.afilter:AddItem("16x") LauncherMenu.afilter:AddItem("32x") y=y+sep --Screen Mode LauncherMenu.waterqualitylabel = Widget:Label("Window Mode",20,y,200,16,LauncherMenu.panel) y=y+16 LauncherMenu.windowmode = Widget:ChoiceBox(20,y,200,30,LauncherMenu.panel) LauncherMenu.windowmode:AddItem("Windowed") LauncherMenu.windowmode:AddItem("Borderless") LauncherMenu.windowmode:AddItem("Full Screen") y=y+sep --Create a checkbox LauncherMenu.tfilter = Widget:Button("Trilinear Filter",20,y,200,30,LauncherMenu.panel) LauncherMenu.tfilter:SetString("style","Checkbox") y=y+sep --Create a checkbox LauncherMenu.vsync = Widget:Button("Vertical Sync",20,y,200,30,LauncherMenu.panel) LauncherMenu.vsync:SetString("style","Checkbox") y=y+sep LauncherMenu.closeoptions = Widget:Button("Close",LauncherMenu:GetBase():GetClientSize().x-72-LauncherBorder,LauncherMenu:GetBase():GetClientSize().y-28-5,72,28,LauncherMenu:GetBase()) LauncherMenu.applyoptions = Widget:Button("Apply",LauncherMenu:GetBase():GetClientSize().x-72*2-4-LauncherBorder,LauncherMenu:GetBase():GetClientSize().y-28-5,72,28,LauncherMenu:GetBase()) local function GetDesktopResolution() --Vec2() -- get current desktop resolution ; Super quick and dirty method, works on windows dont know about linux local launchertestwindow = Window:Create(System.AppName,0,0,1024,768,Window.Tool) launchertestwindow:Maximize() local desktopres = Vec2(launchertestwindow:GetWidth(),launchertestwindow:GetHeight()) launchertestwindow:Release() return desktopres end local function splitstring(str,sep) local array = {} local reg = string.format("([^%s]+)",sep) for mem in string.gmatch(str,reg) do table.insert(array, mem) end return array end local function LoadSettings() --Graphics mode -- Are there both screen settings? if (tonumber((System:GetProperty("screenwidth"))) ~= nil) and (tonumber((System:GetProperty("screenheight"))) ~= nil) then --Set the screen res to the saved settings local count = System:CountGraphicsModes() for n=0,count-1 do local gfx = System:GetGraphicsMode(n) local selected=false if tonumber((System:GetProperty("screenwidth"))) == gfx.x and tonumber((System:GetProperty("screenheight"))) ==gfx.y then LauncherMenu.screenres:SelectItem(n) break end end else -- Default System:Print("setting not found") --No setting found, use desktop resolution local desktopres = GetDesktopResolution() local count = System:CountGraphicsModes() for n=0,count-1 do local gfx = System:GetGraphicsMode(n) local selected=false if desktopres.x ==gfx.x and desktopres.y ==gfx.y then LauncherMenu.screenres:SelectItem(n) break end end end -- antialias local num = 0 num = tonumber((System:GetProperty("antialias"))) if num ~= nil then if num > 0 then if num < 5 then LauncherMenu.antialias:SelectItem(num/2) else LauncherMenu.antialias:SetText(num) end else LauncherMenu.antialias:SelectItem(1) end else -- deafult LauncherMenu.antialias:SelectItem(1) end --Texture detail num = tonumber((System:GetProperty("texturedetail"))) if num~=nil then if num >= 0 then if num <= 3 then LauncherMenu.texturequality:SelectItem(3 - num) else LauncherMenu.texturequality:SelectItem(3) end else LauncherMenu.texturequality:SelectItem(0) end else -- default LauncherMenu.texturequality:SelectItem(3) end --Lighting Quality num = tonumber((System:GetProperty("lightquality"))) if num~=nil then if num >= 0 then if num <= 2 then LauncherMenu.lightquality:SelectItem(num) else LauncherMenu.lightquality:SelectItem(2) end else LauncherMenu.lightquality:SelectItem(0) end else -- Default LauncherMenu.lightquality:SelectItem(1) end --Terrain Quality num = tonumber((System:GetProperty("terrainquality"))) if num ~= nil then if num >= 0 then if num <= 3 then LauncherMenu.terrainquality:SelectItem(num/2) end else LauncherMenu.terrainquality:SelectItem(1) end else -- deafult LauncherMenu.terrainquality:SelectItem(1) end --Water Quality num = tonumber((System:GetProperty("waterquality"))) if num ~= nil then if num >= 0 then if num <= 3 then LauncherMenu.waterquality:SelectItem(num) end else LauncherMenu.waterquality:SelectItem(1) end else -- deafult LauncherMenu.waterquality:SelectItem(1) end --Anisotropic Filter num = tonumber((System:GetProperty("anisotropicfilter"))) if num ~= nil then num = num .. "x" if anisotropy=="0x" then anisotropy="None" end for n=0,LauncherMenu.afilter:CountItems()-1 do LauncherMenu.afilter:SetText(num) if num==LauncherMenu.afilter:GetItemText(n) then LauncherMenu.afilter:SelectItem(n) break end end else -- deafult LauncherMenu.afilter:SelectItem(1) end num = tonumber((System:GetProperty("windowmode"))) if num ~= nil then if num >= 0 then if num > 2 then LauncherMenu.windowmode:SelectItem(2) else LauncherMenu.windowmode:SelectItem(num) end else LauncherMenu.windowmode:SelectItem(2) end else -- default LauncherMenu.windowmode:SelectItem(2) end num = tonumber((System:GetProperty("trilinearfilter"))) if num ~= nil then if num > 0 then LauncherMenu.tfilter:SetState(true) end else --Default LauncherMenu.tfilter:SetState(true) end num = tonumber((System:GetProperty("verticalsync"))) if num ~= nil then if num > 0 then LauncherMenu.vsync:SetState(true) end else --Default LauncherMenu.vsync:SetState(true) end end local function ApplySettings() -- Screen Resolution local gfxmode = splitstring(LauncherMenu.screenres:GetItemText(LauncherMenu.screenres:GetSelectedItem()),"x") System:SetProperty("screenwidth",tonumber(gfxmode[1])) System:SetProperty("screenheight",tonumber(gfxmode[2])) -- Anti-aliasing if LauncherMenu.antialias:GetSelectedItem() > -1 then if string.lower(LauncherMenu.antialias:GetItemText(LauncherMenu.antialias:GetSelectedItem())) == "none" then System:SetProperty("antialias",0) else System:SetProperty("antialias",(string.gsub(LauncherMenu.antialias:GetItemText(LauncherMenu.antialias:GetSelectedItem()),"x",""))) end else System:SetProperty("antialias",LauncherMenu.antialias:GetText()) end -- Texture Quality System:SetProperty("texturedetail",LauncherMenu.texturequality:CountItems()-1-LauncherMenu.texturequality:GetSelectedItem()) -- Lighting Quality System:SetProperty("lightquality",LauncherMenu.lightquality:GetSelectedItem()) -- Terrain Quality System:SetProperty("terrainquality",LauncherMenu.terrainquality:GetSelectedItem()) -- Water Quality System:SetProperty("waterquality",LauncherMenu.waterquality:GetSelectedItem()) -- Anistropic Filtering if LauncherMenu.afilter:GetSelectedItem() > -1 then System:SetProperty("anisotropicfilter",(string.gsub(LauncherMenu.afilter:GetItemText(LauncherMenu.afilter:GetSelectedItem()),"x",""))) else System:SetProperty("anisotropicfilter",(string.gsub(LauncherMenu.afilter:GetText(),"x",""))) end --Anisotropic Filtering System:SetProperty("trilinearfilter",((LauncherMenu.tfilter:GetState() == true) and 1 or 0)) -- Vsync System:SetProperty("verticalsync",((LauncherMenu.vsync:GetState() == true) and 1 or 0)) -- Window Mode if LauncherMenu.windowmode:GetSelectedItem() > -1 then System:SetProperty("windowmode",LauncherMenu.windowmode:GetSelectedItem()) if LauncherMenu.windowmode:GetSelectedItem() == 0 then LauncherWindowMode = Window.Center + Window.Titlebar elseif LauncherMenu.windowmode:GetSelectedItem() == 1 then LauncherWindowMode = Window.Center + Window.Tool elseif LauncherMenu.windowmode:GetSelectedItem() == 2 then LauncherWindowMode = Window.FullScreen else LauncherWindowMode = Window.FullScreen System:SetProperty("windowmode",2) end else LauncherWindowMode = Window.FullScreen System:SetProperty("windowmode",2) end end local function ApplyScreenMode() -- Window Mode num = tonumber((System:GetProperty("windowmode"))) if num ~= nil then if num >= 0 then if num > 2 then LauncherMenu.windowmode:SelectItem(2) else LauncherMenu.windowmode:SelectItem(num) end else LauncherMenu.windowmode:SelectItem(2) end else -- default LauncherMenu.windowmode:SelectItem(2) end if LauncherMenu.windowmode:GetSelectedItem() > -1 then if LauncherMenu.windowmode:GetSelectedItem() == 0 then LauncherWindowMode = Window.Center + Window.Titlebar elseif LauncherMenu.windowmode:GetSelectedItem() == 1 then LauncherWindowMode = Window.Center + Window.Tool elseif LauncherMenu.windowmode:GetSelectedItem() == 2 then LauncherWindowMode = Window.FullScreen else LauncherWindowMode = Window.FullScreen end else LauncherWindowMode = Window.FullScreen end end local function ProcessEvents(event) if event.source == LauncherMenu.applyoptions then ApplySettings() ProcessEvents(Event(Event.WidgetAction,LauncherMenu.closeoptions)) end if event.source == LauncherMenu.closeoptions then LauncherMenuClosed = true end end LoadSettings() ApplyScreenMode() while LauncherWindow:Closed()==false do while EventQueue:Peek() do ProcessEvents(EventQueue:Wait()) end if VSyncMode==nil then VSyncMode=true end LauncherContext:Sync(VSyncMode) if LauncherMenuClosed == true then break end end LauncherWindow:Release() end
To use it, first add:
import("Scripts/Launcher.lua")
to the top of Main.lua.
Next add
LauncherMenu()
After the title line.
Lastly, change:
window=Window:Create(title,0,0,gfxmode.x,gfxmode.y,windowstyle)
to
window=Window:Create(title,0,0,gfxmode.x,gfxmode.y, LauncherWindowMode)
This is all that needs to be done.
In action:
- 1
- 1
- 3
-
If you use the in game menu to change the lighting quality, the lighting seems to be disabled. The shadows disappear and it looks like the scene is only lit with ambient light.
-
"current" desktop resolution. Like if I play this on my TV using HDMI/VGA out. I would want it to run at 720p, but Leadwerks would default to 1080i and I wouldn't want that.
- 1
-
Hey now, I like utf8, I have just never had to deal with coding anything Unicode on Linux. All os's could have conflicting implementations. Is there a bsd/public domain lib that handles Unicode ?
- 1
-
-
I would make sure that the rest of the engine works with utf8 and let lua itself fail with the encoding. 5.3 has utf8 support https://www.lua.org/manual/5.3/manual.html#6.5 but it's not very robust.
Since it is still early, you do have the option to choose Lua derived language or a completely different language not based on Lua. As distasteful as it may be the API is changing, the scripts will need to be updated and it might be simpler to start over early with something else.
Who knows.
-
There really should be a function to get the desktop resolution.
- 1
-
I found this blog post a few days ago through reddit to be insightful. https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
It made me realise everything other than utf-16 is basically a beautiful hack.
it also speaks to the about wcs functions in c++
- 2
-
Yes that is the part that is giving you issues.
--if gamemenu:Hidden() then --Update the app timing Time:Update() --Update the world world:Update() --end
This would keep the game running in the background when you are in a menu. But there is a HUGE catch/problem. Any script that reads input needs to be edited to be made aware that a menu is open or to ignore input. Any script that reads or sets the mouses position or the keyboard or mouses key state will need to be edited. For example,the fpsplayer script will will move your mouse to the middle of the screen and you will not be able to select anything. So you will need to think of a way to let all scripts know that they are in a menu.
-
I've spent the last few days creating a simple self contained server browser. It will list all the servers of a specific game, allow the user to select a server and send a callback with the selected info.
Requirements:
The script from this topic placed in a file here: Scripts/Functions/eventqueuemanager.lua
The Script:
--[[ Name: serverBrowser Author: Einlander Date Completed: 2017-8-22 Description: A Server Browser for Leadwerks Notes: This is a rather simple Server Browser script that allows for listing of servers and selection. -2017-8-24: -Added the ability to directly connect to a ip and port. -Moved the code to put the window into a function and check on server browser creation. -2017-8-25: -Added the abilitiy to automatically resize to fit inside the bounds of the current context --]] --TODO: Add manual server connect import("Scripts/Functions/eventqueuemanager.lua") function serverBrowser(gameName,context,x,y,width,height) local self = {} self.gameName="" local _context local serverBrowser = {} local ServerBrowserClient = Client:Create() local callback = {} local movemode = false local currentWindow --[[ Description: Initializes and Draws the GUI Parameters: x as integer y as integer width as integer height as integer Notes: None ]] local function createUI(x,y,width,height) x = ((tonumber(x)~= nil) and x or 100) y = ((tonumber(y)~= nil) and y or 100) width = ((tonumber(width)~= nil) and width or 500) height = ((tonumber(height)~= nil) and height or 300) serverBrowser.gui = GUI:Create(_context) serverBrowser.gui:Hide() serverBrowser.root = serverBrowser.gui:GetBase() serverBrowser.root:SetLayout(x,y,width,height) serverBrowser.panel = Widget:Panel(0,0,width,height,serverBrowser.root) serverBrowser.closeButton = Widget:Button("X",1,1,19,19,serverBrowser.panel ) serverBrowser.closeButton:SetLayout(serverBrowser.panel:GetSize().x-serverBrowser.closeButton:GetSize().x - 10,1,19,19) -- hides browser when clicked, regardless of results serverBrowser.moveButton = Widget:Button("+",10,1,19,19,serverBrowser.panel ) serverBrowser.titlelabel = Widget:Label("Server Browser",40,5,100,25,serverBrowser.panel) serverBrowser.serveriplabel = Widget:Label("IP/Address:",15,serverBrowser.panel:GetSize().y - 23,100,25,serverBrowser.panel) serverBrowser.serverportlabel = Widget:Label("Port:",290,serverBrowser.panel:GetSize().y - 23,100,25,serverBrowser.panel) serverBrowser.serveripfield = Widget:TextField("",85,serverBrowser.panel:GetSize().y - 30, 200, 25, serverBrowser.panel) serverBrowser.serverportfield = Widget:TextField("",320,serverBrowser.panel:GetSize().y - 30,80,25,serverBrowser.panel) serverBrowser.connectButton = Widget:Button("Connect",405,serverBrowser.panel:GetSize().y - 30,55,25,serverBrowser.panel ) serverBrowser.serverList = Widget:ListBox(10,20,serverBrowser.panel:GetSize().x - 20,serverBrowser.panel:GetSize().y - 100,serverBrowser.panel) serverBrowser.refreshButton = Widget:Button("Refresh",10,serverBrowser.panel:GetSize().y - 70,55,25,serverBrowser.panel ) serverBrowser.joinButton = Widget:Button("Join",0,0,55,25,serverBrowser.panel ) serverBrowser.joinButton:SetLayout(serverBrowser.panel:GetSize().x-serverBrowser.refreshButton:GetSize().x - 10,serverBrowser.panel:GetSize().y - 70,55,25) serverBrowser.gui:Show() end --[[ Description: Resizes the GUI Parameters: Width as integer Height as integer Notes: none ]] function self:SetSize(width,height) serverBrowser.root:SetLayout(serverBrowser.root:GetPosition().x,serverBrowser.root:GetPosition().y,width,height) serverBrowser.panel:SetLayout(0,0,width,height) serverBrowser.closeButton:SetLayout(serverBrowser.panel:GetSize().x-serverBrowser.closeButton:GetSize().x - 10,1,19,19) -- hides browser when clicked, regardless of results serverBrowser.moveButton:SetLayout(10,1,19,19) serverBrowser.titlelabel:SetLayout(40,5,100,25) serverBrowser.serveriplabel:SetLayout(15,serverBrowser.panel:GetSize().y - 23,100,25) serverBrowser.serverportlabel:SetLayout(290,serverBrowser.panel:GetSize().y - 23,100,25) serverBrowser.serveripfield:SetLayout(85,serverBrowser.panel:GetSize().y - 30, 200, 25) serverBrowser.serverportfield:SetLayout(320,serverBrowser.panel:GetSize().y - 30,80,25) serverBrowser.connectButton:SetLayout(405,serverBrowser.panel:GetSize().y - 30,55,25) serverBrowser.serverList:SetLayout(10,20,serverBrowser.panel:GetSize().x - 20,serverBrowser.panel:GetSize().y - 100) serverBrowser.refreshButton:SetLayout(10,serverBrowser.panel:GetSize().y - 70,55,25) serverBrowser.joinButton:SetLayout(serverBrowser.panel:GetSize().x-serverBrowser.refreshButton:GetSize().x - 10,serverBrowser.panel:GetSize().y - 70,55,25) end --[[ Description: Returns the server browsers size Parameters: ScaledCoords as boolean Notes: scaledCoords: if set to false logical coordinates will be returned, otherwise scaled coordinates will be returned. ]] function self:GetSize(ScaledCoords) return serverBrowser.root:GetSize(ScaledCoords == true and true or false ) end --[[ Description: Shows UI Parameters: none Notes: none ]] function self:Show() serverBrowser.gui:Show() serverBrowser.root:Enable() self.context:GetWindow():ShowMouse() end --[[ Description: Hides UI Parameters: none Notes: none ]] function self:Hide() serverBrowser.gui:Hide() serverBrowser.root:Disable() end --[[ Description: Returns if UI is hidden or not Parameters: none Notes: none ]] function self:Hidden() return serverBrowser.gui:Hidden() end --[[ Description: Sets a external function to call when server is selected or window is closed. Parameters: callback as function Notes: --self:SetCallback is an overloaded function --self:SetCallback(callback) simple callback, used on functions not attached to an entity --self:SetCallback(self, callback) Used when adding from a script attached to an entity (calling from and to any function that starts with Script: ) self:SetCallback requires the callback function to have these 3 parameters: (ip,port,close) Ip is the server address as a string port is unused as of now since the leadwerks master server does not return it and also the remoteserver class has no property for it close is a boolean that retuns true if the serverbrowser is closed if it is closed it will return (nil,nil,true) if a server is chosen and connect is clicked, it will return ("address",nil,true) it will also close the window. Take care of how the callback handles the data (recursion is possible if not thought out properly) ]] function self:SetCallback(_callback) --if (#args==1) then if type(_callback) ~= "function" then return false end callback.functionValue = _callback --elseif (#args==2) then --if type(args[2]) ~= "function" then return false end --callback.selfValue = args[1] --callback.functionValue = args[2] --else --return false --end end --[[ Description: Removes the callback Parameters: none Notes: none ]] function self:ClearCallback() --callback.selfValue = nil callback.functionValue = nil end --[[ Description: Moves the serverbrowser back into the window Parameters: non Notes: none ]] local function FitInScreen() -- resize to fit inside current context if serverBrowser.root:GetSize().x > _context:GetWidth() then self:SetSize(_context:GetWidth(), serverBrowser.root:GetSize().y) end if serverBrowser.root:GetSize().y > _context:GetHeight() then self:SetSize(serverBrowser.root:GetSize().x, _context:GetHeight() ) end -- move it into view if serverBrowser.root:GetPosition().x + serverBrowser.root:GetSize().x > _context:GetWidth() then serverBrowser.root:SetLayout(serverBrowser.root:GetPosition().x - ( (serverBrowser.root:GetPosition().x + serverBrowser.root:GetSize().x) - _context:GetWidth()) ,serverBrowser.root:GetPosition().y ,serverBrowser.root:GetSize().x,serverBrowser.root:GetSize().y) end if serverBrowser.root:GetPosition().x < 0 then serverBrowser.root:SetLayout(0,serverBrowser.root:GetPosition().y ,serverBrowser.root:GetSize().x,serverBrowser.root:GetSize().y) end if serverBrowser.root:GetPosition().y + serverBrowser.root:GetSize().y > _context:GetHeight() then serverBrowser.root:SetLayout(serverBrowser.root:GetPosition().x ,serverBrowser.root:GetPosition().y - ( (serverBrowser.root:GetPosition().y + serverBrowser.root:GetSize().y) - _context:GetHeight()),serverBrowser.root:GetSize().x,serverBrowser.root:GetSize().y) end if serverBrowser.root:GetPosition().y < 0 then serverBrowser.root:SetLayout(serverBrowser.root:GetPosition().x, 0 ,serverBrowser.root:GetSize().x,serverBrowser.root:GetSize().y) end end --[[ Description: Processes all the events recived Parameters: event as Event Notes: none ]] local function ProcessEvent(event) if event.id == Event.WidgetSelect then elseif event.id == Event.WidgetAction then if movemode == true and (event.source == serverBrowser.gui) then _context:SetColor(0,0,0,0) -- need to clear alpha!!! otherwise you wont see the 3d serverBrowser.gui:Clear() serverBrowser.root:SetLayout(currentWindow:GetMousePosition().x - serverBrowser.moveButton:GetSize().x , currentWindow:GetMousePosition().y - (serverBrowser.moveButton:GetSize().y/2) ,serverBrowser.root:GetSize().x,serverBrowser.root:GetSize().y) EventQueue:Emit(Event.WidgetAction,serverBrowser.gui) if currentWindow:MouseHit(Key.LButton) then -- make sure it doesnt escape the screen movemode = false FitInScreen() _context:SetColor(0,0,0,0) serverBrowser.gui:Clear() serverBrowser.root:Enable() end serverBrowser.panel:Redraw() return true end if event.source == serverBrowser.moveButton then movemode = true currentWindow = Window:GetCurrent() EventQueue:Emit(Event.WidgetAction,serverBrowser.gui) _context:SetColor(0,0,0,0) serverBrowser.gui:Clear() serverBrowser.root:Disable() currentWindow:FlushMouse() return true end if event.source == serverBrowser.closeButton then serverBrowser.root:Disable() serverBrowser.gui:Hide() --System:Print(self.gameName .. ":: Close button") if callback.functionValue ~= nil then callback.functionValue(nil,nil,true) end self:Release() return true end if event.source == serverBrowser.connectButton then local serverip = ((string.len(serverBrowser.serveripfield:GetText())>0) and serverBrowser.serveripfield:GetText() or nil) local serverport = ((tonumber(serverBrowser.serverportfield:GetText()) ~= nil) and tonumber(serverBrowser.serverportfield:GetText()) or nil) if callback.functionValue ~= nil then local cb = callback.functionValue -- release everything to minimize mem use in case of consecutive server hopping.abs self:Release() cb(serverip,serverport,true)-- should it close when they chose a server? return true end return false end if event.source == serverBrowser.joinButton then --System:Print(self.gameName .. ":: Connect button") if serverBrowser.serverList:GetSelectedItem() > -1 then local servercount = ServerBrowserClient:CountServers(self.gameName) -- has a super high chance of screwing up when clicked, i mean REALLY HIGH local remoteServerData = ServerBrowserClient:GetServer(serverBrowser.serverList:GetSelectedItem()) --System:Print("Server Name::" .. remoteServerData.address .."#### Description" .. remoteServerData.description) serverBrowser.root:Disable() serverBrowser.gui:Hide() if callback.functionValue ~= nil then local cb = callback.functionValue local addy = remoteServerData.address -- there is no port :/ remoteServerData:Release() -- release everything to minimize mem use in case of consecutive server hopping. self:Release() cb(addy,nil,true)-- should it close when they chose a server? return true end end return false end if event.source == serverBrowser.refreshButton then --System:Print(self.gameName .. ":: Refresh button") self:PopulateServers(self.gameName) return true end end return true end --[[ Description: Hides UI Parameters: none Notes: none ]] function self:Update(event) if serverBrowser == nil then return false end if serverBrowser.gui:Hidden() then return false end if event:GetClassName() == "Event" then ProcessEvent(event) end return true end --[[ Description: Adds Servers to the server list Parameters: gameName as string Notes: Gamename is the exact name of the game the server registered ]] function self:PopulateServers(gameName) if gameName == nil then return end local servercount = ServerBrowserClient:CountServers(gameName) --System:Print("Server Count::" .. tostring(servercount)) serverBrowser.serverList:ClearItems() serverBrowser.serverList:SelectItem(-1) for i=0, servercount-1 do remoteServerData = ServerBrowserClient:GetServer(i) -- System:Print("Server Name::" .. remoteServerData.address .."#### Description" .. remoteServerData.description) serverBrowser.serverList:AddItem("["..remoteServerData.address.."] ["..remoteServerData.description.."]") end end --[[ Description: Initializes Class Parameters: gameName as string context as Context x as integer y as y as integer width as integer height as integer Notes: Gamename is the exact name of the game the server registered ]] local function init(gameName,context,x,y,width,height) -- check for the context _context = context createUI(x,y,width,height) FitInScreen() self.gameName = gameName self:PopulateServers(self.gameName) EventQueueManager:AddListener(self.Update) end --[[ Description: Unloads the class and all it's componentes Parameters: none Notes: none ]] function self:Release() for item in pairs(self) do if (type(self[item]) == "function") or (type(self[item]) == "userdata") then self[item] = nil end end self.gameName = nil -- The order is important! serverBrowser.root:Disable() serverBrowser.gui:Hide() serverBrowser.closeButton:Release() serverBrowser.titlelabel:Release() serverBrowser.serverList:Release() serverBrowser.joinButton:Release() serverBrowser.refreshButton:Release() serverBrowser.connectButton:Release() serverBrowser.moveButton:Release() serverBrowser.serveriplabel:Release() serverBrowser.serverportlabel:Release() serverBrowser.serveripfield:Release() serverBrowser.serverportfield:Release() serverBrowser.panel:Release() serverBrowser.root:Release() serverBrowser.gui = nil serverBrowser=nil ServerBrowserClient:Release() _context = nil callback = nil movemode = nil self.Show = nil self = nil end init(gameName,context,x,y,width,height) return self end
A simple example:
It will create a server and open a server browser window. + Starts the move mode, click to exit it. X closes the window.
import("Scripts/Functions/eventqueuemanager.lua") import("Scripts/serverbrowser.lua") local window = Window:Create() local context = Context:Create(window) local server = Server:Create() System:Print("Server1 publish::" .. tostring(server:Publish("Example Temp Test Server", "Testing population of server list from masterserver "))) server:Release() function test(ip,port,close) -- callback function System:Print("Callback") System:Print(ip) System:Print(tostring((close == true) and "close" or "")) end local serverbrowser = serverBrowser("Example Temp Test Server",context,0,0) -- create the serverbrowser serverbrowser:SetCallback(test) -- set callback -- do stuff while true do if window:Closed() then return end if window:KeyHit(Key.Escape) then return end Time:Update() context:SetColor(0,0,0,0) -- need to clear alpha!! or the gui will stay on screen!! context:Clear() EventQueueManager:Update() context:Sync() end serverbrowser:ClearCallback() -- remove callback serverbrowser:Release() -- release everything
The server browser will obey the limits of your window. If any part of it is not on screen, it will be pushed back onto it.
Edits:
-2017-8-24: -Added the ability to directly connect to a ip and port.
-Moved the code to put the window into a function and check on server browser creation.-2017-8-25: -Added the abilitiy to automatically resize to fit inside the bounds of the current context
-
[I had text here but in the edit it dissapeared ]
I found that there can only be one instance of the EventQueue. This meant that all the widget events need to be handled in a single location leading to possible complications in code and lowering the possibility to dynamic things. This script allows the developer to subscribe to an eventqueue manager and get their event safely, without usurping all gui controls.
The script will automatically create an EventQueueManager variable that all other scripts can expect.
To use it from a script not attached to an entity use:
EventQueueManager:AddListener(Update) -- a simple function
On a script attached to an entity or a lua based class use:
EventQueueManager:AddListener(serverbrowser.Update) -- convert : into .
Place the script into a file at: Scripts/Functions/eventqueuemanager.lua
--[[ Name: EventQueueManager Author: Einlander Date Completed: 2017-8-20 Description: An EventQueue manager Notes: This script puts all the eventqueue proccessing in one location, allowing other scripts to manage themselves and not take control of the eventqueue. THIS SCRIPT WILL AUTO LOAD AS A GLOBAL THIS SCRIPT WILL AUTO LOAD AS A GLOBAL THIS SCRIPT WILL AUTO LOAD AS A GLOBAL THIS SCRIPT WILL AUTO LOAD AS A GLOBAL Updates: 2017-8-22 -Will no longer overwrite EventQueueManager variable. This will lead to unintended behavior -No longer loops through the evenqueue. It is possible to have infinite Loops With previous behavior --]] EventQueueManager = {} function EventQueueManager:Create() local self = {} local callbackList = {} --self:AddListener is an overloaded function --self:AddListener(callback) simple callback, used on functions not attached to an entity --self:AddListener(self, callback) Used when adding from a script attached to an entity (calling from and to any function that starts with Script: ) function self:AddListener(...) local args = {...} local _callbackself local _callback if (#args==1) then _callback = args[1] elseif (#args==2) then _callbackself = args[1] _callback = args[2] else return false end for index,callback in ipairs(callbackList) do if callback == _callback then --System:Print("Match Found") return false end end table.insert(callbackList,{callback = _callback,self = _callbackself}) return true end function self:RemoveListener(_callback) -- removes the callback for index,callbackitem in ipairs(callbackList) do if callbackitem.callback == _callback then table.remove(callbackList,index) return true end end return false end function self:Update() -- processes eventqueue and sends the event info to all callbacks if EventQueue:Peek() then -- will no longer loop through the entire event queue. It can lead to infinite loops. local event = EventQueue:Wait() for index,callbackitem in pairs(callbackList) do if callbackitem.self == nil then callbackitem:callback(event) else callbackitem.callback(callbackitem.self,event) end end end end return self end if EventQueueManager ~= nil then -- Will no longer Overwrite variable but will allow for unexpected behavior EventQueueManager = EventQueueManager:Create() end
8-22-2017 -- updated script
- 1
-
I am trying to have a generic gui class and I realized that there can be only 1 EventQueue. This means that all widgets must be managed from a single area. This means that I can't create a gui class that handles its own events without using some creative methods that have some serious edge cases. I would like to specify my own function/callback/eventqueue to call for each widget item. It would allow people to create safe, shareable scripts.
I would like to create a widget and pass it a local eventqueue such as this one
and handle all the events locally.
-
I discovered that there can only be one eventqueue in leadwerks. I wanted local eventqueue instances, so I created a lua based version of EventQueue called EventQueueEx
It is initialized as such:
MyQueue = EventQueueEx:Create()
It is used EXACTLY the same as the Leadwerks version.
--[[ Name: EventQueEX Author: Einlander Date Completed: Description: A lua Implementation of the EventQueue class Notes: This script was mainly created a developer can have self contained EventQueue and not have to restructure your program to have exactly 1 EventQueue processing routine. To be used exactly as the built-in EventQueue. --]] EventQueueEx = {} function EventQueueEx:Create() -- Create an instance of EventQueueEx local self = {} local queue = {} function self:Peek() -- Return true if table is not empty if #queue > 0 then return true end return false end function self:Wait() -- get top entry and remove from table if #queue < 1 then return nil end local eventItem = Event(queue[1].id, queue[1].source, queue[1].data, iVec2(queue[1].x, queue[1].y) , iVec2(queue[1].width, queue[1].height), queue[1].extra) -- we remove and not nil it to keep a contigous array with no holes in it. -- This allows for the #table shorcut to work without manually looping through the whole table table.remove(queue,1) return eventItem end function self:Flush() -- Clear Queue queue = {} end function self:Emit(id, source, data, x,y,width,height,extra) -- Add Event to Queue -- simple input checks and sanitation Debug:Assert(id ~= nil, "id is ["..type(id).."], Number or Event expected." ) if id:GetClassName() == "Event" then -- passed a event object table.insert(queue,{id = id.id, source = id.source, data = id.data, x = id.position.x, y = id.position.y, width = id.size.x, height = id.size.y, extra = extra}) else -- simple input checks and sanitation -- will set defaults if value is missing Debug:Assert(type(id) == "number", "id is ["..type(id).."], Number Expected." ) local source = source local data = (type(data) == "number") and data or 0 local x = (type(x) == "number") and x or 0 local y = (type(y) == "number") and y or 0 local width = (type(width) == "number") and width or 0 local height = (type(height) == "number") and height or 0 local extra = extra table.insert(queue,{id = id, source = source, data = data, x = x, y = y, width = width, height = height, extra = extra}) end end function self:Release() -- allow class to go out of scope queue = nil self = nil end return self end
-
The server list seems to fail when attempting to register multiple servers from the same server but different port.
Also, it will fail to register if the name is just one word.
Example:
server = Server:Create() System:Print("Server1 publish::" .. tostring(server:Publish("Einlanders server stub", "Testing population of server list from masterserver "))) server2 = Server:Create(27015) System:Print("Server2 publish::" .. tostring(server2:Publish("Einlanders server stub", "Testing population of server list from masterserver 2"))) client = Client:Create() local servercount = client:CountServers("Einlanders server stub") System:Print("Server Count::" .. tostring(servercount)) for i=0, servercount-1 do remoteServerData = client:GetServer(i) System:Print("Server Name::" .. remoteServerData.address .."#### Description" .. remoteServerData.description) end
The Output:
Server1 publish::true ERROR Server2 publish::false Server Count::1 Server Name::xxx.xxx.xxx.xxx#### DescriptionTesting pupulation of server list from masterserver
-
While writing a server browser I discovered that RemoteGame does not not have a port property. So if you do set your server on a non default port, you will not be able to connect to it by using the server list. Which leads to this issue:
Container
in Programming
Posted
replace that line with this
if event.source == Storage.but1 then
Your Storage variable was created as a global variable. It is not local to the script that created it.