New Buildings

Discussion in 'Modding' started by Hugojackson18, Oct 5, 2016.

1. EbelModeratorStaff Member

data\terrain\decals\buildings

nice work btw.

Johny likes this.
2. LonerActive Member

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.

Johny likes this.
3. JohnyMember

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.

Last edited: Nov 9, 2019
4. EbelModeratorStaff Member

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 =
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]

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
ActorList.Items[0].Name = willow.large.mesh
ActorList.Items[1] : struct.begin {refurl=.\data\actors\ref\refstone.actor; refkey=.ActorList.Items[0]}
Name = willow.medium.mesh
struct.end
ActorList.Items[2] : struct.begin {refurl=.\data\actors\ref\refstone.actor; refkey=.ActorList.Items[0]}
Name = willow.small.mesh
struct.end
ActorList.Items[3] : struct.begin {refurl=.\data\actors\ref\refstone.actor; refkey=.ActorList.Items[0]}
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

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...

Last edited: Nov 10, 2019
Johny and Loner like this.
5. JohnyMember

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.

Last edited: Nov 30, 2019
6. LonerActive Member

What exactly are you trying to do Johny, are you just trying to change the appearance of the Serdiuk unit.

Johny likes this.
7. JohnyMember

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)

8. LonerActive Member

Sorry Johny, I'm only good, well reasonable, at the art work involved.

9. JohnyMember

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

Last edited: Dec 1, 2019
yquinox, Loner and Ebel like this.
10. LonerActive Member

Great stuff Johny.