From 9978c62b6d6e35fbdc180479eed2e14d5f2da721 Mon Sep 17 00:00:00 2001 From: Daniel Walder Date: Sat, 27 Jul 2013 11:54:24 +1000 Subject: [PATCH] 0.1.0.2 - Alpha release! Cordon compile support Updated tool icon set Check FGD file exists before loading it, fixes #2 Allow for nulls when no textures are loaded, fixes #1 Lots of bug fixes in the VM tool --- .../MapObjects/EntityData.cs | 11 +++ Sledge.Editor/Compiling/Batch.cs | 7 +- Sledge.Editor/Compiling/BatchCompileStep.cs | 1 + Sledge.Editor/Compiling/BatchCompiler.cs | 3 +- .../Documents/DocumentSubscriptions.cs | 63 ++++++++++++++---- Sledge.Editor/Logging/Logger.cs | 3 +- Sledge.Editor/Milestones.txt | 7 +- Sledge.Editor/Properties/AssemblyInfo.cs | 4 +- Sledge.Editor/Resources/Tool_Brush.png | Bin 533 -> 1765 bytes Sledge.Editor/Resources/Tool_Clip.png | Bin 572 -> 2132 bytes Sledge.Editor/Resources/Tool_Decal.png | Bin 521 -> 2586 bytes Sledge.Editor/Resources/Tool_Entity.png | Bin 791 -> 1511 bytes Sledge.Editor/Resources/Tool_Select.png | Bin 255 -> 1795 bytes Sledge.Editor/Resources/Tool_Texture.png | Bin 5412 -> 1920 bytes Sledge.Editor/Resources/Tool_VM.png | Bin 385 -> 1416 bytes Sledge.Editor/Settings/SettingsForm.cs | 5 +- Sledge.Editor/Tools/DecalTool.cs | 9 ++- Sledge.Editor/Tools/TextureApplicationForm.cs | 5 ++ Sledge.Editor/Tools/VMTool.cs | 19 ++++-- Sledge.Editor/UI/EntityEditor.designer.cs | 4 +- Sledge.Editor/Visgroups/VisgroupPanel.cs | 1 + Sledge.Providers/GameData/GameDataProvider.cs | 14 ++-- Sledge.Providers/Map/MapFormatProvider.cs | 12 +++- Sledge.Settings/Models/Game.cs | 1 - 24 files changed, 127 insertions(+), 42 deletions(-) diff --git a/Sledge.DataStructures/MapObjects/EntityData.cs b/Sledge.DataStructures/MapObjects/EntityData.cs index 989de7be0..99d24b1f8 100644 --- a/Sledge.DataStructures/MapObjects/EntityData.cs +++ b/Sledge.DataStructures/MapObjects/EntityData.cs @@ -43,5 +43,16 @@ public string GetPropertyValue(string key) var prop = Properties.FirstOrDefault(x => String.Equals(key, x.Key, StringComparison.InvariantCultureIgnoreCase)); return prop == null ? null : prop.Value; } + + public void SetPropertyValue(string key, string value) + { + var prop = Properties.FirstOrDefault(x => String.Equals(key, x.Key, StringComparison.InvariantCultureIgnoreCase)); + if (prop == null) + { + prop = new Property { Key = key}; + Properties.Add(prop); + } + prop.Value = value; + } } } diff --git a/Sledge.Editor/Compiling/Batch.cs b/Sledge.Editor/Compiling/Batch.cs index c8425b73e..328fe47fd 100644 --- a/Sledge.Editor/Compiling/Batch.cs +++ b/Sledge.Editor/Compiling/Batch.cs @@ -12,23 +12,26 @@ public class Batch public string BeforeExecuteStep { get; set; } public string AfterExecuteStep { get; set; } public string TargetFile { get; set; } + public string OriginalFile { get; set; } - public Batch(Game game, string targetFile) + public Batch(Game game, Build build, string targetFile, string originalFile) { // TODO: this properly - var build = game.Build; BeforeExecute = ""; AfterExecute = ""; BeforeExecuteStep = ""; AfterExecuteStep = ""; TargetFile = targetFile; var fileFlag = '"' + targetFile + '"'; + var bspFile = '"' + Path.ChangeExtension(targetFile, "bsp") + '"'; + var copyBsp = '"' + Path.ChangeExtension(originalFile, "bsp") + '"'; Steps = new List { new BatchCompileStep { Operation = Path.Combine(build.Path, build.Csg), Flags = fileFlag }, new BatchCompileStep { Operation = Path.Combine(build.Path, build.Bsp), Flags = fileFlag }, new BatchCompileStep { Operation = Path.Combine(build.Path, build.Vis), Flags = fileFlag }, new BatchCompileStep { Operation = Path.Combine(build.Path, build.Rad), Flags = fileFlag }, + new BatchCompileStep { Operation = "move", SystemCommand = true, Flags = bspFile + " " + copyBsp } //new BatchCompileStep { Operation = "copy"} }; } diff --git a/Sledge.Editor/Compiling/BatchCompileStep.cs b/Sledge.Editor/Compiling/BatchCompileStep.cs index 9c18fc1e0..a7832b08a 100644 --- a/Sledge.Editor/Compiling/BatchCompileStep.cs +++ b/Sledge.Editor/Compiling/BatchCompileStep.cs @@ -8,6 +8,7 @@ namespace Sledge.Editor.Compiling public class BatchCompileStep { public string Operation { get; set; } + public bool SystemCommand { get; set; } public string Flags { get; set; } public string BeforeExecute { get; set; } public string AfterExecute { get; set; } diff --git a/Sledge.Editor/Compiling/BatchCompiler.cs b/Sledge.Editor/Compiling/BatchCompiler.cs index 6e89f0e1e..a8e857cc3 100644 --- a/Sledge.Editor/Compiling/BatchCompiler.cs +++ b/Sledge.Editor/Compiling/BatchCompiler.cs @@ -16,7 +16,8 @@ public static void Compile(Batch batch) { script.AppendLine(batch.BeforeExecuteStep); script.AppendLine(step.BeforeExecute); - script.Append('"').Append(step.Operation).Append('"').Append(' ').AppendLine(step.Flags); + var cq = step.SystemCommand ? "" : "\""; + script.Append(cq).Append(step.Operation).Append(cq).Append(' ').AppendLine(step.Flags); script.AppendLine(step.AfterExecute); script.AppendLine(batch.AfterExecuteStep); } diff --git a/Sledge.Editor/Documents/DocumentSubscriptions.cs b/Sledge.Editor/Documents/DocumentSubscriptions.cs index bd18e7256..ad4d425d7 100644 --- a/Sledge.Editor/Documents/DocumentSubscriptions.cs +++ b/Sledge.Editor/Documents/DocumentSubscriptions.cs @@ -238,23 +238,60 @@ public void FileSaveAs() public void FileCompile() { FileSave(); - var currentFile = _document.MapFile; - if (currentFile == null) return; - if (!currentFile.EndsWith("map")) + if (_document.MapFile == null) return; + + var tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(tempDir); + + _document.Map.WorldSpawn.EntityData.Properties.Add(new Property { - _document.Map.WorldSpawn.EntityData.Properties.Add(new Property - { - Key = "wad", - Value = string.Join(";", _document.Game.Wads.Select(x => x.Path)) - }); - var map = Path.ChangeExtension(_document.MapFile, "map"); - MapProvider.SaveMapToFile(map, _document.Map); - currentFile = map; - } - var batch = new Batch(_document.Game, currentFile); + Key = "wad", + Value = string.Join(";", _document.Game.Wads.Select(x => x.Path)) + }); + var map = Path.Combine(tempDir, Path.GetFileNameWithoutExtension(_document.MapFile) + ".map"); + SaveWithCordon(map); + + var build = SettingsManager.Builds.FirstOrDefault(x => x.ID == _document.Game.BuildID); + var batch = new Batch(_document.Game, build, map, _document.MapFile); BatchCompiler.Compile(batch); } + private void SaveWithCordon(string file) + { + var map = _document.Map; + if (_document.Map.Cordon) + { + map = new Map(); + map.WorldSpawn.EntityData = _document.Map.WorldSpawn.EntityData.Clone(); + var entities = _document.Map.WorldSpawn.GetAllNodesContainedWithin(_document.Map.CordonBounds); + foreach (var mo in entities) + { + var clone = mo.Clone(); + clone.SetParent(map.WorldSpawn); + } + var outside = new Box(map.WorldSpawn.Children.Select(x => x.BoundingBox).Union(new[] {_document.Map.CordonBounds})); + outside = new Box(outside.Start - Coordinate.One, outside.End + Coordinate.One); + var inside = _document.Map.CordonBounds; + + var brush = new Brushes.BlockBrush(); + + var cordon = (Solid) brush.Create(map.IDGenerator, outside, null).First(); + var carver = (Solid) brush.Create(map.IDGenerator, inside, null).First(); + cordon.Faces.ForEach(x => x.Texture.Name = "BLACK"); + + // Do a carve (TODO: move carve into helper method?) + foreach (var plane in carver.Faces.Select(x => x.Plane)) + { + Solid back, front; + if (!cordon.Split(plane, out back, out front, map.IDGenerator)) continue; + front.SetParent(map.WorldSpawn); + cordon = back; + } + + } + MapProvider.SaveMapToFile(file, map); + } + public void OperationsCopy() { if (!_document.Selection.IsEmpty() && !_document.Selection.InFaceSelection) diff --git a/Sledge.Editor/Logging/Logger.cs b/Sledge.Editor/Logging/Logger.cs index 591834026..2b6cbec58 100644 --- a/Sledge.Editor/Logging/Logger.cs +++ b/Sledge.Editor/Logging/Logger.cs @@ -14,7 +14,8 @@ public static void ShowException(Exception ex, string message = "") { var info = new ExceptionInfo(ex, message); var window = new ExceptionWindow(info); - window.Show(Editor.Instance); + if (Editor.Instance == null || Editor.Instance.IsDisposed) window.Show(); + else window.Show(Editor.Instance); } } diff --git a/Sledge.Editor/Milestones.txt b/Sledge.Editor/Milestones.txt index f295f1c1f..5a73b467b 100644 --- a/Sledge.Editor/Milestones.txt +++ b/Sledge.Editor/Milestones.txt @@ -3,15 +3,16 @@ Priorities Bugs Windows 7 recent file jump list not opening files + Clip tool is laggy + Recent files menu -> open files Enhancements (Empty) Features - Cordon compile - Recent files menu -> open files + (Post-alpha) Post-Alpha Priorities TDI - Advanced compiling + Advanced/proper compiling Texture loader refactor Models Autosaving diff --git a/Sledge.Editor/Properties/AssemblyInfo.cs b/Sledge.Editor/Properties/AssemblyInfo.cs index c3d3bfac2..c3307e158 100644 --- a/Sledge.Editor/Properties/AssemblyInfo.cs +++ b/Sledge.Editor/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.0.1")] -[assembly: AssemblyFileVersion("0.1.0.1")] +[assembly: AssemblyVersion("0.1.0.2")] +[assembly: AssemblyFileVersion("0.1.0.2")] diff --git a/Sledge.Editor/Resources/Tool_Brush.png b/Sledge.Editor/Resources/Tool_Brush.png index a3eb83877376469dc21849c20570d353357eb327..cedee4ffbaf415966b176c95638b68d6404c3d69 100644 GIT binary patch delta 1748 zcmV;_1}piM1mz8oC4X~5NmK|32nc)#WQYI&010qNS#tmYbj$z%bj$&u-(;Nt0010x zMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK*cveTdd00v)4L_t(og~gX^j8#_^ z$A4?>bIvetm^%!j9fU+BYMUs*R4G*HL{dvX*oYca#Au0@4}WSDO#Rf5_@Sam3|~NM zwFwnTn>Jcg3-mQ9(H3Z(wm3YTY0A4W!vOPO?%aFN*~<^-+?jg^Iy@5NJ~=u2-m~}m z|JQ%5z4tm|X8b>!-t5F%HrzLR)!}V>??1R@UvA~1TW{8m+>8R>du!Wcx!E&U)z>!! zqQc1Vus?I?y??*#xNGeiGwb`G5m?drtJSmS-SX>POUv}gg&2k)s8dSj=|6jJchYVAb?X;WgJvQz*Y1!E&z%nAz}F9V0@zM zKhNywShvQ^E?kqq*Y6@P>^&?8CN27;Cl*55CYczXTrxrU3+1a(~rWe5gk`vQ;ZdRF zC*sU_4wSiR_AJ9g5x9hqE5&^CZ(}TcO(3k{L==02hB9^)0Rie81@Ga&KH*>Q2uqek zbaX&VL(EVXj!SnzEMK8JXB)x(FA}N3h^({)0 z7=N8F8vEZ2S$=mNcidj0z!>>LNKi3V0FP$?p^;jaca>QD*HIWUn4wrxfLKOSs#s4V zP|?glRjAJig;LB@JE3b|9pC+Wjybc3>Ggv|z6KRzNQyKwgJpdYcRn$QJ28rHcGyhC z;ZmWp(CMT^y+VQU8$c98h$5w?6?*$ecz<|v!cV^3&dR&y^BRXakK-H6XTh!uxZUqj zoR*Nxtid6um2H(bD@8@7An<{5fQe9F7f`f>jk|i-_jVhbAH0Llcn_QY$;i2Wq_u${ z2ys^4ttav$CE-wYRiA1`dGG>isrvw8;5{hxUL1wdJQ7F-V;JDm z4ID_&vd`whk}HnqY64aXBo*Y1ED^vG5Wy+*3=DBOe;ESFd`v3@!>41je!4>#cq5sl zz*Rz!kr*eMfG-m>@PIee8KajA#DDoBs9@&PX&$@@KBa+~VU~B_-iON(mMxS(H4U zbVC;JF;%>!hna|=k}k?ngR<(rDg+`z@%;JjI6s!M7P7?g6XPulhxZ5`@qaNSNtS$q zk;XU;g-@qvSD*ofe4g%;z2|@-pt>FqkpO65;kO>vPc8a>^pQFBE(|8{H9cj4g*;ClI|JglT4nFrd&;=YfGhbDZWF!>0O_u%m z5%=*09pUtxs%n}Z72EU#fqyaLBt}%z3Lqm91R;SJ&R*=drw?|%v+m{JZ3PYhXMp~z zRz#DCM7Z2Na_{5{^XlGfnyo)$W?K!`QeZj{{iq(7OYq+w=G>&^WpYd0;Lf+ zoFpV7h=-n2?-n0@Z?U%vj>_GJ&f-yY6b4=e)a0nv@v qyQz=Uiu{-X$pQQ6IY`SwdT zOUz75+MOWx$q!bwIJyY;SFuI#YY#-$56U}mra`89FKh#{nQ}6;rxZdbK(Y z%nzU|H7PgP51I$}HY~vs0BQdq-XU&HRiDUc5zfy*a3U&UAR@-oV<6IuBAFL!U@-t= zvV!`bt&$$sise}j4kw4ec*0W&8hs^v1>Rti{FzF^7;|LR;fy( zQT*OGW&@~cg^_G!9*+M20DhZmBt}Db+L}BA5;$`2`!>ECBhbHV!;L6=2p+J~ku5Aj wQzIfYMTAjSrZFJmGe+(Ri0J@=kC_JM7t+@s+gdtaz5oCK07*qoM6N<$g3&k6E&u=k diff --git a/Sledge.Editor/Resources/Tool_Clip.png b/Sledge.Editor/Resources/Tool_Clip.png index b5dd5ec056fba4cd642022a6d4c8a4862d895436..1b84530cbe5e3c11c5bbd362c85ffc59a8b14d24 100644 GIT binary patch delta 2118 zcmV-M2)XyX1k@0aC4X~5NmK|32nc)#WQYI&010qNS#tmYbj$z%bj$&u-(;Nt0010x zMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK*cveTdd00+)VL_t(og~gX^Y!ufO z$NzWk%&yn#Cph?t&3gT|dAfFtO^hD_5^zcoEdeD;C}~BTQh)fwhlU~{)G9%!ij+oC zq>6rMtE6e#05M)dcoc*2+Q!DlPrx=0W8(*Y?`w8;W==miSinNOw5fWe`7(3wIluEi zXYPX$5&oYh20Ac${`>`&Wa}Y85QMSO(a(K~(sJ`|-@X49fCZvJR(kr@=$P2wTdXN@ zl4QW-#5g7=Cx540PDhRG@l-pfr@wk<@7`Oxf4)=sUIFHZhs|4Lu^vuHOx$6yrodpFB@ ze`E~j9FoDHci!!D1$A_UPUw2ysVK=pr)u@3**UKUn}5w)JZ^WB!!cd$a=E&OMn_$9 z0)&}@LsHVxejA^VuxF7q6~SgRRG-fekaG?nk=ovK!`;F^G9tdsjiQkOe^C`W92}%BwWdn3@$oYmG6o{(isBWVj%m1@ zPT&2JVb{di*g2Eg{0<``WTsiA(9p;OQO_-S*OHQgkkBw_J{1K2@<@_|+he1OyQ2fU zoNmKfQNpCI7qB1&jbReWp|F`Al=^n^rk zkYC9dW8j?QW^WIE8wXqtwO zwpNOq7fD;+cvA?Eh=8If900_@ks)77YN~tR{@+Aj>+A|Tdh|=BzOKQi13Z3VB9DxS zWP^?=479gl=h%d>MKrKpA{-V4+(}MDMt_n8Mkc_g_%8vHBw>1b8a>y$w4B9D^y1Po zQP*|mm1TfI06-!D=KWUkjI2!jI%}U{XmAj=Dw}@x>{-3Lw}&lsID|t^H(M?m@i)@( zAtyv-4Pb#iA^G7!g4fMKCZ%1QH&eNPk2i zBE-bTV#iP47LNSsh>%xUfYQNXTFymyGz~sgfhi##5sc7iw_{{@2uu)WoH7PM5Fl`l z>zy4mH8r7Z+4edzvvVYm$NlIp&%gj;j{rOl5@a&5?K^g``p9rh%Q9qLLy<>Djws>K zM;~JMo?S3X9PKU5=;^)zUDKdx8h=`w8W9x{fo*TRX_y}s#buAjF9ri+z#N+q5g~oy zLdJ_$QcIi#EU_(U(nwpyMwate5hDLZ@PUPq1BkzS`=JWZW zJfSzfB@l>!Co1r`m2KLD(?k$84KiaW_4#n_*s`TK!E|278KxKRtE0L9#S<8*^&frbqzZE`eu~^fRK<7NJisK)^qQ&3%h z5;)pVRKex*fz9;OGZ~v%2Y&(w$gx)>iz>Zhz+Bvj~9#Jdm|y z^JZM+9D=67ON4^SDO{*L@gId37!!zy0#*P3UMws`Uv@U`%QCz~SS*SdKXV4X!@~jl zc(5yKx^5N(fzQ-In45!$5NS3u>-v{b51oQE6-FXt-M#}`RaHR2Ie+Ic7>uZ`slmks;+t7+P?koC8ed`Txo1l+gsbL zZnwu29~TFc$>awkFvcc1$JG;6Sm9NeN&q>XXpW9XdS(VLU93U&;w7_*m`o;I>+C?~ zu`h4b+wB|shX#*73^%J85!C^xV~icFtgPIcm!J1mSy}ng(tq+YWMySN0`XEw2~KBc zVZ5#m22n(guA%{O z)rqS0`T6_~M#1e06CFBuT=2vzb{dHc*4zPGvrY88sD&-Q75T(uQ!O5e9=1 zZnqn!zqX;i_J7iQ9oMhF`?TH&=w`$i%S^YX{N(wSD_>i)c1>b=c{wHs_@tzSe$~^> zY9k}@S$x8ce#WATi;Cvu6%^w5Kfai_($x5izIy}Tc~J=n;31HRFmuS};^N{Rt4dZE zww$j<;?)+MkBhf8WMpkyakcqibX?pX(y9I8h4ZgFWk0!fPNxqJAJ6(2zzTD7fADEW wVbS{!-W5JyP?WoD`JVxp0`>Du3j8nZ--uZDR~H8@-T(jq07*qoM6N<$f}I)mf&c&j delta 546 zcmV+-0^R-85WEDCC4Xl@O+f$vv5yP14NwyFK2ngGh8*(+ zeeB=S-q8b9@C^WflxozPugHnQBf>9hubR`1YHeL86G(Ajyf8mlT)v- zb7Yo=uVWi^0pKj;st2hwpy8nF;aZ_D$HUVaHqPh~o2}6EVRBX9kL;Xc+-jYqm~QBj k08UdZ4;z5)oIi8lCuM@RnYK+^e*gdg07*qoM6N<$f+ivDRR910 diff --git a/Sledge.Editor/Resources/Tool_Decal.png b/Sledge.Editor/Resources/Tool_Decal.png index 04aa7853bb1d0450fc9bc3ebae332a9d0a3c632f..20395fcf9fff7d5fd7741e302c367e0c334ddb73 100644 GIT binary patch delta 2577 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 diff --git a/Sledge.Editor/Resources/Tool_Entity.png b/Sledge.Editor/Resources/Tool_Entity.png index 5ec48dc77eebf5f716d963fb807e6dfc061ea4d9..1fb13854647d9d26a2462d428cbd87638bdd01bd 100644 GIT binary patch delta 1493 zcmV;`1uFWN2ImWqB!2{RLP=Bz2nYy#2xN!=000SaNLh0L0Cda%0Cda&pxw(EZ*psMAVX6$2C~zj000GHNkl2d7pMa&fxI*zhreeVfjRzjmyE}P-j>REtR$U~Z}7Me zZbmRF*#ejk95ZeCi~m~zZ+t>3fNUaA4-^1x z;DuGjW5{^S6_MzS{QUe|&UANgt`3KrL{k%nVPMDO_nhqNdbYB%vbwjo_neH!2+9JW zl*;JSQ{T9}r@nEpr@k?NwD;vDrOW5dnXBTlm{Lk9*LBsYt}fNOV4*52E?J*WZ#EHV z1@@V??0>6_M)VS;odIqJlVMT?p`oE6c7C;kf&PI``|zPRll*u? z>UR%LX8C`kr@qnYsc$sW@k}kR$PZUe9a#0st13wwH*8eXs;Y-7O3No_Tmz0JYJn$! zJ-{B*mi@p3q>SHSC5uS3YfABy((cozpKjZ}{ll{Ia`MKE;e$<^xOB;RvAU+FQ$(WI zWPdznrpjumx1nQ+mB7o%C<5(x6L2-K%CzP1B_txzalrR@WB0PAX^n|Q;zVIl5g}dY z%H_+rO3l_aZ39pZTmix|9&?g9Myr8`{an`pEAc8_2UY+*jwLobmRNel5>xzqP693g z69xwd3qqj~4Gj&{Sr(yCh-*VbWxB4{0Dq@|u|Q7HnBiDL0E57{c!TCP;4RaZhk?V6 zB}##O;5odj_%Yzg1S|wT0}26TJVsq@Euc{q4x?!r?YsA&l*_&Y5)p}peMd%2!gap4 zXMyj45YQRmc?9^>wB=S{t7D0ufOmj>ejbMvdNrk}4u{co9ZdtJ$V~!F@&;?bz<=|k z9=I1+>g(F&SmG#f04N6b1^_(>>^E)ckV3kyp9cO|^V;fMUDrq?5(!<`?Nq+uF$@@{ zEzkPiZ*eTq0(1eJePB=FO|JJHOFRR74a@~zPgM$#mzQ_$!o`c@2KxF+T-PO(n{&Qo zO7V3UlHo3JEKv>o2(+5E+~S{o0)N~JtOXVUci|P$0PqE{6R%)9O zJ(hCzk!j2IrY&3WTCvv$6!xDdfK!eo-g7MRxMPXpYyboYQJw!h;8p9gqa zfp*iDD}WWgu{(XB3xFj6jwKEPyYaf@kZH?H=>P;%FbVI%Y4#0O;YH{N;D1YCKd=#4 zX4>-Y(Udusm>e#3T$TlfXDY`hX_;uV$LIJdw_$fV=@j zfIILu=~=){z^}kJz!pG`3c#^M5pW)O$+YEK|IET$zdjC*<4no1#CV_)nCCk*9XOs2 zz vgV#d;I*k^Ac|Zc#@qYo(@cQ=Le*xf6`96a{>6Zaw00000NkvXXu0mjfmXEtp delta 767 zcmVpF8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900M?d zL_t(oN41sBOBGQZh9|QuabtlyHB-wExTrfNf>u#tDw-?NMSp7}@PksR2)DUu5foac zscCKm5qE0dRN954i$rJ>;=(^cpBIiYT*f=YIpe^?nYs7;-uFFoKF0GbuWO@TC5%{> zyO&|!2HoyTmI|1^h6k4A?q!(IKF?s@r@By}A z$b^`q&9q8^*?af}-{B1m!&|r#um{Q7F0u?f`3_=t4Ifq%pf1`!y+uf3T(g} zBm%-{9oz{uW=;zraE0pi%OqtArs#jugwy|HP!$lMfB;uR15i8*>t>{*v_0?;lN+>! z8evKR?SRwyZ(gx>&5Q|{9VLKsAB{k-((Hc) z(-ytwEF4w9%{uowjCY=lMS2O?s002ovPDHLkV1jP%Rk#2E diff --git a/Sledge.Editor/Resources/Tool_Select.png b/Sledge.Editor/Resources/Tool_Select.png index adcac24d89e428e9c079fe921209d6e85fb3d0ce..e363fb358c2bfc009ca77ae88e766a1b1edd8f32 100644 GIT binary patch delta 1778 zcmVZC4X~5NmK|32nc)#WQYI&010qNS#tmYbj$z%bj$&u-(;Nt0010x zMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK*cveTdd00wGkw8pn4 z)~ZosYNGyQGUGNAT{X0&G#3mlP)d1OL1H~;bp+_C;06*;mTV40NB=Iq{F_3+J>W8ZA7p43g9b%xfWlR zwHU>~PEj!wm47e++kxD*_*oG^*ZShpo{c51-_uf0fUY4x&+2F6=2ws8=51ROfVi;L zHCI&KYO1aK?%PG1+q0-FPWN3uKUr4&6YA@Ke7f$@{?~f>KKp4Y+YZPdu5jG&!L~gG)f4T#fV9pj>`#L%CVsbk3}*JAV+GA^ng{JVCm)#C>I8NQnCK zZQD=8J?mXIT~E604p0<@px=6=$NTbWDF*@034h^fYuXjST>z#5{#i= z6QbPJ)bdB%9)m<8A%rloTAji_tGssY%HbcSGqaF@h4#1&yJ}tQKH(}X1T6s;3n&Wc z8olrZA;dQ_HF1zs0-R1r>X6WBgA>1peL@Je10LP2xOS7D4+$-u5XAw8&H#K4I0mHd z0)L>xZKglqP9%tyNTLXE+w3IbQD(rN(KQCaTcI1ECwQr{B>Md1O>q$hfC4}dLy+l7 ze1RGCL=p!Aw_-;`qfCJlP=pZbe0?kc*bnEJxY+qDr^r=jZqQ z>tbh2(=_eI&~WmNH@>CW?T#O0f?6|~Tz-~x$NwM4m395p)^DJ)R{0uS5<)m+T7L|y z)#kn4-%szrp!5er#^+yr(Q@+S$)jauTmAuT0xVKWbJbpkSl}`0II5vc3fzeu}Fk#eSLVlx>I{wTRC;=r#pAG?CuBgoDf2p*Uu(d0Yrpt z19jVjuB}^ZvDx`&*JWDfX1+fy<$oCZIQvARdbm2n2Y4^nKoa=iQXe;gHAQ zJihLk15cmzcnZFg0i88g){l8mLQakwo1OQ%F4N}s9S435i~w>`8V3x+FsG-d2?PR! zqY)yJ2%Vjm%^9Che)a3G*$*B1>?_U9%^kqzY-2h5oR&u4i9FAjKRG&dW`AEe@NM9% zlyV}A=8#01KA#UE1S!KnO(c+}Nqc*{SzcBqtE;QTTp(Br)@yxzR}Tsy&H?&eJg{7j zMS{N+LcC4-$+z#JmYSWNm7!1wP1A@)BE(ePmEjAlYmx~#nPpYcQ6Hl}_i;GLXNSeGfAh~#-cn}#F2!Dsec)Pvblamv_ z85}1DKq=HFx92^>8Ag{ROx4wnhVSV(H%Q>{2a_U z3e7S!G@Ke99zL&W>T4;$3q9K3LTsgIkjZIyu8n+A%UhmN~?Gn%f z^aGPX?12GT1Vli(HH8pX;8Ua**(qR{bPEQ67?6740I~p5fc2#7ES?FRWGR*NUuVk( Uus-rTp8x;=07*qoM6N<$g8wc|{r~^~ delta 226 zcmZqX`_DK*wLaa^*O7r?V?XzwL{P1BKIB+D;FIuWW|m`Re%El(#Na`o0a&2qmEggslP$NIP0B80%$E>jVklT$ V>lW@m`w`F~44$rjF6*2UngD@dOu_&F diff --git a/Sledge.Editor/Resources/Tool_Texture.png b/Sledge.Editor/Resources/Tool_Texture.png index 4c99e3b44ece64e28693f35980c8b85add368f62..1fa6b4d1e688a8995acec47e1c46e15c89652095 100644 GIT binary patch delta 1904 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, - Wads = new List(), - Build = _builds.FirstOrDefault() + Wads = new List() }); ReIndex(); UpdateGameTree(); @@ -479,7 +478,7 @@ private void SelectedGameUpdateFgds() { SelectedGameFgdList.Items.Add(fgd.Path); } - var gd = GameDataProvider.GetGameDataFromFiles(_selectedGame.Fgds.Select(x => x.Path)); + var gd = GameDataProvider.GetGameDataFromFiles(_selectedGame.Fgds.Select(x => x.Path).Where(File.Exists)); SelectedGameDefaultPointEnt.Items.Clear(); SelectedGameDefaultPointEnt.Items.AddRange(gd.Classes.Where(x => x.ClassType == ClassType.Point).Select(x => x.Name).ToArray()); diff --git a/Sledge.Editor/Tools/DecalTool.cs b/Sledge.Editor/Tools/DecalTool.cs index 0e62b3e63..27420ee33 100644 --- a/Sledge.Editor/Tools/DecalTool.cs +++ b/Sledge.Editor/Tools/DecalTool.cs @@ -11,6 +11,7 @@ using Sledge.Editor.History; using Sledge.Editor.Properties; using Sledge.Graphics.Helpers; +using Sledge.Providers.Texture; using Sledge.Settings; using Sledge.UI; @@ -65,6 +66,12 @@ private void CreateDecal(Coordinate origin) var gd = Document.GameData.Classes.First(x => x.Name == "infodecal"); var selected = Editor.Instance.GetSelectedTexture(); var textureName = selected == null ? "{TARGET" : selected.Name; + + if (TexturePackage.GetItem(textureName) == null) + { + return; + } + var decal = new Entity(Document.Map.IDGenerator.GetNextObjectID()) { EntityData = new EntityData(gd), @@ -73,7 +80,7 @@ private void CreateDecal(Coordinate origin) Decal = TextureHelper.Get(textureName), Origin = origin }; - decal.EntityData.Properties.Add(new Property { Key = "texture", Value = textureName }); + decal.EntityData.SetPropertyValue("texture", textureName); Document.PerformAction("Apply decal", new Create(decal)); } diff --git a/Sledge.Editor/Tools/TextureApplicationForm.cs b/Sledge.Editor/Tools/TextureApplicationForm.cs index 212b405bb..766c2a84d 100644 --- a/Sledge.Editor/Tools/TextureApplicationForm.cs +++ b/Sledge.Editor/Tools/TextureApplicationForm.cs @@ -144,6 +144,11 @@ private void UpdateRecentTextureList() public void SelectTexture(TextureItem item) { + if (item == null) + { + SelectedTexturesList.SetSelectedTextures(new TextureItem[0]); + return; + } // Add the texture to the recent texture list if (!_recentTextures.Contains(item)) { diff --git a/Sledge.Editor/Tools/VMTool.cs b/Sledge.Editor/Tools/VMTool.cs index 59baa2a42..b1214b53b 100644 --- a/Sledge.Editor/Tools/VMTool.cs +++ b/Sledge.Editor/Tools/VMTool.cs @@ -205,9 +205,11 @@ private void RefreshMidpoints(bool recreate = true) { foreach (var group in copy.Faces.SelectMany(x => x.GetLines()).GroupBy(x => new { x.Start, x.End })) { - var coord = (group.Key.Start + group.Key.End) / 2; - var mpStart = _points.First(x => !x.IsMidPoint && x.Coordinate == group.Key.Start); - var mpEnd = _points.First(x => !x.IsMidPoint && x.Coordinate == group.Key.End); + var s = group.Key.Start; + var e = group.Key.End; + var coord = (s + e) / 2; + var mpStart = _points.First(x => !x.IsMidPoint && x.Coordinate == s); + var mpEnd = _points.First(x => !x.IsMidPoint && x.Coordinate == e); if (recreate) { _points.Add(new VMPoint @@ -221,7 +223,10 @@ private void RefreshMidpoints(bool recreate = true) } else { - _points.First(x => x.IsMidPoint && x.MidpointStart == mpStart && x.MidpointEnd == mpEnd).Coordinate = coord; + foreach (var point in _points.Where(x => x.IsMidPoint && x.MidpointStart.Coordinate == s && x.MidpointEnd.Coordinate == e)) + { + point.Coordinate = coord; + } } } } @@ -275,7 +280,7 @@ public override void MouseDown(ViewportBase vp, MouseEventArgs e) } vtxs.ForEach(x => x.IsSelected = true); _clickedPoints = vtxs; // This is unset if the mouse is moved, see MouseUp logic. - _snapPointOffset = SnapIfNeeded(viewport.Expand(viewport.ScreenToWorld(e.X, viewport.Height - e.Y))) - viewport.Flatten(vtx.Coordinate); + _snapPointOffset = SnapIfNeeded(viewport.Expand(viewport.ScreenToWorld(e.X, viewport.Height - e.Y))) - viewport.ZeroUnusedCoordinate(vtx.Coordinate); _movingPoint = vtx; } @@ -347,7 +352,7 @@ public override void MouseMove(ViewportBase vp, MouseEventArgs e) // If shift is down, retain the offset the point was at before (relative to the grid) point += _snapPointOffset; } - var moveDistance = point - viewport.Flatten(_movingPoint.Coordinate); + var moveDistance = point - viewport.ZeroUnusedCoordinate(_movingPoint.Coordinate); // Move each selected point by the delta value foreach (var p in _points.Where(x => !x.IsMidPoint && x.IsSelected)) { @@ -440,7 +445,7 @@ protected override void Render3D(Viewport3D vp) foreach (var point in _points) { var c = vp.WorldToScreen(point.Coordinate); - if (c.Z > 1) continue; + if (c == null || c.Z > 1) continue; c -= half; GL.Color3(Color.Black); diff --git a/Sledge.Editor/UI/EntityEditor.designer.cs b/Sledge.Editor/UI/EntityEditor.designer.cs index 5dac9eae3..cff28fc75 100644 --- a/Sledge.Editor/UI/EntityEditor.designer.cs +++ b/Sledge.Editor/UI/EntityEditor.designer.cs @@ -679,9 +679,11 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.VisgroupPanel.DisableAutomatic = true; + this.VisgroupPanel.HideAutomatic = false; this.VisgroupPanel.Location = new System.Drawing.Point(6, 26); this.VisgroupPanel.Name = "VisgroupPanel"; this.VisgroupPanel.ShowCheckboxes = true; + this.VisgroupPanel.ShowHidden = false; this.VisgroupPanel.Size = new System.Drawing.Size(662, 319); this.VisgroupPanel.SortAutomaticFirst = false; this.VisgroupPanel.TabIndex = 2; @@ -741,7 +743,7 @@ private void InitializeComponent() this.ShowIcon = false; this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "EntityEditor"; + this.Text = "Object Properties"; this.Tabs.ResumeLayout(false); this.ClassInfoTab.ResumeLayout(false); this.ClassInfoTab.PerformLayout(); diff --git a/Sledge.Editor/Visgroups/VisgroupPanel.cs b/Sledge.Editor/Visgroups/VisgroupPanel.cs index 3d5fb3709..9dc0b6aae 100644 --- a/Sledge.Editor/Visgroups/VisgroupPanel.cs +++ b/Sledge.Editor/Visgroups/VisgroupPanel.cs @@ -108,6 +108,7 @@ private void AddNode(TreeNode parent, Visgroup visgroup, Func public void Update(Document document) { Clear(); + if (document == null) return; var states = document.Map.WorldSpawn .FindAll() .SelectMany(x => x.Visgroups.Select(y => new {ID = y, Hidden = x.IsVisgroupHidden})) diff --git a/Sledge.Providers/GameData/GameDataProvider.cs b/Sledge.Providers/GameData/GameDataProvider.cs index 6a6727c04..1dfc50937 100644 --- a/Sledge.Providers/GameData/GameDataProvider.cs +++ b/Sledge.Providers/GameData/GameDataProvider.cs @@ -91,16 +91,20 @@ protected virtual bool IsValidForString(string contents) protected virtual DataStructures.GameData.GameData GetFromFile(string filename) { - Stream strm = new FileStream(filename, FileMode.Open, FileAccess.Read); - return GetFromStream(strm); + using (var strm = new FileStream(filename, FileMode.Open, FileAccess.Read)) + { + return GetFromStream(strm); + } } protected virtual DataStructures.GameData.GameData GetFromString(string contents) { var length = Encoding.UTF8.GetByteCount(contents); - Stream strm = new MemoryStream(length); - strm.Write(Encoding.UTF8.GetBytes(contents), 0, length); - return GetFromStream(strm); + using (var strm = new MemoryStream(length)) + { + strm.Write(Encoding.UTF8.GetBytes(contents), 0, length); + return GetFromStream(strm); + } } protected abstract DataStructures.GameData.GameData GetFromStream(Stream stream); diff --git a/Sledge.Providers/Map/MapFormatProvider.cs b/Sledge.Providers/Map/MapFormatProvider.cs index 60048b52a..07f17fdf1 100644 --- a/Sledge.Providers/Map/MapFormatProvider.cs +++ b/Sledge.Providers/Map/MapFormatProvider.cs @@ -194,7 +194,11 @@ private void WriteEntity(StreamWriter sw, Entity ent) sw.WriteLine("{"); WriteProperty(sw, "classname", ent.EntityData.Name); WriteProperty(sw, "spawnflags", ent.EntityData.Flags.ToString()); - ent.EntityData.Properties.ForEach(x => WriteProperty(sw, x.Key, x.Value)); + foreach (var prop in ent.EntityData.Properties) + { + if (prop.Key == "classname" || prop.Key == "spawnflags") continue; + WriteProperty(sw, prop.Key, prop.Value); + } if (solids.Any()) solids.ForEach(x => WriteSolid(sw, x)); // Brush entity else WriteProperty(sw, "origin", FormatCoordinate(ent.Origin)); // Point entity @@ -214,7 +218,11 @@ private void WriteWorld(StreamWriter sw, World world) WriteProperty(sw, "classname", world.EntityData.Name); WriteProperty(sw, "spawnflags", world.EntityData.Flags.ToString()); WriteProperty(sw, "mapversion", "220"); - world.EntityData.Properties.ForEach(x => WriteProperty(sw, x.Key, x.Value)); + foreach (var prop in world.EntityData.Properties) + { + if (prop.Key == "classname" || prop.Key == "spawnflags" || prop.Key == "mapversion") continue; + WriteProperty(sw, prop.Key, prop.Value); + } solids.ForEach(x => WriteSolid(sw, x)); sw.WriteLine("}"); diff --git a/Sledge.Settings/Models/Game.cs b/Sledge.Settings/Models/Game.cs index 62dd43ac3..c4c4348ac 100644 --- a/Sledge.Settings/Models/Game.cs +++ b/Sledge.Settings/Models/Game.cs @@ -26,7 +26,6 @@ public class Game public List Fgds { get; set; } public List Wads { get; set; } - public Build Build { get; set; } public Game() {