So - I have seen over the last few months an increasing interest in Continuous Integration and Neverwinter Nights.
I have just finished getting a more advanced model of the one I had previously setup - so its fresh in my mind - I might as well share.
Objective:
I want to have a system in place that allows a team of script editors, content creators work together and submit content for the PW Server. That content is then automatically compiled and deployed to a target server triggering a restart of nwserver.
This is particularly good for dev servers - where you wish to deploy rapidly to test content before deploying to a master / live server.
What you need (What I used)
2 Linux Servers:
I used 1 Ubuntu server for Jenkins (the continuous Integration being shown here)
and 1 Ubuntu server (originally a 32bit Paravirtual server, which was then migrated to 64bit hardware (hypervirtual))
The significance of that 32bit being migrated later to 64bit is more around nwnx compatibility.
It seems that if you install all the pre-requisites for nwnx compilation while it is 32bit, then migrate to 64bit, it allows compilation under 64bit - as long as you comment out the checks in the compile scripts.
These servers are both T2 Micro (from Amazon AWS / EC2 - you can run one of them for free for a whole year when you sign up to AWS, the other one only costs about 14 dollars per month)
Note: It is very likely that a nwserver process and jenkins can coexist on the same machine - however: from an infrastructure point of view - and a dev-ops point of view, I am meant to say 'that is a bad practice'
But - on this occasion, you could probably live with it - as its a game after all.
Feel free to go with the cheaper option of using a single server to host both.
Software needed:
Jenkins
Plugins: Ant Plugin (plus Ant - if it isn't installed automatically)
Publish over ssh plugin
NWN Ant Tools:
http://sourceforge.n...nt.zip/download
(The jar files need to be installed local to the ant executable on your jenkins server)
Example usage of the ERFPacker tool from the ant tools can be seen here:
http://nwntools.sour....html#erfpacker
Subversion / GIT:
Whichever version control you feel better working in.
An Installation of NWN or NWN Dedicated server on the Jenkins server : so it can reference the nwscript symbols etc (for script compiling)
Note:
If working in EC2 (Amazon) : you will need to know the SSH key required to connect remotely to the intended dev/test server for nwserver.
Lets get started:
First we need to examine what the module file structure consists of
When you have a module open : its contents are all visible inside the temp0 folder within your modules directory.
The problem from a dev-ops point of view, is that this enormous mass of files is just not user friendly.
Insisting that a large team of people copy and paste all the correct files into an SVN folder and get it right 100% of the time is unrealistic.
Lets make things simpler.
Before we start: you need to have a Source Control repo ready: Just start from a blank template.
(I am using SVN)
Inside your blank folder:
create the following directories
are
dlg
gic
git
hak (optional)
ifo
jrl
modules (optional)
ncs
nss
srcs (optional)
utc
uti
utp
utw
hak is a folder I tend to put something like cep2_build.hak into - the likelyhood of it changing is low.
Optionally, I could actually have the content of cep2_build.hak in that folder - and include those resources in the build process.
modules - I create this folder in the source control to save me having to create it via the jenkins build task - this is where my module will be wrote to when built.
srcs - this is an intermediary folder: compiled ncs files are copied here,as well as the content from the other directories (minus nss) - content in this folder is then turned into a module, which then copies to modules.
Once you have that folder structure : you might want to make a batch file (windows batch) that can help automate the copying of files into your svn.
I use the following:
for /R E:\VampireDawn\are %%f in (*.are) do del %%f
for /R E:\VampireDawn\dlg %%f in (*.dlg) do del %%f
for /R E:\VampireDawn\gic %%f in (*.gic) do del %%f
for /R E:\VampireDawn\git %%f in (*.git) do del %%f
for /R E:\VampireDawn\ifo %%f in (*.ifo) do del %%f
for /R E:\VampireDawn\jrl %%f in (*.jrl) do del %%f
for /R E:\VampireDawn\nss %%f in (*.nss) do del %%f
for /R E:\VampireDawn\utc %%f in (*.utc) do del %%f
for /R E:\VampireDawn\uti %%f in (*.uti) do del %%f
for /R E:\VampireDawn\utp %%f in (*.utp) do del %%f
for /R E:\VampireDawn\utw %%f in (*.utw) do del %%f
for /R E:\VampireDawn\hak %%f in (*.hak) do del %%f
timeout 5
for /R E:\NeverwinterNights\hak %%f in (cep2_build.hak) do copy %%f E:\VampireDawn\hak
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.are) do copy %%f E:\VampireDawn\are
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.dlg) do copy %%f E:\VampireDawn\dlg
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.gic) do copy %%f E:\VampireDawn\gic
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.git) do copy %%f E:\VampireDawn\git
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.ifo) do copy %%f E:\VampireDawn\ifo
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.jrl) do copy %%f E:\VampireDawn\jrl
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.nss) do copy %%f E:\VampireDawn\nss
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.utc) do copy %%f E:\VampireDawn\utc
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.uti) do copy %%f E:\VampireDawn\uti
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.utp) do copy %%f E:\VampireDawn\utp
for /R E:\NeverwinterNights\Nosgoth_Module\temp0 %%f in (*.utw) do copy %%f E:\VampireDawn\utw
Basically - I delete any of the files that are in the svn local repo - then I copy the files into directories depending on their file type.
This takes care of content that you may want to remove from the server at a later time.
Eg: Deleting then committing will remove it from the jenkins build.
So - Me running the above batch will automate the copying of content from temp0 to my svn repository.
I then just have to right click and commit and write a nice comment about what I am committing.
One last file that we need: is an ant 'build.xml'
This should be in the root of your repo - outside of the folders we created.
The content I use is like this:
<project name="NWN Content Development" default="build" basedir=".">
<!-- Load some build.properties files so that users can customize
certain properties to their environment. ANT only uses the first
value encountered so any properties defined in these files will
override later settings.
See "build.properties.sample" in the top level directory for all
property values you must customize for successful building!!! -->
<property file="build.properties"/>
<property file="${user.home}/build.properties"/>
<!-- set global property defaults for this build -->
<property name="src" value="src"/>
<property name="build" value="build"/>
<property name="dist" value="dist"/>
<target name="init">
<!-- define some custom tasks used later-->
<taskdef name="nwnc" classname="org.progeeks.nwn.ant.CompileTask" />
<taskdef name="xmltogff" classname="org.progeeks.nwn.ant.XmlToGffTask" />
<taskdef name="erfpacker" classname="org.progeeks.nwn.ant.ErfPackerTask" />
<!-- Create the time stamp... and an additional formatted build time property -->
<tstamp>
<!-- Because I like to include the build time in my generated ERF file descriptions. -->
<format property="build.time" pattern="MM/dd/yyyy hh:mm aa" />
</tstamp>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
<mkdir dir="${build}/client"/>
<mkdir dir="${build}/server"/>
</target>
<target name="VampireDawn" description="Creates the Vampire Dawn module." depends="init" >
<!-- Generate the .mod file using the description from the module.ifo file. -->
<erfpacker basedir="srcs" erffile="modules/VampireDawn.mod" minGameVersion="1.69" expansionPacks="3">
<!--<include name="**/*.ncs" /> -->
</erfpacker>
</target>
<target name="build" description="Builds everything."
depends="VampireDawn" >
</target>
<target name="clean">
<!-- Delete the ${build} directory tree. -->
<delete dir="${build}"/>
</target>
</project>