DefineClass.EditorObject = { __parents = { "CObject" }, EditorEnter = empty_func, EditorExit = empty_func, } function EditorObject:PostLoad() if IsEditorActive() then self:EditorEnter() end end RecursiveCallMethods.EditorEnter = "procall" RecursiveCallMethods.EditorExit = "procall_parents_last" DefineClass.EditorCallbackObject = { __parents = { "CObject" }, flags = { cfEditorCallback = true }, -- all callbacks receive no parameters, except EditorCallbackClone, which receives the original object EditorCallbackPlace = empty_func, EditorCallbackPlaceCursor = empty_func, EditorCallbackDelete = empty_func, EditorCallbackRotate = empty_func, EditorCallbackMove = empty_func, EditorCallbackScale = empty_func, EditorCallbackClone = empty_func, -- function(orig) end, EditorCallbackGenerate = empty_func, -- function(generator, object_source, placed_objects, prefab_list) end, } AutoResolveMethods.EditorCallbackPlace = true AutoResolveMethods.EditorCallbackPlaceCursor = true AutoResolveMethods.EditorCallbackDelete = true AutoResolveMethods.EditorCallbackRotate = true AutoResolveMethods.EditorCallbackMove = true AutoResolveMethods.EditorCallbackScale = true AutoResolveMethods.EditorCallbackClone = true AutoResolveMethods.EditorCallbackGenerate = true function OnMsg.ChangeMapDone() --CObjects that are EditorVisibleObject will get saved as efVisible == true and pop up on first map load if GetMap() == "" then return end if not IsEditorActive() then MapForEach("map", "EditorVisibleObject", const.efVisible, function(o) o:ClearEnumFlags(const.efVisible) end) end end DefineClass.EditorVisibleObject = { __parents = { "EditorObject" }, flags = { efVisible = false }, properties = { { id = "OnCollisionWithCamera" }, }, } function EditorVisibleObject:EditorEnter() self:SetEnumFlags(const.efVisible) end function EditorVisibleObject:EditorExit() self:ClearEnumFlags(const.efVisible) end ---- DefineClass.EditorColorObject = { __parents = { "EditorObject" }, editor_color = false, orig_color = false, } function EditorColorObject:EditorGetColor() return self.editor_color end function EditorColorObject:EditorEnter() local editor_color = self:EditorGetColor() if editor_color then self.orig_color = self:GetColorModifier() self:SetColorModifier(editor_color) end end function EditorColorObject:EditorExit() if self.orig_color then self:SetColorModifier(self.orig_color) self.orig_color = false end end function EditorColorObject:GetColorModifier() if self.orig_color then return self.orig_color end return EditorObject.GetColorModifier(self) end ---- DefineClass.EditorEntityObject = { __parents = { "EditorCallbackObject", "EditorColorObject" }, entity = "", editor_entity = "", orig_scale = false, editor_scale = false, } function EditorEntityObject:EditorCanPlace() return true end function EditorEntityObject:SetEditorEntity(set) if (self.editor_entity or "") ~= "" then self:ChangeEntity(set and self.editor_entity or g_Classes[self.class]:GetEntity()) end if self.editor_scale then if set then self.orig_scale = self:GetScale() self:SetScale(self.editor_scale) elseif self.orig_scale then self:SetScale(self.orig_scale) self.orig_scale = false end end end function EditorEntityObject:GetScale() if self.orig_scale then return self.orig_scale end return EditorObject.GetScale(self) end function EditorEntityObject:EditorEnter() self:SetEditorEntity(true) end function EditorEntityObject:EditorExit() self:SetEditorEntity(false) end function OnMsg.EditorCallback(id, objects, ...) if id == "EditorCallbackPlace" or id == "EditorCallbackPlaceCursor" then for i = 1, #objects do local obj = objects[i] if obj:IsKindOf("EditorEntityObject") then obj:SetEditorEntity(true) end end end end ---- DefineClass.EditorTextObject = { __parents = { "EditorObject", "ComponentAttach" }, editor_text_spot = "Label", editor_text_color = RGBA(255,255,255,255), editor_text_offset = point(0,0,3*guim), editor_text_style = false, editor_text_depth_test = true, editor_text_ctarget = "SetColor", editor_text_obj = false, editor_text_member = "class", editor_text_class = "Text", } function EditorTextObject:EditorEnter() self:EditorTextUpdate(true) end function EditorTextObject:EditorExit() DoneObject(self.editor_text_obj) self.editor_text_obj = nil end AutoResolveMethods.EditorGetText = ".." function EditorTextObject:EditorGetText() return self[self.editor_text_member] end function EditorTextObject:EditorGetTextColor() return self.editor_text_color end function EditorTextObject:EditorGetTextStyle() return self.editor_text_style end function EditorTextObject:Clone(class, ...) local clone = EditorObject.Clone(self, class or self.class, ...) if IsKindOf(clone, "EditorTextObject") then clone:EditorTextUpdate(true) end return clone end function EditorTextObject:EditorTextUpdate(create) if not IsValid(self) then return end local obj = self.editor_text_obj if not IsValid(obj) and not create then return end local is_hidden = GetDeveloperOption("Hidden", "EditorHiddenTextOptions", self.class) local text = not is_hidden and self:EditorGetText() if not text then DoneObject(obj) return end if not IsValid(obj) then obj = PlaceObject(self.editor_text_class, {text_style = self:EditorGetTextStyle()}) obj:SetDepthTest(self.editor_text_depth_test) local spot = self.editor_text_spot if spot and self:HasSpot(spot) then self:Attach(obj, self:GetSpotBeginIndex(spot)) else self:Attach(obj) end local offset = self.editor_text_offset if offset then obj:SetAttachOffset(offset) end self.editor_text_obj = obj end obj:SetText(text) local color = self:EditorGetTextColor() if color then obj[self.editor_text_ctarget](obj, color) end end function EditorTextObject:OnEditorSetProperty(prop_id) if prop_id == self.editor_text_member then self:EditorTextUpdate(true) end return EditorObject.OnEditorSetProperty(self, prop_id) end DefineClass.NoteMarker = { __parents = { "Object", "EditorVisibleObject", "EditorTextObject" }, properties = { { id = "MantisID", editor = "number", default = 0, important = true , buttons = {{name = "OpenMantis", func = "OpenMantisFromMarker"}}}, { id = "Text", editor = "text", lines = 5, default = "", important = true }, { id = "TextColor", editor = "color", default = RGB(255,255,255), important = true }, { id = "TextStyle", editor = "text", default = "InfoText", important = true }, -- disabled properties { id = "Angle", editor = false}, { id = "Axis", editor = false}, { id = "Opacity", editor = false}, { id = "StateCategory", editor = false}, { id = "StateText", editor = false}, { id = "Groups", editor = false}, { id = "Mirrored", editor = false}, { id = "ColorModifier", editor = false}, { id = "Occludes", editor = false}, { id = "Walkable", editor = false}, { id = "ApplyToGrids", editor = false}, { id = "Collision", editor = false}, { id = "OnCollisionWithCamera", editor = false}, { id = "CollectionIndex", editor = false}, { id = "CollectionName", editor = false}, }, editor_text_offset = point(0,0,4*guim), editor_text_member = "Text", } for i = 1, const.MaxColorizationMaterials do table.iappend( NoteMarker.properties, { { id = string.format("Color%d", i), editor = false }, { id = string.format("Roughness%d", i), editor = false }, { id = string.format("Metallic%d", i), editor = false }, }) end function NoteMarker:EditorGetTextColor() return self.TextColor end function NoteMarker:EditorGetTextStyle() return self.TextStyle end function OpenMantisFromMarker(parentEditor, object, prop_id, ...) local mantisID = object:GetProperty(prop_id) if mantisID and mantisID ~= "" and mantisID ~= 0 then local url = "http://mantis.haemimontgames.com/view.php?id="..mantisID OpenUrl(url, "force external browser") end end if not Platform.editor then function OnMsg.ClassesPreprocess(classdefs) for name, class in pairs(classdefs) do class.EditorCallbackPlace = nil class.EditorCallbackPlaceCursor = nil class.EditorCallbackDelete = nil class.EditorCallbackRotate = nil class.EditorCallbackMove = nil class.EditorCallbackScale = nil class.EditorCallbackClone = nil class.EditorCallbackGenerate = nil class.EditorEnter = nil class.EditorExit = nil class.EditorGetText = nil class.EditorGetTextColor = nil class.EditorGetTextStyle = nil class.EditorGetTextFont = nil class.editor_text_obj = nil class.editor_text_spot = nil class.editor_text_color = nil class.editor_text_offset = nil class.editor_text_style = nil end end function OnMsg.Autorun() MsgClear("EditorCallback") MsgClear("GameEnterEditor") MsgClear("GameExitEditor") end end ---- local update_thread function UpdateEditorTexts() if not IsEditorActive() or IsValidThread(update_thread) then return end update_thread = CreateRealTimeThread(function() MapForEach("map", "EditorTextObject", function(obj) obj:EditorTextUpdate(true) end) end) end function OnMsg.DeveloperOptionsChanged(storage, name, id, value) if storage == "EditorHiddenTextOptions" then UpdateEditorTexts() end end ---- DefineClass.ForcedTemplate = { __parents = { "EditorObject" }, template_class = "Template", } function GetTemplateBase(class_name) local class = g_Classes[class_name] return class and class.template_class or "" end MapVar("ForcedTemplateObjs", {}) function ForcedTemplate:EditorEnter() if self:GetGameFlags(const.gofPermanent) == 0 and self:GetEnumFlags(const.efVisible) ~= 0 then ForcedTemplateObjs[self] = true self:ClearEnumFlags(const.efVisible) end end function ForcedTemplate:EditorExit() if ForcedTemplateObjs[self] then self:SetEnumFlags(const.efVisible) end end ---- EditorSelectedObject -------------------------------------- MapVar("l_editor_selection", empty_table) DefineClass.EditorSelectedObject = { __parents = { "CObject" }, } function EditorSelectedObject:EditorSelect(selected) end function EditorSelectedObject:EditorIsSelected(check_helpers) if l_editor_selection[self] then return true end if check_helpers then local helpers = PropertyHelpers and PropertyHelpers[self] or empty_table for prop_id, helper in pairs(helpers) do if editor.IsSelected(helper) then return true end end end return false end function UpdateEditorSelectedObjects(selection) local new_selection = setmetatable({}, weak_keys_meta) local old_selection = l_editor_selection l_editor_selection = new_selection for i=1,#(selection or "") do local obj = selection[i] if IsKindOf(obj, "EditorSelectedObject") then new_selection[obj] = true if not old_selection[obj] then obj:EditorSelect(true) end end end for obj in pairs(old_selection or empty_table) do if not new_selection[obj] then obj:EditorSelect(false) end end end function OnMsg.EditorSelectionChanged(selection) UpdateEditorSelectedObjects(selection) end function OnMsg.GameEnterEditor() UpdateEditorSelectedObjects(editor.GetSel()) end function OnMsg.GameExitEditor() UpdateEditorSelectedObjects() end ---- EditorSubVariantObject -------------------------------------- DefineClass.EditorSubVariantObject = { __parents = { "PropertyObject" }, properties = { { name = "Subvariant", id = "subvariant", editor = "number", default = -1, buttons = { { name = "Next", func = "CycleEntityBtn" }, }, }, }, } function EditorSubVariantObject:CycleEntityBtn() self:CycleEntity() end function EditorSubVariantObject:Setsubvariant(val) self.subvariant = val end function EditorSubVariantObject:PreviousEntity() self:CycleEntity(-1) end function EditorSubVariantObject:NextEntity() self:CycleEntity(-1) end local maxEnt = 20 function EditorSubVariantObject:CycleEntity(delta) delta = delta or 1 local curE = self:GetEntity() local nxt = self.subvariant == -1 and (tonumber(string.match(curE, "%d+$")) or 1) or self.subvariant nxt = nxt + delta local nxtE = string.gsub(curE, "%d+$", (nxt < 10 and "0" or "") .. tostring(nxt)) if not IsValidEntity(nxtE) then if delta > 0 then --going up, reset to first nxt = 1 nxtE = string.gsub(curE, "%d+$", (nxt < 10 and "0" or "") .. tostring(nxt)) else --going down, reset to last, whichever that is.. nxt = maxEnt + 1 while not IsValidEntity(nxtE) and nxt > 0 do nxt = nxt - 1 nxtE = string.gsub(curE, "%d+$", (nxt < 10 and "0" or "") .. tostring(nxt)) end end if not IsValidEntity(nxtE) then nxtE = curE nxt = -1 end end if self.subvariant ~= nxt then self.subvariant = nxt self:ChangeEntity(nxtE) ObjModified(self) return true end return false end function EditorSubVariantObject:ResetSubvariant() self.subvariant = -1 end function EditorSubVariantObject.OnShortcut(delta) local sel = editor.GetSel() if sel and #sel > 0 then XEditorUndo:BeginOp{ objects = sel } for i = 1, #sel do if IsKindOf(sel[i], "EditorSubVariantObject") then sel[i]:CycleEntity(delta) end end XEditorUndo:EndOp(sel) end end function CycleObjSubvariant(obj, dir) if IsKindOf(obj, "EditorSubVariantObject") then obj:CycleEntity(dir) else local class = obj.class local num = tonumber(class:sub(-2, -1)) if num then local list = {} for i = 0, 99 do local class_name = class:sub(1, -3) .. (i <= 9 and "0" or "") .. tostring(i) if g_Classes[class_name] and IsValidEntity(g_Classes[class_name]:GetEntity()) then list[#list + 1] = class_name end end local idx = table.find(list, class) + dir if idx == 0 then idx = #list elseif idx > #list then idx = 1 end obj = editor.ReplaceObject(obj, list[idx]) end end return obj end