Funny you should say that, it is a Church, I pinched it from another nation, can't remember which one, just modified it a bit.
Thank you Ebel, I've just made some minor upgrades and attached suitable underlayers. My last question for a while is on "drawing multiple meshes from the same prop file". You mean directly (for ukranian house) ukrhou.prop file? Since I'm not acquainted what this file is exactly doing (I can only see it's doing something with already spoken meshes and collisons) I need a small help here where should be mesh-decision put. EDIT: I foud it by myself. It's in ukrhou.actor: Code: ActorList.Items[0].LODList.Items[0].MeshObjects.LoadFromFile = .\data\actors\buildings\ukr\building i want to load But still if you have a time to navigate me a little bit, I'm taking evey piece of advice. PS: Only the existence of all-mighty Ebel brought me the anwser.
You are close, but it will take a bit more than just that. Maybe rather than just show how, I should guide a bit, this will teach more than just giving the answer. The clue for anything that isn't there but can be done is usually in the .ref (reference) files. Reference files prevent that .actor, .prop, .lib, .mat etc... files are cluttered with all possible options from the engine making them hard to read. You can also easily overwrite these .ref file options, simply by defining them in the file. Unless you specifically define an option, it will take it from the reference file. So in ukrhou.actor, you will see on top: {refurl=.\data\actors\ref\refbuilding.actor}, which if you look into , refers itself to {refurl=.\data\actors\ref\refobj.actor}. This one has a ton of available settings (to see all the available options for each setting, you have to run the editor.exe, place a building.unit ,select it and right click on it. A choice menu will open, If you choose PropertyEditor , it will take you to whatever is currently setup, just that, with some minor options for change. However if you pick FormEditActor here, it will take you to the actual actor editor with all options available. For example, you will see something called 'Reference', normally this would be aarNone for statics as option, but we know that it can also be aarMorph just by using the drop down button, or aarTransform. aarTranform would be used in conjunction with the Transformation frame list (.tfl) which can be loaded, something I used for my new Terrain mod, to make trees appear to move with the wind. Explaining all these options is beyond the point here and would take us too far. (If you choose save here, it would create an .actor file with all the stuff that it normally refers to in the .ref file, this ofcourse is a bit cluttered and much larger, harder to read.) Back to the .ref file now (refobj.actor) This is the important part: Code: ActorList.Items[0] : struct.begin Name = LODList.Items[0] : struct.begin ScaleFrames = 1 DistanceMin = 0 DistanceMax = 150 FrameInterpolation = afpNone TangentSpace = False TangentSpaceFake = False BinormalsTexCoordIndex = 3 TangentsTexCoordIndex = 4 WeightsTexCoordIndex = 1 MatIndicesTexCoordIndex = 2 TangentSpaceFileName = MeshObjects.LoadFromFile = struct.end ImposterBuilder : struct.begin Impostored = False ImposterFrame = 0 struct.end struct.end From this part only 4 things really matter ActorList.items[0] Name = LODList.Items[0] MeshObjects.LoadFromFile = Actor list and Lodlist bring structure/hierarchy, name gives the mesh a name to call on in the .prop file, and load from file defines which .osm/.oss to load. Here is an example from my Terrain Mod with a tree. (You can do this with units too) Code: //************************************* Willow Tree ******* section.begin {refurl=.\data\actors\ref\reftree.actor} AnimationMode = aamLoop FrameInterpolation = afpNone Reference = aarTransform Animations.LoadFromFile = .\data\animations\aaf\trees\willow\willow.aaf TransformationFrameList.LoadFromFile = .\data\tlf\trees\willow\willow.tlf ActorList.Items[0].Name = willow.large.mesh ActorList.Items[0].LODList.Items[0].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.large\willow.large.1.osm ActorList.Items[0].LODList.Items[1].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.large\willow.large.1.1.osm ActorList.Items[0].LODList.Items[2].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.large\willow.large.1.2.osm ActorList.Items[1] : struct.begin {refurl=.\data\actors\ref\refstone.actor; refkey=.ActorList.Items[0]} Name = willow.medium.mesh LODList.Items[0].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.medium\willow.medium.1.osm LODList.Items[1].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.medium\willow.medium.1.1.osm LODList.Items[2].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.medium\willow.medium.1.2.osm struct.end ActorList.Items[2] : struct.begin {refurl=.\data\actors\ref\refstone.actor; refkey=.ActorList.Items[0]} Name = willow.small.mesh LODList.Items[0].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.small\willow.small.1.osm LODList.Items[1].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.small\willow.small.1.1.osm LODList.Items[2].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.small\willow.small.1.2.osm struct.end ActorList.Items[3] : struct.begin {refurl=.\data\actors\ref\refstone.actor; refkey=.ActorList.Items[0]} Name = willow.dead.mesh LODList.Items[0].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.dead\willow.dead.1.osm LODList.Items[1].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.dead\willow.dead.1.1.osm LODList.Items[2].MeshObjects.LoadFromFile = .\data\actors\env\trees\willow\willow.dead\willow.dead.1.2.osm struct.end section.end What we have here are 4 type of willow trees (dead, small, medium and large) and each type has 3 variants which all look slightly different. Pay good attention to the actor list items numbering , it starts with 0, and the LodListItems each have numbers to. Now, lets have a look at the .prop file, which is where you decide what is to be used in game. Code: actorproperty : section.begin {refurl=.\data\objects\ref\refenv.prop; refkey=actorproperty} LODActorName = willow DefaultMeshName = willow.large.mesh RandomMeshName = True UseableMeshes : struct.begin [0] = True [1] = True [2] = True [3] = True struct.end section.end The numbers here refer to the ActorListItems, and by setting 'randommeshName' to True, it will randomly place one of the 12 meshes. Besides having variety in mesh, I also do a random roll (rotation) which all contributes to the variety on placement, as opposed to everything looking the same , and this is the entire point of this excercise. Sadly doing random rolls on buildings works less good, unless you have an almost perfect square footprint (because of hitbox & collision issues). Next, and here is where it might get a bit confusing: textures, and build stages. Continuing with the sample of the tree, Code: materialproperty : section.begin {refurl=.\data\objects\ref\refenv.prop; refkey=materialproperty} Mesh : struct.begin [0] : struct.begin Enabled = False Static = False ClassName = MeshMaterialProperty DefaultMaterialName = willow.summer RandomMaterialName = False UseableMaterials : struct.begin [0] = willow.summer [1] = willow.dark struct.end UseSeasonMaterial = True UseableSummerMaterials : struct.begin [0] = willow.summer [1] = willow.dark struct.end UseableAutumnMaterials : struct.begin [0] = willow.autumn [1] = willow.dark struct.end UseableWinterMaterials : struct.begin [0] = willow.winter [1] = willow.dark struct.end UseableSpringMaterials : struct.begin [0] = willow.spring [1] = willow.dark struct.end struct.end [1] : struct.begin {refkey=materialproperty.Mesh[0]} DefaultMaterialName = willow.summer RandomMaterialName = False UseableMaterials[0] = willow.summer UseableMaterials[1] = willow.dark UseSeasonMaterial = True UseableSummerMaterials : struct.begin [0] = willow.summer [1] = willow.dark struct.end UseableAutumnMaterials : struct.begin [0] = willow.autumn [1] = willow.dark struct.end UseableWinterMaterials : struct.begin [0] = willow.winter [1] = willow.dark struct.end UseableSpringMaterials : struct.begin [0] = willow.spring [1] = willow.dark struct.end struct.end [2] : struct.begin {refkey=materialproperty.Mesh[0]} DefaultMaterialName = willow.summer RandomMaterialName = False UseableMaterials[0] = willow.summer UseableMaterials[1] = willow.dark UseSeasonMaterial = True UseableSummerMaterials : struct.begin [0] = willow.summer [1] = willow.dark struct.end UseableAutumnMaterials : struct.begin [0] = willow.autumn [1] = willow.dark struct.end UseableWinterMaterials : struct.begin [0] = willow.winter [1] = willow.dark struct.end UseableSpringMaterials : struct.begin [0] = willow.spring [1] = willow.dark struct.end struct.end [3] : struct.begin {refkey=materialproperty.Mesh[0]} DefaultMaterialName = willow.summer RandomMaterialName = False UseableMaterials[0] = willow.summer UseableMaterials[1] = willow.dark UseSeasonMaterial = True UseableSummerMaterials : struct.begin [0] = willow.summer [1] = willow.dark struct.end UseableAutumnMaterials : struct.begin [0] = willow.autumn [1] = willow.dark struct.end UseableWinterMaterials : struct.begin [0] = willow.winter [1] = willow.dark struct.end UseableSpringMaterials : struct.begin [0] = willow.spring [1] = willow.dark struct.end struct.end struct.end section.end The [number] under mesh refers to the UseableMeshes : struct.begin [0] = True [1] = True [2] = True [3] = True struct.end in actorproperty above it. You have to define texture materials for each mesh. Besides season materials, as you can see here you can make things even more complicated by using random materials here, making the game choose a different skin. Which is what I'm doing here for example in a test knight from my current mod I'm working on: Code: {refurl=.\data\objects\ref\refunit.prop} stringproperty : section.begin Enabled = True Static = True ClassName = StringProperty CategorieName = Mod | Master | France.Kingdom Description[*] = Basic knight with random french duchy skins. Repeat of france.knight makes it appear more. section.end mainproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=mainproperty} CustomName = france.inf.knight.2 BaseName = france.inf.knight.2 section.end actorproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=actorproperty} LODActorName = base.inf.knight.1 DefaultMeshName = base.inf.knight.1.mesh section.end section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=materialproperty} Enabled = True Static = True ClassName = MaterialProperty Mesh : struct.begin [0] : struct.begin Enabled = True Static = False ClassName = MeshMaterialProperty DefaultMaterialName = france.knight RandomMaterialName = True UseableMaterials : struct.begin [*] = anjou.knight [*] = artois.knight [*] = beaujeu.knight [*] = bethune.knight [*] = burgundy.knight [*] = chatillon.knight [*] = clerey.knight [*] = corbeil.knight [*] = cousances.knight [*] = dreux.knight [*] = fr.montfort.knight [*] = france.knight [*] = guerin.knight [*] = luxembourg.knight [*] = poitiers.knight [*] = france.knight [*] = france.knight [*] = france.knight [*] = france.knight [*] = france.knight [*] = france.knight [*] = france.knight [*] = france.knight [*] = france.knight struct.end UseSeasonMaterial = False struct.end struct.end section.end frameanimationproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=frameanimationproperty} FrameAnimationCyclesLibName = base.inf.knight.1 section.end autochildrenproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=autochildrenproperty} Enabled = True Mesh[0] : struct.begin Children : struct.begin [0] : struct.begin BaseName = france.inf.knight.helm.2 RaceName = units DefaultMeshName = base.inf.knight.helm.2.mesh RandomMeshName = True Mesh : struct.begin [*] = base.inf.knight.helm.1.mesh [*] = base.inf.knight.helm.2.mesh [*] = base.inf.knight.helm.3.mesh [*] = base.inf.knight.helm.4.mesh [*] = base.inf.knight.helm.5.mesh [*] = base.inf.knight.helm.6.mesh struct.end DefaultMaterialName = france.knight RandomMaterialName = True Materials[0] = anjou.knight Materials[1] = artois.knight Materials[2] = beauchamp.knight Materials[3] = bethune.knight Materials[4] = burgundy.knight Materials[5] = chatillon.knight Materials[6] = clerey.knight Materials[7] = corbeil.knight Materials[8] = france.knight Materials[9] = luxembourg.knight Materials[10] = france.knight Materials[11] = france.knight Materials[12] = france.knight Materials[13] = france.knight Materials[14] = france.knight Materials[15] = france.knight Useable = True struct.end [1] : struct.begin BaseName = base.inf.knight.sword.1 RaceName = units DefaultMeshName = base.inf.knight.sword.1.mesh Mesh[*] = base.inf.knight.sword.1.mesh DefaultMaterialName = france.knight Materials[*] = france.knight Useable = True struct.end [2] : struct.begin BaseName = base.inf.knight.sheath.1 RaceName = units DefaultMeshName = base.inf.knight.sheath.1.mesh Mesh[*] = base.inf.knight.sheath.1.mesh DefaultMaterialName = france.knight Materials[*] = france.knight Useable = True struct.end [3] : struct.begin BaseName = base.inf.knight.shield.1 RaceName = units DefaultMeshName = base.inf.knight.shield.1.mesh Mesh[*] = base.inf.knight.shield.1.mesh DefaultMaterialName = france.shield.knight RandomMaterialName = True Materials[0] = anjou.shield.knight Materials[1] = artois.shield.knight Materials[2] = burgundy.shield.knight Materials[3] = dreux.shield.knight Materials[4] = france.shield.knight Materials[5] = poitiers.shield.knight Materials[6] = france.shield.knight Materials[7] = france.shield.knight Materials[8] = france.shield.knight Materials[9] = france.shield.knight Materials[10] = france.shield.knight Materials[11] = france.shield.knight Useable = True struct.end struct.end struct.end section.end section.begin enabled = true static = true classname = scaleproperty defaultscale : struct.begin x = 0.0950 y = 0.0950 z = 0.0950 struct.end randomscale = True minscalefactor = 0.9 maxscalefactor = 1.1 defaultscalefactor = 1 section.end In this case I'm not using multiple meshes for the main object, but multiple meshes for one of the attachments (autochildren)(base.inf.knight.helm.2.mesh), which in turn uses different textures, so each time I place a unit down in the editor from this .prop file, i get a different looking unit, like this: https://imgur.com/KGuBZgx Spoiler Now, with buildstages for the houses in mind in the autochildren, I would suggest you take it slow and easy at first. I have not ever tried this with houses as I suggested, but I know it's possible because the engine supports the options, as I'v shown with the trees and knight sample. You will have errors at first, this isn't as easy as it seems, it took me a while to get the hang of this as well. What I suggest you do is, use the same mesh initially but rotate it 180 or so, then add it to the .actor file and .prop file and see if you can get it to load at all in the editor without errors and if indeed it randomly picks between the 2, then you can make it more complicated should you wish to do so. If something is not clear or you get stuck, just ask or hit me on discord (or in pm.) PS. random thought: I went from the assumption here, that the new house mesh will have the same footprint. Otherwise it might get messy with the collision mask, hitbox and what not. But lets assume for some reason , you were to have a second house drawn with a different shape, then I would suggest to, 1) look into using the decal as the main object, and the actual building and it's stages as an autochild (might be too complex this), set the decal to fit the largest box needed for collission (or) 2) just set the collision mask to fit the largest house. (or) 3) find a creative solution we haven't though about yet...
Dear Ebel, after some time I tried to implement simple texture on the serdiuk unit (since it's more simple than starting with whole objects). I tired to implement new .dds files with different colour of hats, belts etc. Sadly every time I tired to load the mesh in the game, something slip out of my hands and mesh doesn't load. At best it only wipe out the colour of player and a formation will become mixture of coloured units and white units (meaning of coats, other parts are properly dyed). Please, if you will have a time, can you control my workflow? (I'm definitely missing something and since I'm not a programmed by work, I can't see it) 1) Having new .dds textures in ...materials/units (done, easy) 2) Prepare to open files: refunit.prop, serdiuk.prop, units.mat (since only these influence the material of the unit (or they didn't ?)) 3) Implement parts of codes in files In refunit.prop make a change in actorproperty (or not? since I'm using only Mesh[0]?) and materialproperty. Add UsebaleMaterials, set them Ture, RandomMeshName = True Code: actorproperty : section.begin Enabled = True Static = True ClassName = ActorProperty LODActorName = RandomMeshName = True DefaultMeshName = UseParentTLFToPosition = False UseableMeshes : struct.begin [0] = True [1] = True [2] = True [3] = True struct.end section.end materialproperty : section.begin Enabled = True Static = True ClassName = MaterialProperty Mesh[0] : struct.begin Enabled = True Static = False ClassName = MeshMaterialProperty DefaultMaterialName = RandomMaterialName = True UseableMaterials[0] = UseableMaterials[1] = UseableMaterials[2] = UseableMaterials[3] = UseSeasonMaterial = False struct.end section.end In serdiuk.prop applied these material (in only one mesh, different materials) Code: {refurl=.\data\objects\ref\refunit.prop} mainproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=mainproperty} CustomName = serdiuk BaseName = serdiuk section.end actorproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=actorproperty} LODActorName = serdiuk DefaultMeshName = serdiuk.mesh section.end materialproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=materialproperty} Mesh[0].DefaultMaterialName = serdiuk Mesh[0].UseableMaterials[0] = serdiuk Mesh[0].UseableMaterials[1] = serdiuk1 Mesh[0].UseableMaterials[2] = serdiuk2 Mesh[0].UseableMaterials[3] = serdiuk3 section.end frameanimationproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=frameanimationproperty} FrameAnimationCyclesLibName = serdiuk section.end In units.mat add path to new .dss files PROBLEM: every time I implement this, whole serdiuk mesh goes black Code: section.begin {refurl=.\data\materials\ref\refunit.mat} Material.Name = serdiuk Material.Texture.image = .\data\materials\units\serdiuk.dds section.end section.begin {refurl=.\data\materials\ref\refunit.mat} Material.Name = serdiuk1 Material.Texture.image = .\data\materials\units\serdiuk1.dds section.end section.begin {refurl=.\data\materials\ref\refunit.mat} Material.Name = serdiuk2 Material.Texture.image = .\data\materials\units\serdiuk2.dds section.end section.begin {refurl=.\data\materials\ref\refunit.mat} Material.Name = serdiuk3 Material.Texture.image = .\data\materials\units\serdiuk3.dds section.end When I implement materials already contained in game, everything works and the unit have different materials (even If they didn't fit) Example: Code: materialproperty : section.begin {refurl=.\data\objects\ref\refunit.prop; refkey=materialproperty} Mesh[0].DefaultMaterialName = serdiuk Mesh[0].UseableMaterials[0] = serdiuk Mesh[0].UseableMaterials[1] = musketeer Mesh[0].UseableMaterials[2] = jannisary Mesh[0].UseableMaterials[3] = strelet section.end QUESTIONS: It there a problem in my .dss files or units.mat somewhere? What am I missing? Must I also enabled meshes and material in autochildrenproperty? I hope it wouln't consume much of your time.
What exactly are you trying to do Johny, are you just trying to change the appearance of the Serdiuk unit.
Exactly, I'm not trying to change object itself (this will come later), only appearance. I created 3 (4 total) types of visage, that should be randomly placed on the unit (after coming from barracks), thus I would get a diverse formation. The main problrem is, of course, I suck at it. (if you know some hotfixes, you can contact me on Discord)
SOLVED: (All credits to Ebel all mighty) - Workflow - 1) prepare files: serdiuk.prop, units.mat, your_painted_serdiuk.dds 2) In serdiuk.prop file replace materialproperty section Code: materialproperty : section.begin Enabled = True Static = True ClassName = MaterialProperty Mesh[0] : struct.begin Enabled = True Static = False ClassName = MeshMaterialProperty DefaultMaterialName = serdiuk RandomMaterialName = True UseableMaterials[0] = serdiuk UseableMaterials[1] = serdiuk1 UseableMaterials[2] = serdiuk2 UseableMaterials[3] = serdiuk3 UseSeasonMaterial = False struct.end section.end This means you created 3 additional .dds textures that will be used (by RandomMaterialName setted on True) 3) In units.mat file ADD these lines: Code: section.begin {refurl=.\data\materials\ref\refunit.mat} Material.Name = serdiuk1 Material.Texture.image = .\data\materials\units\serdiuk1.dds section.end section.begin {refurl=.\data\materials\ref\refunit.mat} Material.Name = serdiuk2 Material.Texture.image = .\data\materials\units\serdiuk2.dds section.end section.begin {refurl=.\data\materials\ref\refunit.mat} Material.Name = serdiuk3 Material.Texture.image = .\data\materials\units\serdiuk3.dds section.end Means you basically created a path from .dds files to serdiuk.prop 4) put serdiuk1.dds, serdiuk1.dds.....serdiukN.dds into materials/units (depends how many textures you have) TIPS AND TRICKS Do not change ref files! There are only for units overall, not for the individual one. If you are working in Photoshop CS6, don't forget to flattern you image before saving. Since these files contains Alpha Channel, save it to DTX5 (If there is an alpha channel : save to DXT 5. If there is no alpha channel: DXT 1) If you want to see some quick and visible result, use some unit that is not completley covered in Alpha Channel (player colour, grey zones in Photoshop), otherwise you will get barely visible differences (like me). And since it's modern: Enjoy your diversity