Jump to content

In-Game Script Editor v0.2


Colex

Recommended Posts

In-Game Script Editor v0.2

I was going to start scripting my own gamemode when i realized that I would have to run and close the MTA to make the smallest change. (if there is another way tell me how :P)

I decided to develope a small in-client editor which could help me in my bugfixes and minor updates...

these are the editor's features:

  • File Browser (new)
  • Load Script
  • Save Script
  • Save and reload script
  • Toogle Chat [F1] (this feature lets you use your chat keys for writing)

Zipped Resource:

http://rapidshare.com/files/81600823/ScriptEditor.zip

In order for the File Browser work perfectly you must do the follwoing statemenst: (Mini-Tutorial written by eAi)

Visit your server's web interface and just add general.ModifyOtherObjects to a new ACL, then create a new group for ScriptEditor with resource.ScriptEditor as an object and your new ACL.

The scripts is divided in 3 parts, 1 client script and 2 server scripts.

Firstly, Ill give you the Client Script:

 ---------------In-Game Editor by Colex [Client Script]------------------------- 
  
local WIDTH  = 0.75 
local HEIGHT = 0.9 
  
local INITIAL_DIR = "" 
  
  
-------------------- 
local canChat, editorWindow, editPath, scriptBox = true 
local dialog = {} 
  
local scriptInput = function() 
  if (guiGetVisible(editorWindow)) then 
    canChat = not(canChat) 
    toggleControl("chatbox", canChat) 
  end 
end 
  
local processReturn = function(ret, text) 
  outputChatBox(ret)  
  if (text) then 
    guiSetText(scriptBox, text)   
  end                                                            
end 
  
local reloadScript = function(button, state) 
  if (button == "left" and state == "down") then 
    triggerServerEvent("onSaveScript", getRootElement(), guiGetText(editPath), guiGetText(scriptBox)) 
    triggerServerEvent("onReloadScript", getRootElement()) 
  end 
end 
  
local saveScript = function(button, state) 
  if (button == "left" and state == "down") then 
    triggerServerEvent("onSaveScript", getRootElement(), guiGetText(editPath), guiGetText(scriptBox)) 
  end 
end 
  
local openScript = function(button, state, text) 
  if (button == "left" and state == "down") then 
    triggerServerEvent("onOpenScript", getRootElement(), guiGetText(editPath)) 
  end 
end 
  
local toogleDialog = function(button, state) 
  if (dialog.window) and (state == "down") and (button == "left")   then 
    guiSetVisible(dialog.window, not(guiGetVisible(dialog.window))) 
    guiBringToFront(dialog.window) 
    guiGridListClear(dialog.list) 
    guiGridListAddColumn(dialog.list, "Resources", 1) 
    triggerServerEvent("onRefreshDialog", getRootElement(), guiGetText(editPath))   
  end 
end 
  
local dialogSelect = function(button, state) 
  if (button == "left" and state == "down") then 
    local row = guiGridListGetSelectedItem(dialog.list) 
    if (row) then 
      local elem = guiGridListGetItemText(dialog.list, row, 1) 
      if (elem == "..\\") then elem = "" end 
      local pos, path = elem:find('%.') or 0 
      if (pos > 0) then 
        toogleDialog("left", "down") 
        path = getResourceNameFromPath(guiGetText(editPath)).."\\"..elem      
      else 
        path = elem 
        guiGridListClear(dialog.list) 
        guiGridListAddColumn(dialog.list, "Resources", 1) 
        triggerServerEvent("onRefreshDialog", getRootElement(), path)   
      end 
      guiSetText(editPath, path)   
    end 
  end 
end 
  
local dialogReturn = function(elem) 
  local row = guiGridListAddRow(dialog.list) 
  guiGridListSetItemText(dialog.list, row, 1, elem, false, false)  
end 
  
local createDialog = function() 
  if not(dialog.window) then 
    dialog.window = guiCreateWindow(0.01, 0.01, 0.5, 0.45, "Open Dialog", true) 
    local closeBtn = guiCreateButton(0.9, 0.15, 0.15, 0.15, "X", true, dialog.window) 
    dialog.list = guiCreateGridList(0.1, 0.15, 0.8, 0.85, true, dialog.window) 
    guiBringToFront(dialog.window) 
    guiSetVisible(dialog.window, false) 
    addEventHandler("onClientGUIClick", closeBtn, toogleDialog)        
    addEventHandler("onClientGUIDoubleClick", dialog.list, dialogSelect)  
  end 
end 
  
  
local createEditor = function() 
  if not(editorWindow) then --Constructor    
    editorWindow = guiCreateWindow(0.2, 0.2, HEIGHT, WIDTH, "In-Game Script Editor", true) 
    guiCreateLabel(0.05, 0.06, 1, 1, "Script Path:", true, editorWindow) 
    editPath = guiCreateEdit(0.04, 0.1, 0.6, 0.08, INITIAL_DIR, true, editorWindow) 
    local openBtn   = guiCreateButton(0.75, 0.1, 0.2, 0.1, "Load Script", true, editorWindow) 
    local dialogBtn = guiCreateButton(0.65, 0.1, 0.1, 0.1, "...", true, editorWindow) 
    scriptBox = guiCreateMemo(0.02, 0.26, 0.96, 0.55, "", true, editorWindow)  
    local reloadBtn = guiCreateButton(0.75, 0.88, 0.2, 0.1, "Save & Reload", true, editorWindow) 
    local saveBtn   = guiCreateButton(0.50, 0.88, 0.2, 0.1, "Save Script", true, editorWindow) 
    addEventHandler("onClientGUIClick", reloadBtn, reloadScript) 
    addEventHandler("onClientGUIClick", saveBtn, saveScript) 
    addEventHandler("onClientGUIClick", openBtn, openScript) 
    addEventHandler("onClientGUIClick", dialogBtn, toogleDialog) 
    bindKey("F1", "down", scriptInput)        
    createDialog() 
    showCursor(true) 
  else --Show/Hide 
    showCursor(not(guiGetVisible(editorWindow))) 
    guiSetVisible(editorWindow, not(guiGetVisible(editorWindow))) 
    guiSetVisible(dialog.window, false) 
  end 
end 
  
function getResourceNameFromPath(path) 
  if (type(path) ~= "string") then return "" end 
  local sep1, sep = path:find("\\") or 0 
  local sep2      = path:find("/") or 0 
  if (sep1 > sep2) then sep = sep1 else sep = sep2 end 
  if (sep == 0) then return path end 
  return path:sub(1, sep-1), path:sub(sep+1, path:len()) 
end 
  
addCommandHandler ("editor", createEditor) 
  
addEvent("onProcessReturn", true) 
addEvent("onDialogReturn", true) 
addEventHandler("onProcessReturn", getRootElement(), processReturn) 
addEventHandler("onDialogReturn", getRootElement(), dialogReturn) 

Now the Server Scripts:

  
---------------In-Game Editor by Colex [server Script]------------------------- 
  
local getEndOfFile = function(file) 
  local tmp, endPos = fileGetPos(file) 
  while not fileIsEOF(file) do     
    fileRead(file, 500)                       
  end 
  endPos = fileGetPos(file) 
  fileSetPos(file, tmp) 
  return endPos 
end 
  
  
function getResourceNameByPath(path) 
  if (type(path) ~= "string") then return "" end 
  local sep1, sep = path:find("\\") or 0 
  local sep2      = path:find("/") or 0 
  if (sep1 > sep2) then sep = sep1 else sep = sep2 end 
  if (sep == 0) then return path end 
  return path:sub(1, sep-1), path:sub(sep+1, path:len()) 
end 
  
function reloadScript() 
  triggerClientEvent(client, "onProcessReturn", getRootElement(), "Restarting resources...")   
  local resources = getResources() 
  for _,res in ipairs(resources) do 
    if getResourceState(res) == "running" then 
      restartResource(res) 
    end 
  end    
end 
  
function saveScript(path, text) 
  triggerClientEvent(client, "onProcessReturn", getRootElement(), "Saving Script...")  
  local resName, path = getResourceNameByPath(path)  
  local file = fileCreate(path, getResourceFromName(resName)) 
  if (file) then 
    fileWrite(file, text) 
    fileClose(file) 
    triggerClientEvent(client, "onProcessReturn", getRootElement(), "[DONE] Script Saved!")   
  else 
    triggerClientEvent(client, "onProcessReturn", getRootElement(), "[ERROR] Could not save the script!")         
  end  
end 
  
function openScript(path) 
  triggerClientEvent(client, "onProcessReturn", getRootElement(), "Loading Script...")  
  local resName, path = getResourceNameByPath(path)  
  local file = fileOpen(path, true, getResourceFromName(resName)) 
  if (file) then 
    local text = fileRead(file, getEndOfFile(file)) 
    triggerClientEvent(client, "onProcessReturn", getRootElement(), "[DONE] Script loaded!", text) 
    fileClose(file)  
  else 
    triggerClientEvent(client, "onProcessReturn", getRootElement(), "[ERROR] Script could not be loaded!") 
  end     
end 
  
addEvent("onReloadScript", true) 
addEvent("onSaveScript", true) 
addEvent("onOpenScript", true) 
addEventHandler("onReloadScript", getRootElement(), reloadScript) 
addEventHandler("onSaveScript", getRootElement(), saveScript) 
addEventHandler("onOpenScript", getRootElement(), openScript) 
  

---------------In-Game Editor by Colex [server Script (Open sDialog)]------------------------- 
  
  
OpenDialog = { 
  create = function() 
    local resources, id = getResources(), #OpenDialog+1 
    return {res = resources, resource = "", refresh = OpenDialog.refresh, delete = OpenDialog.delete,  
    readMeta = OpenDialog.readMeta}  
  end, 
  refresh = function(self) 
    self.res = getResources()   
  end, 
  readMeta = function(self) 
    local root = getResourceFromName(self.resource) 
    local xml, ret = xmlLoadFile("meta.xml", root), {} 
    if (xml) then 
      local node, i = xmlFindSubNode(xml, "script", 0), 0 
      while (node) do   
        table.insert(ret, xmlNodeGetAttribute(node, "src")) 
        i = i + 1 
        node = xmlFindSubNode(xml, "script", i) 
      end   
    end 
    return ret 
  end, 
  delete = function(self) 
    for i in pairs(self) do 
      self[i] = nil 
    end 
  end 
} 
  
  
local refreshDialog = function(path) 
  OpenDial.resource = getResourceNameByPath(path) 
  local res, elems = getResourceFromName(OpenDial.resource), {} 
  if (res) then 
    elems = OpenDial:readMeta()   
    table.insert(elems, 1, "..\\") 
  else 
    elems = getResources() 
  end 
  for _,v in ipairs(elems) do 
    local value 
    if (type(v) == "userdata") then value = getResourceName(v) else value = v end  
    triggerClientEvent(client, "onDialogReturn", getRootElement(), value)  
  end 
end 
  
  
OpenDial = OpenDialog.create() 
  
  
addEvent("onRefreshDialog", true) 
addEventHandler("onRefreshDialog", getRootElement(), refreshDialog) 

To open and close the editor type the command /editor

If you don't find it useful, you can still use it for studying purposes.

Anyway, hope you enjoy it, if you find any bug please report it here, so I can try to fix it.

Yours,

Colex

Edited by Guest
Link to comment
Nice script :). We'll look at a way of minimizing MTA later though, might not be in next Development Preview, but in a later one.

Nice! This is one of the reasons why MTA pwnz SA:MP now... :D I will try it i hope this works good :)

1. Please use EDIT button. :wink:

2. Well, some SA-MP scripters have made something like this too.

3. MTA still pwnz sa-mp :mrgreen:

Link to comment

At this moment, you must have the editor in the same directory of the script you want to edit... (I'll start the new update now)

if you have the script CounterStrike.lua in the editor's folder, to load the script you type CounterStrike.lua

If everything goes as I'm planning, I'll add a resources browser and if I have time I might add an tabs system =)

Yours,

Colex

Link to comment
At this moment, you must have the editor in the same directory of the script you want to edit... (I'll start the new update now)

if you have the script CounterStrike.lua in the editor's folder, to load the script you type CounterStrike.lua

If everything goes as I'm planning, I'll add a resources browser and if I have time I might add an tabs system =)

Yours,

Colex

Awesome, would be totally awesome with the tabs. Thanks for this :D

Link to comment

Yes file browser! just what i was about to ask, thanks!

Edit: i selected the directory but its not showing my lua file :(

i dont know if this is the cause but this is what i got in my server.log

ERROR: xmlLoadFile failed; ModifyOtherObjects in ACL denied resource ScriptEditor to access commands

commands is the script folder

Link to comment

ok eAI i did what you said and it still doesnt work... i tried both of these

   <group name="ScriptEditor"/> 
      <acl name="ScriptEditor"/> 
      <object name="resource.ScriptEditor"/> 
   </group> 

   <group name="ScriptEditor"/> 
      <acl name="ScriptEditor"/> 
      <right name="general.ModifyOtherObjects" access="true"/> 
      <object name="resource.ScriptEditor"/> 
   </group> 

Neither worked. script still didnt show or load :(

Link to comment
ok eAI i did what you said and it still doesnt work... i tried both of these

   <group name="ScriptEditor"/> 
      <acl name="ScriptEditor"/> 
      <object name="resource.ScriptEditor"/> 
   </group> 

   <group name="ScriptEditor"/> 
      <acl name="ScriptEditor"/> 
      <right name="general.ModifyOtherObjects" access="true"/> 
      <object name="resource.ScriptEditor"/> 
   </group> 

Neither worked. script still didnt show or load :(

You defined 2 times a group, you need to define the ACL too. Like this (untested):

   <group name="ScriptEditor"/> 
      <acl name="ScriptEditor"/> 
      <object name="resource.ScriptEditor"/> 
   </group> 

   <acl name="ScriptEditor"/> 
      <right name="general.ModifyOtherObjects" access="true"/> 
   </acl> 

Edited by Guest
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...