Compare commits
167 Commits
release-20
...
playtest-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08eeec4d99 | ||
|
|
564a4598b9 | ||
|
|
7e25b6e58e | ||
|
|
57f74606f0 | ||
|
|
b44cb9ad57 | ||
|
|
dfd5906d7f | ||
|
|
2e7b5e8712 | ||
|
|
eb8682fd0e | ||
|
|
2d224a207c | ||
|
|
5070a81db4 | ||
|
|
e97dd2ee47 | ||
|
|
da74c6ad23 | ||
|
|
c7f1d08748 | ||
|
|
7850acc6fb | ||
|
|
ec5b9a1150 | ||
|
|
83f67a9d48 | ||
|
|
fb799ad436 | ||
|
|
60186efca6 | ||
|
|
20ab3b6caa | ||
|
|
32db66eb7e | ||
|
|
112844a9f7 | ||
|
|
745df591e0 | ||
|
|
9c7759d131 | ||
|
|
4bb70f11e9 | ||
|
|
ce5ca9dbca | ||
|
|
0b9a984b7a | ||
|
|
45cd6caeec | ||
|
|
4c517c0e59 | ||
|
|
7884cb310b | ||
|
|
306bece709 | ||
|
|
748a055a24 | ||
|
|
240b26a265 | ||
|
|
ac82121460 | ||
|
|
3189a4f457 | ||
|
|
291e7588e1 | ||
|
|
b8e274e0f9 | ||
|
|
e81a1f78a4 | ||
|
|
51c3455ffe | ||
|
|
583fa0aa39 | ||
|
|
f768f8d969 | ||
|
|
0e26f0ce26 | ||
|
|
2a8beca0f8 | ||
|
|
b5813ebff8 | ||
|
|
0f6f36411a | ||
|
|
f798639125 | ||
|
|
6014095ab3 | ||
|
|
52e265557c | ||
|
|
f9f9fbf3e4 | ||
|
|
d559b5cdb7 | ||
|
|
d6733e62d6 | ||
|
|
00a0aac7a3 | ||
|
|
840ade5b78 | ||
|
|
13d3137ae4 | ||
|
|
62c652a645 | ||
|
|
76428cbda2 | ||
|
|
434ea26950 | ||
|
|
9655b34e5f | ||
|
|
e91caa4e7a | ||
|
|
3b0810a096 | ||
|
|
1d81e71bcb | ||
|
|
29ac9a594a | ||
|
|
fb0e399ab9 | ||
|
|
7c5c989eb2 | ||
|
|
41fd19c766 | ||
|
|
b423889c06 | ||
|
|
5f43923b80 | ||
|
|
5470264f00 | ||
|
|
06ed722b7a | ||
|
|
8565b7be0c | ||
|
|
a3861823c9 | ||
|
|
84fd45ad69 | ||
|
|
dd6a431af2 | ||
|
|
fa31fb199f | ||
|
|
fbeb638582 | ||
|
|
1aebd59062 | ||
|
|
7182908728 | ||
|
|
58a92de5a1 | ||
|
|
4ea04f461a | ||
|
|
26c084cfb8 | ||
|
|
ac513557a1 | ||
|
|
db5b5698a7 | ||
|
|
1f61d22489 | ||
|
|
520f602f23 | ||
|
|
8c5c63a4b5 | ||
|
|
a0741ba26b | ||
|
|
9f21d944d1 | ||
|
|
10f9e3e787 | ||
|
|
eff5e409c0 | ||
|
|
f108735f74 | ||
|
|
e62149398b | ||
|
|
d6e831eb07 | ||
|
|
dcf3912d24 | ||
|
|
efad699d4b | ||
|
|
77a35fd132 | ||
|
|
2fe7e10750 | ||
|
|
6f66a19b18 | ||
|
|
2fc88e439d | ||
|
|
b4b05c3f4e | ||
|
|
0ee1d39bac | ||
|
|
c3521a2490 | ||
|
|
cb93955cc5 | ||
|
|
666efc94d1 | ||
|
|
d2a52fd529 | ||
|
|
085685a769 | ||
|
|
034196ddd6 | ||
|
|
3dc16bdbb4 | ||
|
|
f42f39f9c9 | ||
|
|
40235db52e | ||
|
|
810b73e1f0 | ||
|
|
82850cf4fb | ||
|
|
21e597ca2d | ||
|
|
ed8203c896 | ||
|
|
de7668e8ff | ||
|
|
7271dd5248 | ||
|
|
16dd07bab3 | ||
|
|
5cbfc45819 | ||
|
|
6a238ab51a | ||
|
|
4d9c2a30df | ||
|
|
8b18927c67 | ||
|
|
d77563bdb0 | ||
|
|
d0466714c8 | ||
|
|
08c9c1a92f | ||
|
|
ea3943daf4 | ||
|
|
6ac92c45f1 | ||
|
|
96cd0e2259 | ||
|
|
fc5830a687 | ||
|
|
1dfe437641 | ||
|
|
b8eda5a152 | ||
|
|
de8603832f | ||
|
|
f11bcd27cc | ||
|
|
00dc91cf49 | ||
|
|
8b0255e2f7 | ||
|
|
3a2279f378 | ||
|
|
8085bcb232 | ||
|
|
5e6f325df1 | ||
|
|
f892eb629e | ||
|
|
1629958970 | ||
|
|
2079627030 | ||
|
|
2072b78489 | ||
|
|
3d1d4a1aff | ||
|
|
41665f7e95 | ||
|
|
604aae5980 | ||
|
|
ac613f7bea | ||
|
|
46d0a6d00d | ||
|
|
402afc82ca | ||
|
|
1cd59a0892 | ||
|
|
7b7bcf1005 | ||
|
|
be701007df | ||
|
|
fef6285436 | ||
|
|
b3c4afa620 | ||
|
|
8df1813afd | ||
|
|
6a28bcb49a | ||
|
|
730ed8c597 | ||
|
|
7b5be4a0ec | ||
|
|
30fb1250b3 | ||
|
|
a363bf841c | ||
|
|
da5830845b | ||
|
|
23e6eada26 | ||
|
|
490b0801a0 | ||
|
|
49ab704a84 | ||
|
|
4a12b78f14 | ||
|
|
656dbdcd28 | ||
|
|
88398afba6 | ||
|
|
2f74207bf6 | ||
|
|
f4f9abe4d4 | ||
|
|
e50b8ec7dc | ||
|
|
70f92494b2 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -44,6 +44,9 @@ packaging/osx/launcher/OpenRA.xcodeproj/*.mode1v3
|
||||
temp.c
|
||||
temp.o
|
||||
temp.s
|
||||
|
||||
OpenRA.Launcher.Mac/build/
|
||||
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.pbxuser
|
||||
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.perspectivev3
|
||||
OpenRA.Launcher.Mac/OpenRA.xcodeproj/*.mode1v3
|
||||
*.config
|
||||
*.resources
|
||||
|
||||
1
AUTHORS
1
AUTHORS
@@ -8,3 +8,4 @@ The OpenRA developers are:
|
||||
* Alli Witheford
|
||||
* Joakim Lindberg
|
||||
* Andrew Riedi
|
||||
* Tim Mylemans
|
||||
|
||||
263
Makefile
263
Makefile
@@ -1,23 +1,43 @@
|
||||
CSC = gmcs
|
||||
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
|
||||
DEFINE = DEBUG;TRACE
|
||||
PROGRAMS = fileformats rcg rgl rnull game ra cnc seqed editor ralint filex tsbuild utility winlaunch
|
||||
prefix = /usr/local
|
||||
datarootdir = $(prefix)/share
|
||||
datadir = $(datarootdir)
|
||||
bindir = $(prefix)/bin
|
||||
BIN_INSTALL_DIR = $(DESTDIR)$(bindir)
|
||||
INSTALL_DIR = $(DESTDIR)$(datadir)/openra
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL)
|
||||
|
||||
CSC = gmcs
|
||||
CSFLAGS = -nologo -warn:4 -debug:+ -debug:full -optimize- -codepage:utf8 -unsafe
|
||||
DEFINE = DEBUG;TRACE
|
||||
COMMON_LIBS = System.dll System.Core.dll System.Drawing.dll System.Xml.dll
|
||||
PHONY = core tools package all mods clean distclean
|
||||
|
||||
fileformats_SRCS = $(shell find OpenRA.FileFormats/ -iname '*.cs')
|
||||
fileformats_TARGET = OpenRA.FileFormats.dll
|
||||
fileformats_KIND = library
|
||||
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll System.Windows.Forms.dll thirdparty/ICSharpCode.SharpZipLib.dll
|
||||
.SUFFIXES:
|
||||
core: game renderers mod_ra mod_cnc
|
||||
tools: editor ralint seqed filex tsbuild utility
|
||||
package: fixheader core editor utility winlaunch
|
||||
mods: mod_ra mod_cnc
|
||||
all: core tools winlaunch
|
||||
clean:
|
||||
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb *.resources
|
||||
distclean: clean
|
||||
|
||||
#
|
||||
# Core binaries
|
||||
#
|
||||
fileformats_SRCS = $(shell find OpenRA.FileFormats/ -iname '*.cs')
|
||||
fileformats_TARGET = OpenRA.FileFormats.dll
|
||||
#fileformats_DEPS = fixheader
|
||||
fileformats_KIND = library
|
||||
fileformats_LIBS = $(COMMON_LIBS) thirdparty/Tao/Tao.Sdl.dll System.Windows.Forms.dll thirdparty/ICSharpCode.SharpZipLib.dll
|
||||
PROGRAMS = fileformats
|
||||
fileformats: $(fileformats_TARGET)
|
||||
|
||||
game_SRCS = $(shell find OpenRA.Game/ -iname '*.cs')
|
||||
game_TARGET = OpenRA.Game.exe
|
||||
game_KIND = winexe
|
||||
game_DEPS = $(fileformats_TARGET)
|
||||
game_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(game_DEPS) \
|
||||
thirdparty/Tao/Tao.OpenAl.dll thirdparty/Tao/Tao.FreeType.dll
|
||||
game_FLAGS = -win32icon:OpenRA.Game/OpenRA.ico
|
||||
PROGRAMS += game
|
||||
game: $(game_TARGET)
|
||||
|
||||
#
|
||||
# Renderer dlls
|
||||
#
|
||||
rcg_SRCS = $(shell find OpenRA.Renderer.Cg/ -iname '*.cs')
|
||||
rcg_TARGET = OpenRA.Renderer.Cg.dll
|
||||
rcg_KIND = library
|
||||
@@ -40,99 +60,159 @@ rnull_KIND = library
|
||||
rnull_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
rnull_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll \
|
||||
$(rnull_DEPS) $(game_TARGET)
|
||||
PROGRAMS += rcg rgl rnull
|
||||
renderers: $(rcg_TARGET) $(rgl_TARGET) $(rnull_TARGET)
|
||||
|
||||
game_SRCS = $(shell find OpenRA.Game/ -iname '*.cs')
|
||||
game_TARGET = OpenRA.Game.exe
|
||||
game_KIND = winexe
|
||||
game_DEPS = $(fileformats_TARGET)
|
||||
game_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(game_DEPS) \
|
||||
thirdparty/Tao/Tao.OpenAl.dll thirdparty/Tao/Tao.FreeType.dll
|
||||
game_FLAGS = -win32icon:OpenRA.Game/OpenRA.ico
|
||||
#
|
||||
# Official Mods
|
||||
#
|
||||
# Red Alert
|
||||
mod_ra_SRCS = $(shell find OpenRA.Mods.RA/ -iname '*.cs')
|
||||
mod_ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
|
||||
mod_ra_KIND = library
|
||||
mod_ra_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
mod_ra_LIBS = $(COMMON_LIBS) $(mod_ra_DEPS)
|
||||
PROGRAMS += mod_ra
|
||||
mod_ra: $(mod_ra_TARGET)
|
||||
# mono RALint.exe ra
|
||||
|
||||
ra_SRCS = $(shell find OpenRA.Mods.RA/ -iname '*.cs')
|
||||
ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
|
||||
ra_KIND = library
|
||||
ra_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
ra_LIBS = $(COMMON_LIBS) $(ra_DEPS)
|
||||
|
||||
cnc_SRCS = $(shell find OpenRA.Mods.Cnc/ -iname '*.cs')
|
||||
cnc_TARGET = mods/cnc/OpenRA.Mods.Cnc.dll
|
||||
cnc_KIND = library
|
||||
cnc_DEPS = $(fileformats_TARGET) $(game_TARGET) $(ra_TARGET)
|
||||
cnc_LIBS = $(COMMON_LIBS) $(cnc_DEPS)
|
||||
# Command and Conquer
|
||||
mod_cnc_SRCS = $(shell find OpenRA.Mods.Cnc/ -iname '*.cs')
|
||||
mod_cnc_TARGET = mods/cnc/OpenRA.Mods.Cnc.dll
|
||||
mod_cnc_KIND = library
|
||||
mod_cnc_DEPS = $(fileformats_TARGET) $(game_TARGET) $(mod_ra_TARGET)
|
||||
mod_cnc_LIBS = $(COMMON_LIBS) $(mod_cnc_DEPS)
|
||||
PROGRAMS += mod_cnc
|
||||
mod_cnc: $(mod_cnc_TARGET)
|
||||
# mono RALint.exe cnc
|
||||
|
||||
#
|
||||
# Tools
|
||||
#
|
||||
# Sequence editor (defunct)
|
||||
seqed_SRCS = $(shell find SequenceEditor/ -iname '*.cs')
|
||||
seqed_TARGET = SequenceEditor.exe
|
||||
seqed_KIND = winexe
|
||||
seqed_DEPS = $(fileformats_TARGET)
|
||||
seqed_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll $(seqed_DEPS)
|
||||
seqed_EXTRA = -resource:SequenceEditor.Form1.resources
|
||||
PROGRAMS += seqed
|
||||
SequenceEditor.Form1.resources:
|
||||
resgen2 SequenceEditor/Form1.resx SequenceEditor.Form1.resources 1> /dev/null
|
||||
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
|
||||
|
||||
# Map Editor
|
||||
editor_SRCS = $(shell find OpenRA.Editor/ -iname '*.cs')
|
||||
editor_TARGET = OpenRA.Editor.exe
|
||||
editor_KIND = winexe
|
||||
editor_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
editor_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll System.Data.dll $(editor_DEPS)
|
||||
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
|
||||
PROGRAMS += editor
|
||||
OpenRA.Editor.MapSelect.resources:
|
||||
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
|
||||
OpenRA.Editor.Form1.resources:
|
||||
resgen2 OpenRA.Editor/Form1.resx OpenRA.Editor.Form1.resources 1> /dev/null
|
||||
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
|
||||
|
||||
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
|
||||
ralint_TARGET = RALint.exe
|
||||
ralint_KIND = exe
|
||||
ralint_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
ralint_LIBS = $(COMMON_LIBS) $(ralint_DEPS)
|
||||
# Analyses mod yaml for easy to detect errors
|
||||
ralint_SRCS = $(shell find RALint/ -iname '*.cs')
|
||||
ralint_TARGET = RALint.exe
|
||||
ralint_KIND = exe
|
||||
ralint_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
ralint_LIBS = $(COMMON_LIBS) $(ralint_DEPS)
|
||||
PROGRAMS += ralint
|
||||
ralint: $(ralint_TARGET)
|
||||
|
||||
filex_SRCS = $(shell find FileExtractor/ -iname '*.cs')
|
||||
filex_TARGET = FileExtractor.exe
|
||||
filex_KIND = exe
|
||||
filex_DEPS = $(fileformats_TARGET)
|
||||
filex_LIBS = $(COMMON_LIBS) $(filex_DEPS)
|
||||
# Extracts files from packages (mixfiles, zips, etc)
|
||||
filex_SRCS = $(shell find FileExtractor/ -iname '*.cs')
|
||||
filex_TARGET = FileExtractor.exe
|
||||
filex_KIND = exe
|
||||
filex_DEPS = $(fileformats_TARGET)
|
||||
filex_LIBS = $(COMMON_LIBS) $(filex_DEPS)
|
||||
PROGRAMS += filex
|
||||
filex: $(filex_TARGET)
|
||||
|
||||
# Builds and exports tilesets from a bitmap
|
||||
tsbuild_SRCS = $(shell find OpenRA.TilesetBuilder/ -iname '*.cs')
|
||||
tsbuild_TARGET = TilesetBuilder.exe
|
||||
tsbuild_KIND = winexe
|
||||
tsbuild_DEPS = $(fileformats_TARGET) $(game_TARGET)
|
||||
tsbuild_LIBS = $(COMMON_LIBS) $(tsbuild_DEPS) System.Windows.Forms.dll
|
||||
tsbuild_EXTRA = -resource:OpenRA.TilesetBuilder.Form1.resources
|
||||
PROGRAMS += tsbuild
|
||||
OpenRA.TilesetBuilder.Form1.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/Form1.resx OpenRA.TilesetBuilder.Form1.resources 1> /dev/null
|
||||
tsbuild: OpenRA.TilesetBuilder.Form1.resources $(tsbuild_TARGET)
|
||||
|
||||
#
|
||||
# Launchers / Utilities
|
||||
#
|
||||
# Patches binary headers to work around a mono bug
|
||||
fixheader: packaging/fixheader.cs
|
||||
@$(CSC) packaging/fixheader.cs $(CSFLAGS) -out:fixheader.exe -t:exe $(COMMON_LIBS:%=-r:%)
|
||||
PHONY += fixheader
|
||||
|
||||
# Backend for the launcher apps - queries game/mod info and applies actions to an install
|
||||
utility_SRCS = $(shell find OpenRA.Utility/ -iname '*.cs')
|
||||
utility_TARGET = OpenRA.Utility.exe
|
||||
utility_KIND = exe
|
||||
utility_DEPS = $(fileformats_TARGET) thirdparty/ICSharpCode.SharpZipLib.dll
|
||||
utility_LIBS = $(COMMON_LIBS) $(utility_DEPS)
|
||||
PROGRAMS += utility
|
||||
utility: $(utility_TARGET)
|
||||
|
||||
# Windows launcher
|
||||
winlaunch_SRCS = $(shell find OpenRA.Launcher/ -iname '*.cs')
|
||||
winlaunch_TARGET = OpenRA.Launcher.exe
|
||||
winlaunch_KIND = winexe
|
||||
winlaunch_DEPS =
|
||||
winlaunch_LIBS = $(COMMON_LIBS) System.Windows.Forms.dll
|
||||
winlaunch_EXTRA = -resource:OpenRA.Launcher.MainForm.resources \
|
||||
-resource:OpenRA.Launcher.InstallPackagesDialog.resources \
|
||||
-resource:OpenRA.Launcher.ConfigureModsDialog.resources
|
||||
winlaunch_EXTRA = -resource:OpenRA.Launcher.Launcher.resources
|
||||
PROGRAMS += winlaunch
|
||||
OpenRA.Launcher.Launcher.resources:
|
||||
resgen2 OpenRA.Launcher/Launcher.resx OpenRA.Launcher.Launcher.resources 1> /dev/null
|
||||
winlaunch: OpenRA.Launcher.Launcher.resources $(winlaunch_TARGET)
|
||||
|
||||
# -platform:x86
|
||||
.PHONY: $(PHONY) $(PROGRAMS)
|
||||
|
||||
.SUFFIXES:
|
||||
.PHONY: clean all game tool default mods mod_ra mod_cnc install uninstall editor_res editor tsbuild ralint seqed filex utility winlaunch
|
||||
core: game editor
|
||||
package: game editor utility
|
||||
all: game tools
|
||||
tools: editor ralint seqed filex tsbuild utility winlaunch
|
||||
game: $(fileformats_TARGET) $(rcg_TARGET) $(rgl_TARGET) $(rnull_TARGET) $(game_TARGET) $(ra_TARGET) $(cnc_TARGET)
|
||||
#
|
||||
# Generate build rules for each target defined above in PROGRAMS
|
||||
#
|
||||
define BUILD_ASSEMBLY
|
||||
|
||||
clean:
|
||||
@-rm *.exe *.dll *.mdb mods/**/*.dll mods/**/*.mdb *.resources
|
||||
$$($(1)_TARGET): $$($(1)_SRCS) Makefile $$($(1)_DEPS)
|
||||
@echo CSC $$(@)
|
||||
@$(CSC) $$($(1)_LIBS:%=-r:%) \
|
||||
-out:$$(@) $(CSFLAGS) $$($(1)_FLAGS) \
|
||||
-define:"$(DEFINE)" \
|
||||
-t:"$$($(1)_KIND)" \
|
||||
$$($(1)_EXTRA) \
|
||||
$$($(1)_SRCS)
|
||||
@test -e fixheader.exe && mono fixheader.exe $$(@) || ``
|
||||
endef
|
||||
|
||||
distclean: clean
|
||||
$(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))
|
||||
|
||||
|
||||
#
|
||||
# Install / Uninstall for *nix
|
||||
#
|
||||
prefix = /usr/local
|
||||
datarootdir = $(prefix)/share
|
||||
datadir = $(datarootdir)
|
||||
bindir = $(prefix)/bin
|
||||
BIN_INSTALL_DIR = $(DESTDIR)$(bindir)
|
||||
INSTALL_DIR = $(DESTDIR)$(datadir)/openra
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL)
|
||||
CORE = fileformats rcg rgl rnull game editor utility winlaunch
|
||||
|
||||
install: all
|
||||
@-echo "Installing OpenRA to $(INSTALL_DIR)"
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) $(foreach prog,$(CORE),$($(prog)_TARGET)) $(INSTALL_DIR)
|
||||
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/cnc
|
||||
@$(INSTALL_PROGRAM) $(cnc_TARGET) $(INSTALL_DIR)/mods/cnc
|
||||
@$(INSTALL_PROGRAM) $(mod_cnc_TARGET) $(INSTALL_DIR)/mods/cnc
|
||||
@-cp $(foreach f,$(shell ls mods/cnc --hide=*.dll),mods/cnc/$(f)) $(INSTALL_DIR)/mods/cnc
|
||||
@cp -r mods/cnc/maps $(INSTALL_DIR)/mods/cnc
|
||||
@cp -r mods/cnc/chrome $(INSTALL_DIR)/mods/cnc
|
||||
@@ -143,7 +223,7 @@ install: all
|
||||
@cp -r mods/cnc/uibits $(INSTALL_DIR)/mods/cnc
|
||||
|
||||
@$(INSTALL_PROGRAM) -d $(INSTALL_DIR)/mods/ra
|
||||
@$(INSTALL_PROGRAM) $(ra_TARGET) $(INSTALL_DIR)/mods/ra
|
||||
@$(INSTALL_PROGRAM) $(mod_ra_TARGET) $(INSTALL_DIR)/mods/ra
|
||||
@-cp $(foreach f,$(shell ls mods/ra --hide=*.dll),mods/ra/$(f)) $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/maps $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/bits $(INSTALL_DIR)/mods/ra
|
||||
@@ -152,10 +232,10 @@ install: all
|
||||
@cp -r mods/ra/tilesets $(INSTALL_DIR)/mods/ra
|
||||
@cp -r mods/ra/uibits $(INSTALL_DIR)/mods/ra
|
||||
|
||||
@cp -r shaders $(INSTALL_DIR)
|
||||
@cp -r glsl $(INSTALL_DIR)
|
||||
@cp -r cg $(INSTALL_DIR)
|
||||
@cp *.ttf $(INSTALL_DIR)
|
||||
@cp --parents -r thirdparty/Tao $(INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) thirdparty/WindowsBase.dll $(INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) thirdparty/ICSharpCode.SharpZipLib.dll $(INSTALL_DIR)
|
||||
@-$(INSTALL_PROGRAM) VERSION $(INSTALL_DIR)
|
||||
|
||||
@@ -164,7 +244,7 @@ install: all
|
||||
@echo "mono "$(datadir)"/openra/OpenRA.Game.exe SupportDir=~/.openra \"$$""@\"" >> openra
|
||||
@$(INSTALL_PROGRAM) -d $(BIN_INSTALL_DIR)
|
||||
@$(INSTALL_PROGRAM) -m +rx openra $(BIN_INSTALL_DIR)
|
||||
|
||||
|
||||
@echo "OpenRA is now installed. You will now want to download"
|
||||
@echo "http://open-ra.org/get-dependency.php?file=ra-packages and"
|
||||
@echo "http://open-ra.org/get-dependency.php?file=cnc-packages"
|
||||
@@ -176,53 +256,4 @@ install: all
|
||||
|
||||
uninstall:
|
||||
@-rm -r $(INSTALL_DIR)
|
||||
@-rm $(DESTDIR)$(bindir)/openra
|
||||
|
||||
mod_ra: $(ra_TARGET) $(ralint_TARGET)
|
||||
mono RALint.exe ra
|
||||
mod_cnc: $(cnc_TARGET) $(ralint_TARGET)
|
||||
mono RALint.exe cnc
|
||||
mods: mod_ra mod_cnc
|
||||
|
||||
OpenRA.Editor.MapSelect.resources:
|
||||
resgen2 OpenRA.Editor/MapSelect.resx OpenRA.Editor.MapSelect.resources 1> /dev/null
|
||||
|
||||
OpenRA.Editor.Form1.resources:
|
||||
resgen2 OpenRA.Editor/Form1.resx OpenRA.Editor.Form1.resources 1> /dev/null
|
||||
editor: OpenRA.Editor.MapSelect.resources OpenRA.Editor.Form1.resources $(editor_TARGET)
|
||||
ralint: $(ralint_TARGET)
|
||||
seqed: SequenceEditor.Form1.resources $(seqed_TARGET)
|
||||
SequenceEditor.Form1.resources:
|
||||
resgen2 SequenceEditor/Form1.resx SequenceEditor.Form1.resources 1> /dev/null
|
||||
filex: $(filex_TARGET)
|
||||
tsbuild: OpenRA.TilesetBuilder.Form1.resources $(tsbuild_TARGET)
|
||||
OpenRA.TilesetBuilder.Form1.resources:
|
||||
resgen2 OpenRA.TilesetBuilder/Form1.resx OpenRA.TilesetBuilder.Form1.resources 1> /dev/null
|
||||
|
||||
utility: $(utility_TARGET)
|
||||
winlaunch: OpenRA.Launcher.MainForm.resources OpenRA.Launcher.InstallPackagesDialog.resources \
|
||||
OpenRA.Launcher.ConfigureModsDialog.resources $(winlaunch_TARGET)
|
||||
OpenRA.Launcher.MainForm.resources:
|
||||
resgen2 OpenRA.Launcher/MainForm.resx OpenRA.Launcher.MainForm.resources 1> /dev/null
|
||||
OpenRA.Launcher.InstallPackagesDialog.resources:
|
||||
resgen2 OpenRA.Launcher/InstallPackagesDialog.resx OpenRA.Launcher.InstallPackagesDialog.resources 1> /dev/null
|
||||
OpenRA.Launcher.ConfigureModsDialog.resources:
|
||||
resgen2 OpenRA.Launcher/ConfigureModsDialog.resx OpenRA.Launcher.ConfigureModsDialog.resources 1> /dev/null
|
||||
|
||||
fixheader: packaging/fixheader.cs
|
||||
@$(CSC) packaging/fixheader.cs $(CSFLAGS) -out:fixheader.exe -t:exe $(COMMON_LIBS:%=-r:%)
|
||||
|
||||
define BUILD_ASSEMBLY
|
||||
|
||||
$$($(1)_TARGET): $$($(1)_SRCS) Makefile $$($(1)_DEPS) fixheader
|
||||
@echo CSC $$(@)
|
||||
@$(CSC) $$($(1)_LIBS:%=-r:%) \
|
||||
-out:$$(@) $(CSFLAGS) $$($(1)_FLAGS) \
|
||||
-define:"$(DEFINE)" \
|
||||
-t:"$$($(1)_KIND)" \
|
||||
$$($(1)_EXTRA) \
|
||||
$$($(1)_SRCS)
|
||||
@mono fixheader.exe $$(@)
|
||||
endef
|
||||
|
||||
$(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog))))
|
||||
@-rm $(DESTDIR)$(bindir)/openra
|
||||
@@ -94,7 +94,7 @@ namespace OpenRA.Editor
|
||||
void PrepareMapResources(Manifest manifest, Map map)
|
||||
{
|
||||
Rules.LoadRules(manifest, map);
|
||||
tileset = Rules.TileSets[map.Theater];
|
||||
tileset = Rules.TileSets[map.Tileset];
|
||||
tileset.LoadTiles();
|
||||
var palette = new Palette(FileSystem.Open(tileset.Palette), true);
|
||||
|
||||
@@ -213,16 +213,18 @@ namespace OpenRA.Editor
|
||||
{
|
||||
rd.width.Value = surface1.Map.MapSize.X;
|
||||
rd.height.Value = surface1.Map.MapSize.Y;
|
||||
rd.cordonLeft.Value = surface1.Map.TopLeft.X;
|
||||
rd.cordonTop.Value = surface1.Map.TopLeft.Y;
|
||||
rd.cordonRight.Value = surface1.Map.BottomRight.X;
|
||||
rd.cordonBottom.Value = surface1.Map.BottomRight.Y;
|
||||
rd.cordonLeft.Value = surface1.Map.Bounds.Left;
|
||||
rd.cordonTop.Value = surface1.Map.Bounds.Top;
|
||||
rd.cordonRight.Value = surface1.Map.Bounds.Right;
|
||||
rd.cordonBottom.Value = surface1.Map.Bounds.Bottom;
|
||||
|
||||
if (DialogResult.OK != rd.ShowDialog())
|
||||
return;
|
||||
|
||||
surface1.Map.TopLeft = new int2((int)rd.cordonLeft.Value, (int)rd.cordonTop.Value);
|
||||
surface1.Map.BottomRight = new int2((int)rd.cordonRight.Value, (int)rd.cordonBottom.Value);
|
||||
surface1.Map.ResizeCordon((int)rd.cordonLeft.Value,
|
||||
(int)rd.cordonTop.Value,
|
||||
(int)rd.cordonRight.Value,
|
||||
(int)rd.cordonBottom.Value);
|
||||
|
||||
if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y)
|
||||
{
|
||||
|
||||
2
OpenRA.Editor/MapSelect.Designer.cs
generated
2
OpenRA.Editor/MapSelect.Designer.cs
generated
@@ -256,7 +256,7 @@
|
||||
this.lblTheater.Name = "lblTheater";
|
||||
this.lblTheater.Size = new System.Drawing.Size(47, 13);
|
||||
this.lblTheater.TabIndex = 11;
|
||||
this.lblTheater.Text = "Theater:";
|
||||
this.lblTheater.Text = "Tileset:";
|
||||
//
|
||||
// txtAuthor
|
||||
//
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA.Editor
|
||||
var map = new Map(new Folder(Path.Combine(MapFolderPath, MapList.SelectedItems[0].Text), 0));
|
||||
txtTitle.Text = map.Title;
|
||||
txtAuthor.Text = map.Author;
|
||||
txtTheater.Text = map.Theater;
|
||||
txtTheater.Text = map.Tileset;
|
||||
txtDesc.Text = map.Description;
|
||||
pbMinimap.Image = null;
|
||||
try
|
||||
|
||||
2
OpenRA.Editor/NewMapDialog.Designer.cs
generated
2
OpenRA.Editor/NewMapDialog.Designer.cs
generated
@@ -221,7 +221,7 @@
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(44, 13);
|
||||
this.label4.TabIndex = 14;
|
||||
this.label4.Text = "Theater";
|
||||
this.label4.Text = "Tileset";
|
||||
//
|
||||
// theater
|
||||
//
|
||||
|
||||
@@ -97,9 +97,9 @@ namespace OpenRA.Editor
|
||||
{
|
||||
var ri = info.Traits.Get<RenderSimpleInfo>();
|
||||
string image = null;
|
||||
if (ri.OverrideTheater != null)
|
||||
for (int i = 0; i < ri.OverrideTheater.Length; i++)
|
||||
if (ri.OverrideTheater[i] == tileset.Id)
|
||||
if (ri.OverrideTileset != null)
|
||||
for (int i = 0; i < ri.OverrideTileset.Length; i++)
|
||||
if (ri.OverrideTileset[i] == tileset.Id)
|
||||
image = ri.OverrideImage[i];
|
||||
|
||||
image = image ?? ri.Image ?? info.Name;
|
||||
|
||||
@@ -505,10 +505,10 @@ namespace OpenRA.Editor
|
||||
}
|
||||
|
||||
e.Graphics.DrawRectangle(CordonPen,
|
||||
Map.XOffset * TileSet.TileSize * Zoom + Offset.X,
|
||||
Map.YOffset * TileSet.TileSize * Zoom + Offset.Y,
|
||||
Map.Width * TileSet.TileSize * Zoom,
|
||||
Map.Height * TileSet.TileSize * Zoom);
|
||||
Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X,
|
||||
Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y,
|
||||
Map.Bounds.Width * TileSet.TileSize * Zoom,
|
||||
Map.Bounds.Height * TileSet.TileSize * Zoom);
|
||||
|
||||
foreach (var ar in Map.Actors)
|
||||
DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type],
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace OpenRA.FileFormats
|
||||
[FieldLoader.Load] public bool Selectable;
|
||||
|
||||
[FieldLoader.Load] public string Title;
|
||||
[FieldLoader.Load] public string Type = "Conquest";
|
||||
[FieldLoader.Load] public string Description;
|
||||
[FieldLoader.Load] public string Author;
|
||||
[FieldLoader.Load] public int PlayerCount;
|
||||
@@ -35,8 +36,7 @@ namespace OpenRA.FileFormats
|
||||
|
||||
[FieldLoader.Load] public int2 TopLeft;
|
||||
[FieldLoader.Load] public int2 BottomRight;
|
||||
public int Width { get { return BottomRight.X - TopLeft.X; } }
|
||||
public int Height { get { return BottomRight.Y - TopLeft.Y; } }
|
||||
public Rectangle Bounds;
|
||||
|
||||
public MapStub() {} // Hack for the editor - not used for anything important
|
||||
public MapStub(IFolder container)
|
||||
@@ -44,7 +44,8 @@ namespace OpenRA.FileFormats
|
||||
Container = container;
|
||||
var yaml = MiniYaml.FromStream(Container.GetContent("map.yaml"));
|
||||
FieldLoader.Load( this, new MiniYaml( null, yaml ) );
|
||||
|
||||
|
||||
Bounds = Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
|
||||
Uid = Container.GetContent("map.uid").ReadAllText();
|
||||
}
|
||||
|
||||
|
||||
@@ -72,5 +72,11 @@ namespace OpenRA
|
||||
{
|
||||
return a + ( b - a ) * mul / div;
|
||||
}
|
||||
|
||||
public int2 Clamp(Rectangle r)
|
||||
{
|
||||
return new int2(Math.Min(r.Right, Math.Max(X, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(Y, r.Top)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA
|
||||
[Sync]
|
||||
public Player Owner;
|
||||
|
||||
IActivity currentActivity;
|
||||
private IActivity currentActivity;
|
||||
public Group Group;
|
||||
|
||||
internal Actor(World world, string name, TypeDictionary initDict )
|
||||
@@ -77,7 +77,7 @@ namespace OpenRA
|
||||
|
||||
public bool IsIdle
|
||||
{
|
||||
get { return currentActivity == null || currentActivity is Idle; }
|
||||
get { return currentActivity == null; }
|
||||
}
|
||||
|
||||
OpenRA.FileFormats.Lazy<float2> Size;
|
||||
@@ -91,17 +91,10 @@ namespace OpenRA
|
||||
|
||||
public RectangleF GetBounds(bool useAltitude)
|
||||
{
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
|
||||
var size = Size.Value;
|
||||
|
||||
/* apply scaling */
|
||||
var scale = this.TraitOrDefault<Scale>();
|
||||
if (scale != null && scale.Info.Value != 1)
|
||||
size = size*scale.Info.Value;
|
||||
|
||||
var loc = CenterLocation - 0.5f * size;
|
||||
var size = Size.Value;
|
||||
var loc = CenterLocation - 0.5f * size;
|
||||
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
if (si != null && si.Bounds != null && si.Bounds.Length > 2)
|
||||
loc += new float2(si.Bounds[2], si.Bounds[3]);
|
||||
|
||||
@@ -137,7 +130,6 @@ namespace OpenRA
|
||||
currentActivity.Cancel( this );
|
||||
}
|
||||
|
||||
// For pathdebug, et al
|
||||
public IActivity GetCurrentActivity()
|
||||
{
|
||||
return currentActivity;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Effects
|
||||
{
|
||||
public class MoveFlash : IEffect
|
||||
{
|
||||
Animation anim = new Animation("moveflsh");
|
||||
float2 pos;
|
||||
|
||||
|
||||
public MoveFlash( World world, int2 cell )
|
||||
{
|
||||
this.pos = Game.CellSize * (cell + new float2(0.5f, 0.5f));
|
||||
anim.PlayThen( "idle",
|
||||
() => world.AddFrameEndTask(
|
||||
w => w.Remove( this ) ) );
|
||||
}
|
||||
|
||||
public MoveFlash( World world, float2 pos )
|
||||
{
|
||||
this.pos = pos;
|
||||
anim.PlayThen( "idle",
|
||||
() => world.AddFrameEndTask(
|
||||
w => w.Remove( this ) ) );
|
||||
}
|
||||
|
||||
public void Tick( World world ) { anim.Tick(); }
|
||||
|
||||
public IEnumerable<Renderable> Render()
|
||||
{
|
||||
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow", (int)pos.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,8 +77,9 @@ namespace OpenRA
|
||||
ConnectionStateChanged( orderManager );
|
||||
}
|
||||
|
||||
internal static int RenderFrame = 0;
|
||||
internal static int LocalTick { get { return orderManager.LocalFrameNumber; } }
|
||||
public static int RenderFrame = 0;
|
||||
public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } }
|
||||
public static int LocalTick { get { return orderManager.LocalFrameNumber; } }
|
||||
const int NetTickScale = 3; // 120ms net tick for 40ms local tick
|
||||
|
||||
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
|
||||
@@ -168,7 +169,7 @@ namespace OpenRA
|
||||
BeforeGameStart();
|
||||
|
||||
var map = modData.PrepareMap(mapUID);
|
||||
viewport = new Viewport(new int2(Renderer.Resolution), map.TopLeft, map.BottomRight, Renderer);
|
||||
viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer);
|
||||
orderManager.world = new World(modData.Manifest, map, orderManager);
|
||||
worldRenderer = new WorldRenderer(orderManager.world);
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap TerrainBitmap(Map map, bool actualSize)
|
||||
{
|
||||
var tileset = Rules.TileSets[map.Tileset];
|
||||
var width = map.Width;
|
||||
var height = map.Height;
|
||||
var width = map.Bounds.Width;
|
||||
var height = map.Bounds.Height;
|
||||
|
||||
if (!actualSize)
|
||||
{
|
||||
width = height = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
width = height = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
}
|
||||
|
||||
Bitmap terrain = new Bitmap(width, height);
|
||||
@@ -45,11 +45,11 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
for (var x = 0; x < map.Width; x++)
|
||||
for (var y = 0; y < map.Height; y++)
|
||||
for (var x = 0; x < map.Bounds.Width; x++)
|
||||
for (var y = 0; y < map.Bounds.Height; y++)
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
var type = tileset.GetTerrainType(map.MapTiles[mapX, mapY]);
|
||||
if (!tileset.Terrain.ContainsKey(type))
|
||||
throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type));
|
||||
@@ -75,11 +75,11 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
for (var x = 0; x < map.Width; x++)
|
||||
for (var y = 0; y < map.Height; y++)
|
||||
for (var x = 0; x < map.Bounds.Width; x++)
|
||||
for (var y = 0; y < map.Bounds.Height; y++)
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
if (map.MapResources[mapX, mapY].type == 0)
|
||||
continue;
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap CustomTerrainBitmap(World world)
|
||||
{
|
||||
var map = world.Map;
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
Bitmap bitmap = new Bitmap(size, size);
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
@@ -109,11 +109,11 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
for (var x = 0; x < map.Width; x++)
|
||||
for (var y = 0; y < map.Height; y++)
|
||||
for (var x = 0; x < map.Bounds.Width; x++)
|
||||
for (var y = 0; y < map.Bounds.Height; y++)
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
var custom = map.CustomTerrain[mapX,mapY];
|
||||
if (custom == null)
|
||||
continue;
|
||||
@@ -127,7 +127,7 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap ActorsBitmap(World world)
|
||||
{
|
||||
var map = world.Map;
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
Bitmap bitmap = new Bitmap(size, size);
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
@@ -136,17 +136,15 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
var player = world.LocalPlayer;
|
||||
|
||||
foreach (var t in world.Queries.WithTraitMultiple<IRadarSignature>())
|
||||
{
|
||||
if (!t.Actor.IsVisible(player))
|
||||
if (!world.LocalShroud.IsVisible(t.Actor))
|
||||
continue;
|
||||
|
||||
var color = t.Trait.RadarSignatureColor(t.Actor);
|
||||
foreach (var cell in t.Trait.RadarSignatureCells(t.Actor))
|
||||
if (world.Map.IsInMap(cell))
|
||||
*(c + ((cell.Y - world.Map.TopLeft.Y) * bitmapData.Stride >> 2) + cell.X - world.Map.TopLeft.X) = color.ToArgb();
|
||||
*(c + ((cell.Y - world.Map.Bounds.Top) * bitmapData.Stride >> 2) + cell.X - world.Map.Bounds.Left) = color.ToArgb();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,28 +155,29 @@ namespace OpenRA.Graphics
|
||||
public static Bitmap ShroudBitmap(World world)
|
||||
{
|
||||
var map = world.Map;
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Width, map.Height));
|
||||
var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height));
|
||||
Bitmap bitmap = new Bitmap(size, size);
|
||||
if (world.LocalShroud.Disabled)
|
||||
return bitmap;
|
||||
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
|
||||
var shroud = Color.Black.ToArgb();
|
||||
var fog = Color.FromArgb(128, Color.Black).ToArgb();
|
||||
|
||||
var playerShroud = world.LocalPlayer.Shroud;
|
||||
|
||||
unsafe
|
||||
{
|
||||
int* c = (int*)bitmapData.Scan0;
|
||||
|
||||
for (var x = 0; x < map.Width; x++)
|
||||
for (var y = 0; y < map.Height; y++)
|
||||
for (var x = 0; x < map.Bounds.Width; x++)
|
||||
for (var y = 0; y < map.Bounds.Height; y++)
|
||||
{
|
||||
var mapX = x + map.TopLeft.X;
|
||||
var mapY = y + map.TopLeft.Y;
|
||||
if (!playerShroud.IsExplored(mapX, mapY))
|
||||
var mapX = x + map.Bounds.Left;
|
||||
var mapY = y + map.Bounds.Top;
|
||||
if (!world.LocalShroud.IsExplored(mapX, mapY))
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = shroud;
|
||||
else if (!playerShroud.IsVisible(mapX,mapY))
|
||||
else if (!world.LocalShroud.IsVisible(mapX,mapY))
|
||||
*(c + (y * bitmapData.Stride >> 2) + x) = fog;
|
||||
}
|
||||
}
|
||||
|
||||
161
OpenRA.Game/Graphics/ShroudRenderer.cs
Normal file
161
OpenRA.Game/Graphics/ShroudRenderer.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class ShroudRenderer
|
||||
{
|
||||
Traits.Shroud shroud;
|
||||
Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow");
|
||||
Sprite[,] sprites, fogSprites;
|
||||
|
||||
bool dirty = true;
|
||||
Map map;
|
||||
|
||||
public ShroudRenderer(World world)
|
||||
{
|
||||
this.shroud = world.LocalShroud;
|
||||
this.map = world.Map;
|
||||
|
||||
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
shroud.Dirty += () => dirty = true;
|
||||
}
|
||||
|
||||
static readonly byte[][] SpecialShroudTiles =
|
||||
{
|
||||
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
|
||||
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
|
||||
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
|
||||
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
|
||||
new byte[] { 44 },
|
||||
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
|
||||
new byte[] { 40 },
|
||||
new byte[] { 35, 24, 17, 18 },
|
||||
new byte[] { 39, 39, 29, 29 },
|
||||
new byte[] { 45 },
|
||||
new byte[] { 43 },
|
||||
new byte[] { 38, 28 },
|
||||
new byte[] { 42 },
|
||||
new byte[] { 41 },
|
||||
new byte[] { 46 },
|
||||
};
|
||||
|
||||
Sprite ChooseShroud(int i, int j)
|
||||
{
|
||||
if( !shroud.IsExplored( i, j ) ) return shadowBits[ 0xf ];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if( !shroud.IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; }
|
||||
if( !shroud.IsExplored( i + 1, j ) ) { v |= 2; u |= 6; }
|
||||
if( !shroud.IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; }
|
||||
if( !shroud.IsExplored( i - 1, j ) ) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if( !shroud.IsExplored( i - 1, j - 1 ) ) u |= 1;
|
||||
if( !shroud.IsExplored( i + 1, j - 1 ) ) u |= 2;
|
||||
if( !shroud.IsExplored( i + 1, j + 1 ) ) u |= 4;
|
||||
if( !shroud.IsExplored( i - 1, j + 1 ) ) u |= 8;
|
||||
|
||||
return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ];
|
||||
}
|
||||
|
||||
Sprite ChooseFog(int i, int j)
|
||||
{
|
||||
if (!shroud.IsVisible(i,j)) return shadowBits[0xf];
|
||||
if (!shroud.IsExplored(i, j)) return shadowBits[0xf];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if (!shroud.IsVisible(i, j - 1)) { v |= 1; u |= 3; }
|
||||
if (!shroud.IsVisible(i + 1, j)) { v |= 2; u |= 6; }
|
||||
if (!shroud.IsVisible(i, j + 1)) { v |= 4; u |= 12; }
|
||||
if (!shroud.IsVisible(i - 1, j)) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if (!shroud.IsVisible(i - 1, j - 1)) u |= 1;
|
||||
if (!shroud.IsVisible(i + 1, j - 1)) u |= 2;
|
||||
if (!shroud.IsVisible(i + 1, j + 1)) u |= 4;
|
||||
if (!shroud.IsVisible(i - 1, j + 1)) u |= 8;
|
||||
|
||||
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
|
||||
}
|
||||
|
||||
internal void Draw( WorldRenderer wr )
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
dirty = false;
|
||||
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
sprites[i, j] = ChooseShroud(i, j);
|
||||
|
||||
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
fogSprites[i, j] = ChooseFog(i, j);
|
||||
}
|
||||
|
||||
var clipRect = Game.viewport.WorldBounds(wr.world);
|
||||
DrawShroud( wr, clipRect, fogSprites, "fog" );
|
||||
DrawShroud( wr, clipRect, sprites, "shroud" );
|
||||
}
|
||||
|
||||
void DrawShroud( WorldRenderer wr, Rectangle clip, Sprite[,] s, string pal )
|
||||
{
|
||||
var shroudPalette = wr.GetPaletteIndex(pal);
|
||||
|
||||
for (var j = clip.Top; j < clip.Bottom; j++)
|
||||
{
|
||||
var starti = clip.Left;
|
||||
var last = shadowBits[0x0f];
|
||||
for (var i = clip.Left; i < clip.Right; i++)
|
||||
{
|
||||
if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f])
|
||||
|| (s[i, j] == shadowBits[0] && last == shadowBits[0]))
|
||||
continue;
|
||||
|
||||
if (starti != i)
|
||||
{
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (i - starti), Game.CellSize));
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
s[i, j].DrawAt(
|
||||
Game.CellSize * new float2(i, j),
|
||||
shroudPalette);
|
||||
starti = i + 1;
|
||||
last = s[i, j];
|
||||
}
|
||||
|
||||
if (starti < clip.Right)
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (clip.Right - starti), Game.CellSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,15 +34,16 @@ namespace OpenRA.Graphics
|
||||
var tileMapping = new Cache<TileReference<ushort,byte>, Sprite>(
|
||||
x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize));
|
||||
|
||||
Vertex[] vertices = new Vertex[4 * map.Height * map.Width];
|
||||
ushort[] indices = new ushort[6 * map.Height * map.Width];
|
||||
Vertex[] vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width];
|
||||
ushort[] indices = new ushort[6 * map.Bounds.Height * map.Bounds.Width];
|
||||
|
||||
terrainSheet = tileMapping[map.MapTiles[map.TopLeft.X, map.TopLeft.Y]].sheet;
|
||||
terrainSheet = tileMapping[map.MapTiles[map.Bounds.Left, map.Bounds.Top]].sheet;
|
||||
|
||||
int nv = 0;
|
||||
int ni = 0;
|
||||
for( int j = map.TopLeft.Y ; j < map.BottomRight.Y; j++ )
|
||||
for( int i = map.TopLeft.X ; i < map.BottomRight.X; i++ )
|
||||
|
||||
for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ )
|
||||
for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ )
|
||||
{
|
||||
Sprite tile = tileMapping[map.MapTiles[i, j]];
|
||||
// TODO: The zero below should explicitly refer to the terrain palette, but this code is called
|
||||
@@ -64,28 +65,28 @@ namespace OpenRA.Graphics
|
||||
|
||||
public void Draw( WorldRenderer wr, Viewport viewport )
|
||||
{
|
||||
int indicesPerRow = map.Width * 6;
|
||||
int verticesPerRow = map.Width * 4;
|
||||
int indicesPerRow = map.Bounds.Width * 6;
|
||||
int verticesPerRow = map.Bounds.Width * 4;
|
||||
|
||||
int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2);
|
||||
|
||||
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.YOffset);
|
||||
int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.Bounds.Top);
|
||||
int lastRow = firstRow + visibleRows;
|
||||
|
||||
if (lastRow < 0 || firstRow > map.Height)
|
||||
if (lastRow < 0 || firstRow > map.Bounds.Height)
|
||||
return;
|
||||
|
||||
if (firstRow < 0) firstRow = 0;
|
||||
if (lastRow > map.Height) lastRow = map.Height;
|
||||
if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height;
|
||||
|
||||
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.Disabled && world.LocalPlayer.Shroud.Bounds.HasValue)
|
||||
if (world.LocalPlayer != null && !world.LocalShroud.Disabled && world.LocalShroud.Bounds.HasValue)
|
||||
{
|
||||
var r = world.LocalPlayer.Shroud.Bounds.Value;
|
||||
if (firstRow < r.Top - map.YOffset)
|
||||
firstRow = r.Top - map.YOffset;
|
||||
var r = world.LocalShroud.Bounds.Value;
|
||||
if (firstRow < r.Top - map.Bounds.Top)
|
||||
firstRow = r.Top - map.Bounds.Top;
|
||||
|
||||
if (firstRow > r.Bottom - map.YOffset)
|
||||
firstRow = r.Bottom - map.YOffset;
|
||||
if (firstRow > r.Bottom - map.Bounds.Top)
|
||||
firstRow = r.Bottom - map.Bounds.Top;
|
||||
}
|
||||
|
||||
if( lastRow < firstRow ) lastRow = firstRow;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
@@ -21,8 +22,7 @@ namespace OpenRA.Graphics
|
||||
readonly int2 screenSize;
|
||||
int2 scrollPosition;
|
||||
readonly Renderer renderer;
|
||||
readonly int2 mapStart;
|
||||
readonly int2 mapEnd;
|
||||
readonly Rectangle adjustedMapBounds;
|
||||
|
||||
public float2 Location { get { return scrollPosition; } }
|
||||
|
||||
@@ -52,60 +52,43 @@ namespace OpenRA.Graphics
|
||||
|
||||
private int2 NormalizeScrollPosition(int2 newScrollPosition)
|
||||
{
|
||||
var topLeftBorder = Game.CellSize* mapStart;
|
||||
var bottomRightBorder = Game.CellSize* mapEnd;
|
||||
|
||||
if(newScrollPosition.Y < topLeftBorder.Y - screenSize.Y/2)
|
||||
newScrollPosition.Y = topLeftBorder.Y - screenSize.Y/2;
|
||||
if(newScrollPosition.X < topLeftBorder.X - screenSize.X/2)
|
||||
newScrollPosition.X = topLeftBorder.X - screenSize.X/2;
|
||||
if(newScrollPosition.Y > bottomRightBorder.Y - screenSize.Y/2)
|
||||
newScrollPosition.Y = bottomRightBorder.Y - screenSize.Y/2;
|
||||
if(newScrollPosition.X > bottomRightBorder.X - screenSize.X/2)
|
||||
newScrollPosition.X = bottomRightBorder.X - screenSize.X/2;
|
||||
|
||||
return newScrollPosition;
|
||||
return newScrollPosition.Clamp(adjustedMapBounds);
|
||||
}
|
||||
|
||||
public ScrollDirection GetBlockedDirections()
|
||||
{
|
||||
int2 topLeftBorder = (Game.CellSize* mapStart);
|
||||
int2 bottomRightBorder = (Game.CellSize* mapEnd);
|
||||
|
||||
ScrollDirection blockedDirections = ScrollDirection.None;
|
||||
|
||||
if(scrollPosition.Y <= topLeftBorder.Y - screenSize.Y/2)
|
||||
if(scrollPosition.Y <= adjustedMapBounds.Top)
|
||||
blockedDirections = blockedDirections.Set(ScrollDirection.Up, true);
|
||||
if(scrollPosition.X <= topLeftBorder.X - screenSize.X/2)
|
||||
if(scrollPosition.X <= adjustedMapBounds.Left)
|
||||
blockedDirections = blockedDirections.Set(ScrollDirection.Left, true);
|
||||
if(scrollPosition.Y >= bottomRightBorder.Y - screenSize.Y/2)
|
||||
if(scrollPosition.Y >= adjustedMapBounds.Bottom)
|
||||
blockedDirections = blockedDirections.Set(ScrollDirection.Down, true);
|
||||
if(scrollPosition.X >= bottomRightBorder.X - screenSize.X/2)
|
||||
if(scrollPosition.X >= adjustedMapBounds.Right)
|
||||
blockedDirections = blockedDirections.Set(ScrollDirection.Right, true);
|
||||
|
||||
return blockedDirections;
|
||||
}
|
||||
|
||||
public Viewport(int2 screenSize, int2 mapStart, int2 mapEnd, Renderer renderer)
|
||||
public Viewport(int2 screenSize, Rectangle mapBounds, Renderer renderer)
|
||||
{
|
||||
this.screenSize = screenSize;
|
||||
this.renderer = renderer;
|
||||
this.mapStart = mapStart;
|
||||
this.mapEnd = mapEnd;
|
||||
|
||||
this.scrollPosition = Game.CellSize* mapStart;
|
||||
this.adjustedMapBounds = new Rectangle(Game.CellSize*mapBounds.X - screenSize.X/2,
|
||||
Game.CellSize*mapBounds.Y - screenSize.Y/2,
|
||||
Game.CellSize*mapBounds.Width,
|
||||
Game.CellSize*mapBounds.Height);
|
||||
this.scrollPosition = new int2(adjustedMapBounds.Location) + new int2(adjustedMapBounds.Size)/2;
|
||||
}
|
||||
|
||||
public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler )
|
||||
{
|
||||
renderer.BeginFrame(scrollPosition);
|
||||
|
||||
wr.Draw();
|
||||
|
||||
Widget.DoDraw( wr );
|
||||
|
||||
var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default";
|
||||
var c = new Cursor(cursorName);
|
||||
c.Draw(wr, (int)cursorFrame, Viewport.LastMousePos + Location);
|
||||
new Cursor(cursorName).Draw(wr, (int)cursorFrame, Viewport.LastMousePos + Location);
|
||||
|
||||
renderer.EndFrame( inputHandler );
|
||||
}
|
||||
@@ -139,22 +122,38 @@ namespace OpenRA.Graphics
|
||||
|
||||
scrollPosition = this.NormalizeScrollPosition((avgPos.ToInt2() - screenSize / 2));
|
||||
}
|
||||
|
||||
public Rectangle ShroudBounds( World world )
|
||||
{
|
||||
var localPlayer = world.LocalPlayer;
|
||||
if( localPlayer == null ) return world.Map.Bounds;
|
||||
if( localPlayer.Shroud.Disabled ) return world.Map.Bounds;
|
||||
if( !localPlayer.Shroud.Bounds.HasValue ) return world.Map.Bounds;
|
||||
return Rectangle.Intersect( localPlayer.Shroud.Bounds.Value, world.Map.Bounds );
|
||||
}
|
||||
|
||||
public Rectangle ViewBounds()
|
||||
public Rectangle ViewBounds(World world)
|
||||
{
|
||||
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
|
||||
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
|
||||
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
|
||||
return Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
|
||||
var r = WorldBounds(world);
|
||||
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
|
||||
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
|
||||
var right = left + (int)(Game.CellSize * r.Width);
|
||||
var bottom = top + (int)(Game.CellSize * r.Height);
|
||||
|
||||
if (left < 0) left = 0;
|
||||
if (top < 0) top = 0;
|
||||
if (right > Game.viewport.Width) right = Game.viewport.Width;
|
||||
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
int2 cachedScroll = new int2(int.MaxValue, int.MaxValue);
|
||||
Rectangle cachedRect;
|
||||
|
||||
public Rectangle WorldBounds(World world)
|
||||
{
|
||||
if (cachedScroll != scrollPosition)
|
||||
{
|
||||
int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors
|
||||
var tl = ViewToWorld(int2.Zero).ToInt2() - boundary;
|
||||
var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary;
|
||||
cachedRect = Rectangle.Intersect(Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y), world.Map.Bounds);
|
||||
cachedScroll = scrollPosition;
|
||||
}
|
||||
|
||||
var b = world.LocalShroud.Bounds;
|
||||
return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public readonly World world;
|
||||
internal readonly TerrainRenderer terrainRenderer;
|
||||
internal readonly ShroudRenderer shroudRenderer;
|
||||
|
||||
public readonly UiOverlay uiOverlay;
|
||||
internal readonly HardwarePalette palette;
|
||||
|
||||
@@ -29,6 +31,7 @@ namespace OpenRA.Graphics
|
||||
this.world = world;
|
||||
|
||||
terrainRenderer = new TerrainRenderer(world, this);
|
||||
shroudRenderer = new ShroudRenderer(world);
|
||||
uiOverlay = new UiOverlay();
|
||||
palette = new HardwarePalette(world.Map);
|
||||
|
||||
@@ -48,31 +51,9 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle GetBoundsRect()
|
||||
{
|
||||
if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.Disabled && world.LocalPlayer.Shroud.Bounds.HasValue)
|
||||
{
|
||||
var r = world.LocalPlayer.Shroud.Bounds.Value;
|
||||
|
||||
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
|
||||
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
|
||||
var right = left + (int)(Game.CellSize * r.Width);
|
||||
var bottom = top + (int)(Game.CellSize * r.Height);
|
||||
|
||||
if (left < 0) left = 0;
|
||||
if (top < 0) top = 0;
|
||||
if (right > Game.viewport.Width) right = Game.viewport.Width;
|
||||
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
|
||||
|
||||
return new Rectangle(left, top, right - left, bottom - top);
|
||||
}
|
||||
else
|
||||
return new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height);
|
||||
}
|
||||
|
||||
IEnumerable<Renderable> SpritesToRender()
|
||||
{
|
||||
var bounds = GetBoundsRect();
|
||||
var bounds = Game.viewport.ViewBounds(world);
|
||||
var comparer = new SpriteComparer();
|
||||
|
||||
bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y);
|
||||
@@ -92,7 +73,7 @@ namespace OpenRA.Graphics
|
||||
public void Draw()
|
||||
{
|
||||
RefreshPalette();
|
||||
var bounds = GetBoundsRect();
|
||||
var bounds = Game.viewport.ViewBounds(world);
|
||||
Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
|
||||
|
||||
terrainRenderer.Draw(this, Game.viewport);
|
||||
@@ -113,10 +94,15 @@ namespace OpenRA.Graphics
|
||||
if (world.OrderGenerator != null)
|
||||
world.OrderGenerator.RenderAfterWorld(this, world);
|
||||
|
||||
if (world.LocalPlayer != null)
|
||||
world.LocalPlayer.Shroud.Draw( this );
|
||||
|
||||
shroudRenderer.Draw( this );
|
||||
Game.Renderer.DisableScissor();
|
||||
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld(this, a);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
void DrawBox(RectangleF r, Color color)
|
||||
@@ -130,20 +116,6 @@ namespace OpenRA.Graphics
|
||||
Game.Renderer.LineRenderer.DrawLine(a, a + c, color, color);
|
||||
}
|
||||
|
||||
void DrawBins(RectangleF bounds)
|
||||
{
|
||||
DrawBox(bounds, Color.Red);
|
||||
if (world.LocalPlayer != null)
|
||||
DrawBox(world.LocalPlayer.Shroud.Bounds.Value, Color.Blue);
|
||||
|
||||
for (var j = 0; j < world.Map.MapSize.Y;
|
||||
j += world.WorldActor.Info.Traits.Get<SpatialBinsInfo>().BinSize)
|
||||
{
|
||||
Game.Renderer.LineRenderer.DrawLine(new float2(0, j * Game.CellSize), new float2(world.Map.MapSize.X * Game.CellSize, j * Game.CellSize), Color.Black, Color.Black);
|
||||
Game.Renderer.LineRenderer.DrawLine(new float2(j * Game.CellSize, 0), new float2(j * Game.CellSize, world.Map.MapSize.Y * Game.CellSize), Color.Black, Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSelectionBox(Actor selectedUnit, Color c)
|
||||
{
|
||||
var bounds = selectedUnit.GetBounds(true);
|
||||
@@ -184,7 +156,7 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawRangeCircle(Color c, float2 location, int range)
|
||||
public void DrawRangeCircle(Color c, float2 location, float range)
|
||||
{
|
||||
var prev = location + Game.CellSize * range * float2.FromAngle(0);
|
||||
for (var i = 1; i <= 32; i++)
|
||||
|
||||
@@ -44,17 +44,10 @@ namespace OpenRA
|
||||
public byte TileFormat = 1;
|
||||
[FieldLoader.Load] public int2 MapSize;
|
||||
|
||||
|
||||
public TileReference<ushort, byte>[,] MapTiles;
|
||||
public TileReference<byte, byte>[,] MapResources;
|
||||
public string [,] CustomTerrain;
|
||||
|
||||
// Temporary compat hacks
|
||||
public int XOffset { get { return TopLeft.X; } }
|
||||
public int YOffset { get { return TopLeft.Y; } }
|
||||
public string Theater { get { return Tileset; } }
|
||||
public Rectangle Bounds { get { return Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); } }
|
||||
|
||||
public Map()
|
||||
{
|
||||
// Do nothing; not a valid map (editor hack)
|
||||
@@ -74,8 +67,7 @@ namespace OpenRA
|
||||
index = (byte)(tile.Value.PickAny ? 0xffu : 0) } } };
|
||||
|
||||
PlayerCount = 0;
|
||||
TopLeft = new int2(0, 0);
|
||||
BottomRight = new int2(0, 0);
|
||||
ResizeCordon(0,0,0,0);
|
||||
|
||||
Title = "Name your map here";
|
||||
Description = "Describe your map here";
|
||||
@@ -224,8 +216,8 @@ namespace OpenRA
|
||||
x.Key,
|
||||
x.Value.Save() ) ).ToList() ) );
|
||||
|
||||
root.Add( new MiniYamlNode( "Waypoints", MiniYaml.FromDictionary<string, int2>( Waypoints ) ) );
|
||||
root.Add( new MiniYamlNode( "Smudges", MiniYaml.FromList<SmudgeReference>( Smudges ) ) );
|
||||
root.Add(new MiniYamlNode("Waypoints", MiniYaml.FromDictionary<string, int2>( Waypoints )));
|
||||
root.Add(new MiniYamlNode("Smudges", MiniYaml.FromList<SmudgeReference>( Smudges )));
|
||||
root.Add(new MiniYamlNode("Rules", null, Rules));
|
||||
root.Add(new MiniYamlNode("Sequences", null, Sequences));
|
||||
root.Add(new MiniYamlNode("Weapons", null, Weapons));
|
||||
@@ -337,7 +329,7 @@ namespace OpenRA
|
||||
|
||||
public bool IsInMap(int x, int y)
|
||||
{
|
||||
return (x >= TopLeft.X && y >= TopLeft.Y && x < BottomRight.X && y < BottomRight.Y);
|
||||
return Bounds.Contains(x,y);
|
||||
}
|
||||
|
||||
static T[,] ResizeArray<T>(T[,] ts, T t, int width, int height)
|
||||
@@ -356,5 +348,12 @@ namespace OpenRA
|
||||
MapResources = ResizeArray(MapResources, MapResources[0, 0], width, height);
|
||||
MapSize = new int2(width, height);
|
||||
}
|
||||
|
||||
public void ResizeCordon(int left, int top, int right, int bottom)
|
||||
{
|
||||
TopLeft = new int2(left, top);
|
||||
BottomRight = new int2(right, bottom);
|
||||
Bounds = Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace OpenRA
|
||||
{
|
||||
public readonly Manifest Manifest;
|
||||
public readonly ObjectCreator ObjectCreator;
|
||||
public readonly SheetBuilder SheetBuilder;
|
||||
public readonly CursorSheetBuilder CursorSheetBuilder;
|
||||
public readonly Dictionary<string, MapStub> AvailableMaps;
|
||||
public readonly WidgetLoader WidgetLoader;
|
||||
public ILoadScreen LoadScreen = null;
|
||||
|
||||
public SheetBuilder SheetBuilder;
|
||||
public CursorSheetBuilder CursorSheetBuilder;
|
||||
|
||||
public ModData( params string[] mods )
|
||||
{
|
||||
Manifest = new Manifest( mods );
|
||||
@@ -52,7 +52,7 @@ namespace OpenRA
|
||||
return paths.Select(p => new MapStub(new Folder(p, int.MaxValue))).ToDictionary(m => m.Uid);
|
||||
}
|
||||
|
||||
string cachedTheatre = null;
|
||||
string cachedTileset = null;
|
||||
bool previousMapHadSequences = true;
|
||||
IFolder previousMapMount = null;
|
||||
|
||||
@@ -78,13 +78,15 @@ namespace OpenRA
|
||||
|
||||
Rules.LoadRules(Manifest, map);
|
||||
|
||||
if (map.Theater != cachedTheatre
|
||||
if (map.Tileset != cachedTileset
|
||||
|| previousMapHadSequences || map.Sequences.Count > 0)
|
||||
{
|
||||
SheetBuilder = new SheetBuilder( TextureChannel.Red );
|
||||
SpriteSheetBuilder.Initialize( Rules.TileSets[map.Tileset] );
|
||||
CursorSheetBuilder = new CursorSheetBuilder( this );
|
||||
CursorProvider.Initialize(Manifest.Cursors);
|
||||
SequenceProvider.Initialize(Manifest.Sequences, map.Sequences);
|
||||
cachedTheatre = map.Theater;
|
||||
cachedTileset = map.Tileset;
|
||||
}
|
||||
|
||||
previousMapHadSequences = map.Sequences.Count > 0;
|
||||
|
||||
@@ -11,23 +11,43 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Network;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
[Flags]
|
||||
enum OrderFields : byte
|
||||
{
|
||||
TargetActor = 0x01,
|
||||
TargetLocation = 0x02,
|
||||
TargetString = 0x04,
|
||||
Queued = 0x08,
|
||||
ExtraLocation = 0x10,
|
||||
}
|
||||
|
||||
static class OrderFieldsExts
|
||||
{
|
||||
public static bool HasField(this OrderFields of, OrderFields f)
|
||||
{
|
||||
return (of & f) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Order
|
||||
{
|
||||
public readonly string OrderString;
|
||||
public readonly Actor Subject;
|
||||
public readonly Actor TargetActor;
|
||||
public readonly int2 TargetLocation;
|
||||
public readonly string TargetString;
|
||||
public readonly bool Queued;
|
||||
public Actor TargetActor;
|
||||
public int2 TargetLocation;
|
||||
public string TargetString;
|
||||
public int2 ExtraLocation;
|
||||
public bool IsImmediate;
|
||||
|
||||
public Player Player { get { return Subject.Owner; } }
|
||||
|
||||
public Order(string orderString, Actor subject,
|
||||
Actor targetActor, int2 targetLocation, string targetString, bool queued)
|
||||
Order(string orderString, Actor subject,
|
||||
Actor targetActor, int2 targetLocation, string targetString, bool queued, int2 extraLocation)
|
||||
{
|
||||
this.OrderString = orderString;
|
||||
this.Subject = subject;
|
||||
@@ -35,22 +55,11 @@ namespace OpenRA
|
||||
this.TargetLocation = targetLocation;
|
||||
this.TargetString = targetString;
|
||||
this.Queued = queued;
|
||||
this.ExtraLocation = extraLocation;
|
||||
}
|
||||
|
||||
public Order(string orderString, Actor subject, bool queued)
|
||||
: this(orderString, subject, null, int2.Zero, null, queued) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor, bool queued)
|
||||
: this(orderString, subject, targetActor, int2.Zero, null, queued) { }
|
||||
public Order(string orderString, Actor subject, int2 targetLocation, bool queued)
|
||||
: this(orderString, subject, null, targetLocation, null, queued) { }
|
||||
public Order(string orderString, Actor subject, string targetString, bool queued)
|
||||
: this(orderString, subject, null, int2.Zero, targetString, queued) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor, int2 targetLocation, bool queued)
|
||||
: this(orderString, subject, targetActor, targetLocation, null, queued) { }
|
||||
public Order(string orderString, Actor subject, Actor targetActor, string targetString, bool queued)
|
||||
: this(orderString, subject, targetActor, int2.Zero, targetString, queued) { }
|
||||
public Order(string orderString, Actor subject, int2 targetLocation, string targetString, bool queued)
|
||||
: this(orderString, subject, null, targetLocation, targetString, queued) { }
|
||||
: this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
@@ -78,13 +87,25 @@ namespace OpenRA
|
||||
w.Write( (byte)0xFF );
|
||||
w.Write(OrderString);
|
||||
w.Write(UIntFromActor(Subject));
|
||||
w.Write(UIntFromActor(TargetActor));
|
||||
w.Write(TargetLocation.X);
|
||||
w.Write(TargetLocation.Y);
|
||||
w.Write(TargetString != null);
|
||||
|
||||
OrderFields fields = 0;
|
||||
if (TargetActor != null) fields |= OrderFields.TargetActor;
|
||||
if (TargetLocation != int2.Zero) fields |= OrderFields.TargetLocation;
|
||||
if (TargetString != null) fields |= OrderFields.TargetString;
|
||||
if (Queued) fields |= OrderFields.Queued;
|
||||
if (ExtraLocation != int2.Zero) fields |= OrderFields.ExtraLocation;
|
||||
|
||||
w.Write((byte)fields);
|
||||
|
||||
if (TargetActor != null)
|
||||
w.Write(UIntFromActor(TargetActor));
|
||||
if (TargetLocation != int2.Zero)
|
||||
w.Write(TargetLocation);
|
||||
if (TargetString != null)
|
||||
w.Write(TargetString);
|
||||
w.Write(Queued);
|
||||
if (ExtraLocation != int2.Zero)
|
||||
w.Write(ExtraLocation);
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
}
|
||||
@@ -98,19 +119,19 @@ namespace OpenRA
|
||||
{
|
||||
var order = r.ReadString();
|
||||
var subjectId = r.ReadUInt32();
|
||||
var targetActorId = r.ReadUInt32();
|
||||
var targetLocation = new int2(r.ReadInt32(), 0);
|
||||
targetLocation.Y = r.ReadInt32();
|
||||
var targetString = null as string;
|
||||
if (r.ReadBoolean())
|
||||
targetString = r.ReadString();
|
||||
var queued = r.ReadBoolean();
|
||||
var flags = (OrderFields)r.ReadByte();
|
||||
|
||||
var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : 0xffffffff;
|
||||
var targetLocation = flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero;
|
||||
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
|
||||
var queued = flags.HasField(OrderFields.Queued);
|
||||
var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero;
|
||||
|
||||
Actor subject, targetActor;
|
||||
if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) )
|
||||
return null;
|
||||
|
||||
return new Order( order, subject, targetActor, targetLocation, targetString, queued);
|
||||
return new Order( order, subject, targetActor, targetLocation, targetString, queued, extraLocation);
|
||||
}
|
||||
|
||||
case 0xfe:
|
||||
@@ -118,7 +139,7 @@ namespace OpenRA
|
||||
var name = r.ReadString();
|
||||
var data = r.ReadString();
|
||||
|
||||
return new Order( name, null, data, false ) { IsImmediate = true };
|
||||
return new Order( name, null, false ) { IsImmediate = true, TargetString = data };
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -162,32 +183,32 @@ namespace OpenRA
|
||||
// Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them.
|
||||
public static Order Chat(string text)
|
||||
{
|
||||
return new Order("Chat", null, text, false) { IsImmediate = true };
|
||||
return new Order("Chat", null, false) { IsImmediate = true, TargetString = text};
|
||||
}
|
||||
|
||||
public static Order TeamChat(string text)
|
||||
{
|
||||
return new Order("TeamChat", null, text, false) { IsImmediate = true };
|
||||
return new Order("TeamChat", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order Command(string text)
|
||||
{
|
||||
return new Order("Command", null, text, false) { IsImmediate = true };
|
||||
return new Order("Command", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order StartProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("StartProduction", subject, new int2( count, 0 ), item, false );
|
||||
return new Order("StartProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
}
|
||||
|
||||
public static Order PauseProduction(Actor subject, string item, bool pause)
|
||||
{
|
||||
return new Order("PauseProduction", subject, new int2( pause ? 1 : 0, 0 ), item, false);
|
||||
return new Order("PauseProduction", subject, false) { TargetLocation = new int2(pause ? 1 : 0, 0), TargetString = item };
|
||||
}
|
||||
|
||||
public static Order CancelProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("CancelProduction", subject, new int2( count, 0 ), item, false);
|
||||
return new Order("CancelProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
@@ -47,5 +45,18 @@ namespace OpenRA.Network
|
||||
}
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static int2 ReadInt2(this BinaryReader r)
|
||||
{
|
||||
var x = r.ReadInt32();
|
||||
var y = r.ReadInt32();
|
||||
return new int2(x, y);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter w, int2 p)
|
||||
{
|
||||
w.Write(p.X);
|
||||
w.Write(p.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,12 +118,16 @@ namespace OpenRA.Network
|
||||
|
||||
SetPlayerStance(world, order.Player, targetPlayer, newStance);
|
||||
|
||||
// automatically declare war reciprocally
|
||||
if (newStance == Stance.Enemy)
|
||||
SetPlayerStance(world, targetPlayer, order.Player, newStance);
|
||||
|
||||
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
|
||||
order.Player.PlayerName, targetPlayer.PlayerName, newStance));
|
||||
|
||||
// automatically declare war reciprocally
|
||||
if (newStance == Stance.Enemy && targetPlayer.Stances[order.Player] == Stance.Ally)
|
||||
{
|
||||
SetPlayerStance(world, targetPlayer, order.Player, newStance);
|
||||
Game.Debug("{0} has reciprocated",targetPlayer.PlayerName);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -141,12 +145,12 @@ namespace OpenRA.Network
|
||||
}
|
||||
}
|
||||
|
||||
static void SetPlayerStance(World w, Player a, Player b, Stance s)
|
||||
static void SetPlayerStance(World w, Player p, Player target, Stance s)
|
||||
{
|
||||
var oldStance = a.Stances[b];
|
||||
a.Stances[b] = s;
|
||||
if (b == w.LocalPlayer)
|
||||
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, b, oldStance, s);
|
||||
var oldStance = p.Stances[target];
|
||||
p.Stances[target] = s;
|
||||
if (target == w.LocalPlayer)
|
||||
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, p, oldStance, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -83,17 +83,10 @@
|
||||
<Compile Include="Traits\Player\PlayerResources.cs" />
|
||||
<Compile Include="Traits\World\Shroud.cs" />
|
||||
<Compile Include="Widgets\ChatEntryWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\ConnectionDialogsDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\CreateServerMenuDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\DiplomacyDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\MainMenuButtonsDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\ServerBrowserDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\SettingsMenuDelegate.cs" />
|
||||
<Compile Include="Widgets\MapPreviewWidget.cs" />
|
||||
<Compile Include="Widgets\WidgetUtils.cs" />
|
||||
<Compile Include="Effects\DelayedAction.cs" />
|
||||
<Compile Include="Effects\FlashTarget.cs" />
|
||||
<Compile Include="Effects\MoveFlash.cs" />
|
||||
<Compile Include="Exts.cs" />
|
||||
<Compile Include="GameRules\ActorInfo.cs" />
|
||||
<Compile Include="GameRules\VoiceInfo.cs" />
|
||||
@@ -111,7 +104,6 @@
|
||||
<Compile Include="Server\MasterServerQuery.cs" />
|
||||
<Compile Include="Server\Server.cs" />
|
||||
<Compile Include="Server\ServerOrder.cs" />
|
||||
<Compile Include="ShroudRenderer.cs" />
|
||||
<Compile Include="Sound.cs" />
|
||||
<Compile Include="Support\PerfHistory.cs" />
|
||||
<Compile Include="Sync.cs" />
|
||||
@@ -126,7 +118,6 @@
|
||||
<Compile Include="Graphics\CursorSheetBuilder.cs" />
|
||||
<Compile Include="Graphics\LineRenderer.cs" />
|
||||
<Compile Include="Graphics\WorldRenderer.cs" />
|
||||
<Compile Include="Traits\Activities\Idle.cs" />
|
||||
<Compile Include="Orders\IOrderGenerator.cs" />
|
||||
<Compile Include="Player.cs" />
|
||||
<Compile Include="Graphics\Sheet.cs" />
|
||||
@@ -165,17 +156,12 @@
|
||||
<Compile Include="Widgets\BackgroundWidget.cs" />
|
||||
<Compile Include="Widgets\LabelWidget.cs" />
|
||||
<Compile Include="Widgets\CheckboxWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\MusicPlayerDelegate.cs" />
|
||||
<Compile Include="Widgets\PerfGraphWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\PerfDebugDelegate.cs" />
|
||||
<Compile Include="Widgets\Delegates\LobbyDelegate.cs" />
|
||||
<Compile Include="Widgets\ColorBlockWidget.cs" />
|
||||
<Compile Include="GameRules\MusicInfo.cs" />
|
||||
<Compile Include="Widgets\ImageWidget.cs" />
|
||||
<Compile Include="Widgets\TextFieldWidget.cs" />
|
||||
<Compile Include="Widgets\ChatDisplayWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\MapChooserDelegate.cs" />
|
||||
<Compile Include="Widgets\ListBoxWidget.cs" />
|
||||
<Compile Include="Widgets\SliderWidget.cs" />
|
||||
<Compile Include="Widgets\TimerWidget.cs" />
|
||||
<Compile Include="Widgets\ShpImageWidget.cs" />
|
||||
@@ -186,13 +172,14 @@
|
||||
<Compile Include="Traits\RevealsShroud.cs" />
|
||||
<Compile Include="Traits\Health.cs" />
|
||||
<Compile Include="Widgets\VqaPlayerWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\VideoPlayerDelegate.cs" />
|
||||
<Compile Include="GameRules\Settings.cs" />
|
||||
<Compile Include="Support\Arguments.cs" />
|
||||
<Compile Include="Traits\ActorStance.cs" />
|
||||
<Compile Include="Traits\Armor.cs" />
|
||||
<Compile Include="Graphics\CursorProvider.cs" />
|
||||
<Compile Include="Server\TraitInterfaces.cs" />
|
||||
<Compile Include="Widgets\ScrollPanelWidget.cs" />
|
||||
<Compile Include="Graphics\ShroudRenderer.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
@@ -211,12 +198,10 @@
|
||||
<Compile Include="Network\SyncReport.cs" />
|
||||
<Compile Include="Traits\EditorAppearance.cs" />
|
||||
<Compile Include="Traits\ValidateOrder.cs" />
|
||||
<Compile Include="Traits\Scale.cs" />
|
||||
<Compile Include="TraitDictionary.cs" />
|
||||
<Compile Include="Traits\Activities\CancelableActivity.cs" />
|
||||
<Compile Include="Traits\SharesCell.cs" />
|
||||
<Compile Include="Widgets\PasswordFieldWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
|
||||
<Compile Include="Widgets\ScrollingTextWidget.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -239,9 +224,6 @@
|
||||
<ItemGroup>
|
||||
<Content Include="OpenRA.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="ServerTraits\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace OpenRA.Orders
|
||||
{
|
||||
world.CancelInputMode();
|
||||
foreach (var subject in subjects)
|
||||
yield return new Order(order, subject, xy, false);
|
||||
yield return new Order(order, subject, false) { TargetLocation = xy };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,15 +77,7 @@ namespace OpenRA.Orders
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world)
|
||||
{
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld(wr, a);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
public void RenderAfterWorld(WorldRenderer wr, World world) {}
|
||||
|
||||
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
|
||||
}
|
||||
|
||||
@@ -44,10 +44,12 @@ namespace OpenRA.Orders
|
||||
.ToArray();
|
||||
|
||||
var actorsInvolved = orders.Select(o => o.self).Distinct();
|
||||
if (actorsInvolved.Any())
|
||||
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor,
|
||||
string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()), false)
|
||||
;
|
||||
if (actorsInvolved.Any())
|
||||
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor, false)
|
||||
{
|
||||
TargetString = string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray())
|
||||
};
|
||||
|
||||
|
||||
foreach (var o in orders)
|
||||
yield return CheckSameOrder(o.iot, o.trait.IssueOrder(o.self, o.iot, o.target, mi.Modifiers.HasModifier(Modifiers.Shift)));
|
||||
@@ -88,18 +90,13 @@ namespace OpenRA.Orders
|
||||
custom.RenderAfterWorld(wr, world);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var a in world.Selection.Actors)
|
||||
if (!a.Destroyed)
|
||||
foreach (var t in a.TraitsImplementing<IPostRenderSelection>())
|
||||
t.RenderAfterWorld( wr, a );
|
||||
|
||||
|
||||
Game.Renderer.Flush();
|
||||
}
|
||||
|
||||
public string GetCursor( World world, int2 xy, MouseInput mi )
|
||||
{
|
||||
bool useSelect = false;
|
||||
bool useSelect = false;
|
||||
|
||||
var custom = world.WorldActor.TraitOrDefault<ICustomUnitOrderGenerator>();
|
||||
if (custom != null)
|
||||
@@ -132,19 +129,10 @@ namespace OpenRA.Orders
|
||||
if (self.Owner != self.World.LocalPlayer)
|
||||
return null;
|
||||
|
||||
if (!self.World.Map.IsInMap(xy.X, xy.Y))
|
||||
return null;
|
||||
|
||||
if (self.Destroyed)
|
||||
return null;
|
||||
|
||||
//var old = self.TraitsImplementing<IIssueOrder>()
|
||||
// .OrderByDescending( x => x.OrderPriority( self, xy, mi, underCursor ) )
|
||||
// .Select( x => x.IssueOrder( self, xy, mi, underCursor ) )
|
||||
// .FirstOrDefault( x => x != null );
|
||||
//if( old != null )
|
||||
// return old;
|
||||
|
||||
if( mi.Button == MouseButton.Right )
|
||||
{
|
||||
var uim = self.World.WorldActor.Trait<UnitInfluence>();
|
||||
|
||||
@@ -40,13 +40,12 @@ namespace OpenRA
|
||||
public readonly PlayerReference PlayerRef;
|
||||
public bool IsBot;
|
||||
|
||||
public ShroudRenderer Shroud;
|
||||
public Shroud Shroud { get { return World.LocalShroud; }}
|
||||
public World World { get; private set; }
|
||||
|
||||
public Player(World world, PlayerReference pr, int index)
|
||||
{
|
||||
World = world;
|
||||
Shroud = new ShroudRenderer(this, world.Map);
|
||||
|
||||
Index = index;
|
||||
Palette = "player" + index;
|
||||
@@ -69,8 +68,6 @@ namespace OpenRA
|
||||
public Player(World world, Session.Client client, PlayerReference pr, int index)
|
||||
{
|
||||
World = world;
|
||||
Shroud = new ShroudRenderer(this, world.Map);
|
||||
|
||||
Index = index;
|
||||
Palette = "player" + index;
|
||||
Color = client.Color1;
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public class ShroudRenderer
|
||||
{
|
||||
Traits.Shroud shroud;
|
||||
Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow");
|
||||
Sprite[,] sprites, fogSprites;
|
||||
|
||||
bool dirty = true;
|
||||
bool disabled = false;
|
||||
Map map;
|
||||
|
||||
public Rectangle? Bounds { get { return shroud.exploredBounds; } }
|
||||
|
||||
public ShroudRenderer(Player owner, Map map)
|
||||
{
|
||||
this.shroud = owner.World.WorldActor.Trait<Traits.Shroud>();
|
||||
this.map = map;
|
||||
|
||||
sprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y];
|
||||
|
||||
shroud.Dirty += () => dirty = true;
|
||||
}
|
||||
|
||||
public bool Disabled
|
||||
{
|
||||
get { return disabled; }
|
||||
set { disabled = value; dirty = true;}
|
||||
}
|
||||
|
||||
public bool IsExplored(int2 xy) { return IsExplored(xy.X, xy.Y); }
|
||||
public bool IsExplored(int x, int y)
|
||||
{
|
||||
if (disabled)
|
||||
return true;
|
||||
return shroud.exploredCells[x,y];
|
||||
}
|
||||
|
||||
public bool IsVisible(int2 xy) { return IsVisible(xy.X, xy.Y); }
|
||||
public bool IsVisible(int x, int y)
|
||||
{
|
||||
if (disabled)
|
||||
return true;
|
||||
return shroud.visibleCells[x,y] != 0;
|
||||
}
|
||||
|
||||
static readonly byte[][] SpecialShroudTiles =
|
||||
{
|
||||
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
|
||||
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
|
||||
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
|
||||
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
|
||||
new byte[] { 44 },
|
||||
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
|
||||
new byte[] { 40 },
|
||||
new byte[] { 35, 24, 17, 18 },
|
||||
new byte[] { 39, 39, 29, 29 },
|
||||
new byte[] { 45 },
|
||||
new byte[] { 43 },
|
||||
new byte[] { 38, 28 },
|
||||
new byte[] { 42 },
|
||||
new byte[] { 41 },
|
||||
new byte[] { 46 },
|
||||
};
|
||||
|
||||
Sprite ChooseShroud(int i, int j)
|
||||
{
|
||||
if( !shroud.exploredCells[ i, j ] ) return shadowBits[ 0xf ];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if( !shroud.exploredCells[ i, j - 1 ] ) { v |= 1; u |= 3; }
|
||||
if( !shroud.exploredCells[ i + 1, j ] ) { v |= 2; u |= 6; }
|
||||
if( !shroud.exploredCells[ i, j + 1 ] ) { v |= 4; u |= 12; }
|
||||
if( !shroud.exploredCells[ i - 1, j ] ) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if( !shroud.exploredCells[ i - 1, j - 1 ] ) u |= 1;
|
||||
if( !shroud.exploredCells[ i + 1, j - 1 ] ) u |= 2;
|
||||
if( !shroud.exploredCells[ i + 1, j + 1 ] ) u |= 4;
|
||||
if( !shroud.exploredCells[ i - 1, j + 1 ] ) u |= 8;
|
||||
|
||||
return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ];
|
||||
}
|
||||
|
||||
Sprite ChooseFog(int i, int j)
|
||||
{
|
||||
if (shroud.visibleCells[i, j] == 0) return shadowBits[0xf];
|
||||
if (!shroud.exploredCells[i, j]) return shadowBits[0xf];
|
||||
|
||||
// bits are for unexploredness: up, right, down, left
|
||||
var v = 0;
|
||||
// bits are for unexploredness: TL, TR, BR, BL
|
||||
var u = 0;
|
||||
|
||||
if (shroud.visibleCells[i, j - 1] == 0) { v |= 1; u |= 3; }
|
||||
if (shroud.visibleCells[i + 1, j] == 0) { v |= 2; u |= 6; }
|
||||
if (shroud.visibleCells[i, j + 1] == 0) { v |= 4; u |= 12; }
|
||||
if (shroud.visibleCells[i - 1, j] == 0) { v |= 8; u |= 9; }
|
||||
|
||||
var uSides = u;
|
||||
|
||||
if (shroud.visibleCells[i - 1, j - 1] == 0) u |= 1;
|
||||
if (shroud.visibleCells[i + 1, j - 1] == 0) u |= 2;
|
||||
if (shroud.visibleCells[i + 1, j + 1] == 0) u |= 4;
|
||||
if (shroud.visibleCells[i - 1, j + 1] == 0) u |= 8;
|
||||
|
||||
return shadowBits[SpecialShroudTiles[u ^ uSides][v]];
|
||||
}
|
||||
|
||||
internal void Draw( WorldRenderer wr )
|
||||
{
|
||||
if (disabled)
|
||||
return;
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
dirty = false;
|
||||
for (int i = map.TopLeft.X; i < map.BottomRight.X; i++)
|
||||
for (int j = map.TopLeft.Y; j < map.BottomRight.Y; j++)
|
||||
sprites[i, j] = ChooseShroud(i, j);
|
||||
for (int i = map.TopLeft.X; i < map.BottomRight.X; i++)
|
||||
for (int j = map.TopLeft.Y; j < map.BottomRight.Y; j++)
|
||||
fogSprites[i, j] = ChooseFog(i, j);
|
||||
}
|
||||
|
||||
var clipRect = Bounds.HasValue ? Rectangle.Intersect(Bounds.Value, map.Bounds) : map.Bounds;
|
||||
clipRect = Rectangle.Intersect(Game.viewport.ViewBounds(), clipRect);
|
||||
var miny = clipRect.Top;
|
||||
var maxy = clipRect.Bottom;
|
||||
var minx = clipRect.Left;
|
||||
var maxx = clipRect.Right;
|
||||
|
||||
DrawShroud( wr, minx, miny, maxx, maxy, fogSprites, "fog" );
|
||||
DrawShroud( wr, minx, miny, maxx, maxy, sprites, "shroud" );
|
||||
}
|
||||
|
||||
void DrawShroud( WorldRenderer wr, int minx, int miny, int maxx, int maxy, Sprite[,] s, string pal )
|
||||
{
|
||||
var shroudPalette = wr.GetPaletteIndex(pal);
|
||||
|
||||
for (var j = miny; j < maxy; j++)
|
||||
{
|
||||
var starti = minx;
|
||||
for (var i = minx; i < maxx; i++)
|
||||
{
|
||||
if (s[i, j] == shadowBits[0x0f])
|
||||
continue;
|
||||
|
||||
if (starti != i)
|
||||
{
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (i - starti), Game.CellSize));
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
s[i, j].DrawAt(
|
||||
Game.CellSize * new float2(i, j),
|
||||
shroudPalette);
|
||||
starti = i + 1;
|
||||
}
|
||||
|
||||
if (starti < maxx)
|
||||
s[starti, j].DrawAt(
|
||||
Game.CellSize * new float2(starti, j),
|
||||
shroudPalette,
|
||||
new float2(Game.CellSize * (maxx - starti), Game.CellSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Support
|
||||
{
|
||||
static class PerfHistory
|
||||
public static class PerfHistory
|
||||
{
|
||||
static readonly Color[] colors = { Color.Red, Color.Green,
|
||||
Color.Blue, Color.Yellow,
|
||||
@@ -45,7 +45,7 @@ namespace OpenRA.Support
|
||||
}
|
||||
}
|
||||
|
||||
class PerfItem
|
||||
public class PerfItem
|
||||
{
|
||||
public readonly Color c;
|
||||
public readonly string Name;
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public abstract class CancelableActivity : IActivity
|
||||
{
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
namespace OpenRA.Traits.Activities
|
||||
{
|
||||
public class Idle : CancelableActivity
|
||||
{
|
||||
public override IActivity Tick(Actor self) { return NextActivity ?? this; }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Effects;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
@@ -69,6 +70,34 @@ namespace OpenRA.Traits
|
||||
Game.Renderer.LineRenderer.DrawLine(p + new float2(1, -1), p + new float2(-1, -1), c, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class LineTargetExts
|
||||
{
|
||||
public static void SetTargetLine(this Actor self, Target target, Color color)
|
||||
{
|
||||
self.SetTargetLine(target, color, true);
|
||||
}
|
||||
|
||||
public static void SetTargetLine(this Actor self, Target target, Color color, bool display)
|
||||
{
|
||||
if (self.Owner != self.World.LocalPlayer)
|
||||
return;
|
||||
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (self.Destroyed) return;
|
||||
if (target.IsActor && display)
|
||||
w.Add(new FlashTarget(target.Actor));
|
||||
|
||||
var line = self.TraitOrDefault<DrawLineToTarget>();
|
||||
if (line != null)
|
||||
if (display)
|
||||
line.SetTarget(self, target, color);
|
||||
else
|
||||
line.SetTargetSilently(self, target, color);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
DisableShroud ^= true;
|
||||
if (self.World.LocalPlayer == self.Owner)
|
||||
self.World.LocalPlayer.Shroud.Disabled = DisableShroud;
|
||||
self.World.LocalShroud.Disabled = DisableShroud;
|
||||
break;
|
||||
}
|
||||
case "DevPathDebug":
|
||||
|
||||
@@ -17,9 +17,10 @@ namespace OpenRA.Traits
|
||||
public abstract class RenderSimpleInfo : ITraitInfo
|
||||
{
|
||||
public readonly string Image = null;
|
||||
public readonly string[] OverrideTheater = null;
|
||||
public readonly string[] OverrideTileset = null;
|
||||
public readonly string[] OverrideImage = null;
|
||||
public readonly string Palette = null;
|
||||
public readonly float Scale = 1f;
|
||||
public abstract object Create(ActorInitializer init);
|
||||
}
|
||||
|
||||
@@ -28,32 +29,44 @@ namespace OpenRA.Traits
|
||||
public Dictionary<string, AnimationWithOffset> anims = new Dictionary<string, AnimationWithOffset>();
|
||||
public Animation anim { get { return anims[""].Animation; } protected set { anims[""].Animation = value; } }
|
||||
|
||||
public static string GetImage(ActorInfo actor, string Tileset)
|
||||
{
|
||||
var Info = actor.Traits.Get<RenderSimpleInfo>();
|
||||
if (Info.OverrideTileset != null && Tileset != null)
|
||||
for (int i = 0; i < Info.OverrideTileset.Length; i++)
|
||||
if (Info.OverrideTileset[i] == Tileset)
|
||||
return Info.OverrideImage[i];
|
||||
|
||||
return Info.Image ?? actor.Name;
|
||||
}
|
||||
|
||||
string cachedImage = null;
|
||||
public string GetImage(Actor self)
|
||||
{
|
||||
if (cachedImage != null)
|
||||
return cachedImage;
|
||||
|
||||
var Info = self.Info.Traits.Get<RenderSimpleInfo>();
|
||||
if (Info.OverrideTheater != null)
|
||||
for (int i = 0; i < Info.OverrideTheater.Length; i++)
|
||||
if (Info.OverrideTheater[i] == self.World.Map.Theater)
|
||||
return cachedImage = Info.OverrideImage[i];
|
||||
|
||||
return cachedImage = Info.Image ?? self.Info.Name;
|
||||
return cachedImage = GetImage(self.Info, self.World.Map.Tileset);
|
||||
}
|
||||
|
||||
RenderSimpleInfo Info;
|
||||
public RenderSimple(Actor self, Func<int> baseFacing)
|
||||
{
|
||||
anims.Add( "", new Animation( GetImage(self), baseFacing ) );
|
||||
Info = self.Info.Traits.Get<RenderSimpleInfo>();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Renderable> Render( Actor self )
|
||||
{
|
||||
var palette = self.Info.Traits.Get<RenderSimpleInfo>().Palette;
|
||||
|
||||
foreach( var a in anims.Values )
|
||||
if( a.DisableFunc == null || !a.DisableFunc() )
|
||||
yield return ( palette == null ) ? a.Image( self ) : a.Image( self ).WithPalette(palette);
|
||||
{
|
||||
Renderable ret = a.Image( self );
|
||||
if (Info.Scale != 1f)
|
||||
ret = ret.WithScale(Info.Scale).WithPos(ret.Pos + 0.5f*ret.Sprite.size*(1 - Info.Scale));
|
||||
yield return ( Info.Palette == null ) ? ret : ret.WithPalette(Info.Palette);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Tick(Actor self)
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ScaleInfo : ITraitInfo
|
||||
{
|
||||
public readonly float Value = 1f; /* default */
|
||||
|
||||
public ScaleInfo() { } /* only because we have other ctors */
|
||||
|
||||
public object Create(ActorInitializer init) { return new Scale(this); }
|
||||
}
|
||||
|
||||
public class Scale : IRenderModifier
|
||||
{
|
||||
public ScaleInfo Info { get; protected set; }
|
||||
|
||||
public Scale(ScaleInfo info)
|
||||
{
|
||||
this.Info = info;
|
||||
}
|
||||
|
||||
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
|
||||
{
|
||||
var r2 = new List<Renderable>(r);
|
||||
var r3 = new List<Renderable>();
|
||||
|
||||
for (int i = 0; i < r2.Count;i++)
|
||||
{
|
||||
var renderable = r2[i];
|
||||
|
||||
renderable.Scale = Info.Value;
|
||||
r3.Add(renderable);
|
||||
// yield return renderable;
|
||||
}
|
||||
|
||||
return r3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ namespace OpenRA.Traits
|
||||
Color RadarSignatureColor(Actor self);
|
||||
}
|
||||
|
||||
public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); }
|
||||
public interface IVisibilityModifier { bool IsVisible(Actor self); }
|
||||
public interface IRadarColorModifier { Color RadarColorOverride(Actor self); }
|
||||
public interface IHasLocation
|
||||
{
|
||||
@@ -151,15 +151,6 @@ namespace OpenRA.Traits
|
||||
public readonly int ZOffset;
|
||||
public float Scale;
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset)
|
||||
{
|
||||
Sprite = sprite;
|
||||
Pos = pos;
|
||||
Palette = palette;
|
||||
Z = z;
|
||||
ZOffset = zOffset;
|
||||
Scale = 1f; /* default */
|
||||
}
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset, float scale)
|
||||
{
|
||||
Sprite = sprite;
|
||||
@@ -171,12 +162,12 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z)
|
||||
: this(sprite, pos, palette, z, 0) { }
|
||||
|
||||
: this(sprite, pos, palette, z, 0, 1f) { }
|
||||
|
||||
public Renderable(Sprite sprite, float2 pos, string palette, int z, float scale)
|
||||
: this(sprite, pos, palette, z, 0, scale) { }
|
||||
|
||||
|
||||
public Renderable WithScale(float newScale) { return new Renderable(Sprite, Pos, Palette, Z, ZOffset, newScale); }
|
||||
public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset, Scale); }
|
||||
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset, Scale); }
|
||||
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset, Scale); }
|
||||
@@ -242,6 +233,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
string[] TargetTypes { get; }
|
||||
IEnumerable<int2> TargetableCells( Actor self );
|
||||
bool TargetableBy(Actor self, Actor byActor);
|
||||
}
|
||||
|
||||
public interface INotifyKeyPress { bool KeyPressed(Actor self, KeyInput e); }
|
||||
|
||||
@@ -100,12 +100,7 @@ namespace OpenRA.Traits
|
||||
public static Renderable Centered(Actor self, Sprite s, float2 location)
|
||||
{
|
||||
var pal = self.Owner == null ? "player0" : self.Owner.Palette;
|
||||
var scale = self.TraitOrDefault<Scale>();
|
||||
var scaleModifier = 1f;
|
||||
if (scale != null)
|
||||
scaleModifier = scale.Info.Value;
|
||||
|
||||
var loc = location - 0.5f * s.size * scaleModifier;
|
||||
var loc = location - 0.5f * s.size;
|
||||
|
||||
return new Renderable(s, loc.Round(), pal, (int)self.CenterLocation.Y);
|
||||
}
|
||||
|
||||
@@ -26,27 +26,15 @@ namespace OpenRA.Traits
|
||||
|
||||
public void Render( WorldRenderer wr )
|
||||
{
|
||||
var cliprect = Game.viewport.ShroudBounds( world );
|
||||
cliprect = Rectangle.Intersect(Game.viewport.ViewBounds(), cliprect);
|
||||
|
||||
var minx = cliprect.Left;
|
||||
var maxx = cliprect.Right;
|
||||
|
||||
var miny = cliprect.Top;
|
||||
var maxy = cliprect.Bottom;
|
||||
|
||||
foreach( var rt in world.WorldActor.TraitsImplementing<ResourceType>() )
|
||||
rt.info.PaletteIndex = wr.GetPaletteIndex(rt.info.Palette);
|
||||
|
||||
ShroudRenderer shroud = null;
|
||||
if( world.LocalPlayer != null )
|
||||
shroud = world.LocalPlayer.Shroud;
|
||||
|
||||
for (int x = minx; x < maxx; x++)
|
||||
for (int y = miny; y < maxy; y++)
|
||||
var clip = Game.viewport.WorldBounds(world);
|
||||
for (int x = clip.Left; x < clip.Right; x++)
|
||||
for (int y = clip.Top; y < clip.Bottom; y++)
|
||||
{
|
||||
if (shroud != null && !shroud.IsExplored(new int2(x, y)))
|
||||
continue;
|
||||
if (!world.LocalShroud.IsExplored(new int2(x, y)))
|
||||
continue;
|
||||
|
||||
var c = content[x, y];
|
||||
if (c.image != null)
|
||||
@@ -67,8 +55,8 @@ namespace OpenRA.Traits
|
||||
|
||||
var map = w.Map;
|
||||
|
||||
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
for (int x = map.Bounds.Left; x < map.Bounds.Right; x++)
|
||||
for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++)
|
||||
{
|
||||
// Todo: Valid terrain should be specified in the resource
|
||||
if (!AllowResourceAt(new int2(x,y)))
|
||||
@@ -80,8 +68,8 @@ namespace OpenRA.Traits
|
||||
content[x, y].image = ChooseContent(content[x, y].type);
|
||||
}
|
||||
|
||||
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
|
||||
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
|
||||
for (int x = map.Bounds.Left; x < map.Bounds.Right; x++)
|
||||
for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++)
|
||||
if (content[x, y].type != null)
|
||||
{
|
||||
content[x, y].density = GetIdealDensity(x, y);
|
||||
|
||||
@@ -23,18 +23,31 @@ namespace OpenRA.Traits
|
||||
public class Shroud
|
||||
{
|
||||
Map map;
|
||||
|
||||
World world;
|
||||
|
||||
public int[,] visibleCells;
|
||||
public bool[,] exploredCells;
|
||||
public Rectangle? exploredBounds;
|
||||
Rectangle? exploredBounds;
|
||||
bool disabled = false;
|
||||
public bool Disabled
|
||||
{
|
||||
get { return disabled || world.LocalPlayer == null; }
|
||||
set { disabled = value; Dirty(); }
|
||||
}
|
||||
|
||||
public Rectangle? Bounds
|
||||
{
|
||||
get { return Disabled ? null : exploredBounds; }
|
||||
}
|
||||
|
||||
public event Action Dirty = () => { };
|
||||
|
||||
public Shroud(World world)
|
||||
{
|
||||
this.world = world;
|
||||
map = world.Map;
|
||||
visibleCells = new int[map.MapSize.X, map.MapSize.Y];
|
||||
exploredCells = new bool[map.MapSize.X, map.MapSize.Y];
|
||||
|
||||
world.ActorAdded += AddActor;
|
||||
world.ActorRemoved += RemoveActor;
|
||||
}
|
||||
@@ -48,10 +61,10 @@ namespace OpenRA.Traits
|
||||
{
|
||||
var min = a - new int2(r, r);
|
||||
var max = a + new int2(r, r);
|
||||
if (min.X < world.Map.XOffset - 1) min.X = world.Map.XOffset - 1;
|
||||
if (min.Y < world.Map.YOffset - 1) min.Y = world.Map.YOffset - 1;
|
||||
if (max.X > world.Map.XOffset + world.Map.Width) max.X = world.Map.XOffset + world.Map.Width;
|
||||
if (max.Y > world.Map.YOffset + world.Map.Height) max.Y = world.Map.YOffset + world.Map.Height;
|
||||
if (min.X < world.Map.Bounds.Left - 1) min.X = world.Map.Bounds.Left - 1;
|
||||
if (min.Y < world.Map.Bounds.Top - 1) min.Y = world.Map.Bounds.Top - 1;
|
||||
if (max.X > world.Map.Bounds.Right) max.X = world.Map.Bounds.Right;
|
||||
if (max.Y > world.Map.Bounds.Bottom) max.Y = world.Map.Bounds.Bottom;
|
||||
|
||||
for (var j = min.Y; j <= max.Y; j++)
|
||||
for (var i = min.X; i <= max.X; i++)
|
||||
@@ -90,13 +103,13 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
var box = new Rectangle(p.X - v.range, p.Y - v.range, 2 * v.range + 1, 2 * v.range + 1);
|
||||
exploredBounds = exploredBounds.HasValue ?
|
||||
Rectangle.Union(exploredBounds.Value, box) : box;
|
||||
exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box;
|
||||
}
|
||||
|
||||
vis[a] = v;
|
||||
|
||||
Dirty();
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void UpdatePlayerStance(World w, Player player, Stance oldStance, Stance newStance)
|
||||
@@ -139,8 +152,9 @@ namespace OpenRA.Traits
|
||||
--visibleCells[q.X, q.Y];
|
||||
|
||||
vis.Remove(a);
|
||||
|
||||
Dirty();
|
||||
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void UpdateActor(Actor a)
|
||||
@@ -157,20 +171,21 @@ namespace OpenRA.Traits
|
||||
exploredCells[q.X, q.Y] = true;
|
||||
|
||||
var box = new Rectangle(center.X - range, center.Y - range, 2 * range + 1, 2 * range + 1);
|
||||
exploredBounds = exploredBounds.HasValue ?
|
||||
Rectangle.Union(exploredBounds.Value, box) : box;
|
||||
exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box;
|
||||
|
||||
Dirty();
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void ExploreAll(World world)
|
||||
{
|
||||
for (int i = map.TopLeft.X; i < map.BottomRight.X; i++)
|
||||
for (int j = map.TopLeft.Y; j < map.BottomRight.Y; j++)
|
||||
for (int i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
||||
for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
||||
exploredCells[i, j] = true;
|
||||
exploredBounds = new Rectangle(world.Map.TopLeft.X,world.Map.TopLeft.Y,world.Map.Width,world.Map.Height);
|
||||
exploredBounds = world.Map.Bounds;
|
||||
|
||||
Dirty();
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void ResetExploration() // for `hide map` crate
|
||||
@@ -179,7 +194,38 @@ namespace OpenRA.Traits
|
||||
for (var i = 0; i <= exploredCells.GetUpperBound(0); i++)
|
||||
exploredCells[i, j] = visibleCells[i, j] > 0;
|
||||
|
||||
Dirty();
|
||||
if (!Disabled)
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public bool IsExplored(int2 xy) { return IsExplored(xy.X, xy.Y); }
|
||||
public bool IsExplored(int x, int y)
|
||||
{
|
||||
if (!map.IsInMap(x, y))
|
||||
return false;
|
||||
|
||||
if (Disabled)
|
||||
return true;
|
||||
|
||||
return exploredCells[x,y];
|
||||
}
|
||||
|
||||
public bool IsVisible(int2 xy) { return IsVisible(xy.X, xy.Y); }
|
||||
public bool IsVisible(int x, int y)
|
||||
{
|
||||
if (Disabled)
|
||||
return true;
|
||||
|
||||
return visibleCells[x,y] != 0;
|
||||
}
|
||||
|
||||
// Actors are hidden under shroud, but not under fog by default
|
||||
public bool IsVisible(Actor a)
|
||||
{
|
||||
if (a.TraitsImplementing<IVisibilityModifier>().Any(t => !t.IsVisible(a)))
|
||||
return false;
|
||||
|
||||
return Disabled || a.Owner == a.World.LocalPlayer || GetVisOrigins(a).Any(o => IsExplored(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,10 +49,10 @@ namespace OpenRA.Traits
|
||||
{
|
||||
var bounds = a.Actor.GetBounds(true);
|
||||
|
||||
if (bounds.Right <= Game.CellSize * self.World.Map.XOffset) continue;
|
||||
if (bounds.Bottom <= Game.CellSize * self.World.Map.YOffset) continue;
|
||||
if (bounds.Left >= Game.CellSize * (self.World.Map.XOffset + self.World.Map.Width)) continue;
|
||||
if (bounds.Top >= Game.CellSize * (self.World.Map.YOffset + self.World.Map.Height)) continue;
|
||||
if (bounds.Right <= Game.CellSize * self.World.Map.Bounds.Left) continue;
|
||||
if (bounds.Bottom <= Game.CellSize * self.World.Map.Bounds.Top) continue;
|
||||
if (bounds.Left >= Game.CellSize * self.World.Map.Bounds.Right) continue;
|
||||
if (bounds.Top >= Game.CellSize * self.World.Map.Bounds.Bottom) continue;
|
||||
|
||||
var i1 = Math.Max(0, (int)bounds.Left / scale);
|
||||
var i2 = Math.Min(bins.GetUpperBound(0), (int)bounds.Right / scale);
|
||||
|
||||
@@ -27,13 +27,13 @@ namespace OpenRA
|
||||
unitDebug = SynthesizeTile(0x04);
|
||||
}
|
||||
|
||||
static Sprite SynthesizeTile(byte paletteIndex)
|
||||
public static Sprite SynthesizeTile(byte paletteIndex)
|
||||
{
|
||||
byte[] data = new byte[Game.CellSize * Game.CellSize];
|
||||
|
||||
for (int i = 0; i < Game.CellSize; i++)
|
||||
for (int j = 0; j < Game.CellSize; j++)
|
||||
data[i * Game.CellSize + j] = ((i + j) % 4 < 2) ? (byte)0 : paletteIndex;
|
||||
data[i * Game.CellSize + j] = ((i+j) % 4 != 0) ? (byte)0 : paletteIndex;
|
||||
|
||||
return Game.modData.SheetBuilder.Add(data, new Size(Game.CellSize, Game.CellSize));
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
class BackgroundWidget : Widget
|
||||
public class BackgroundWidget : Widget
|
||||
{
|
||||
public readonly string Background = "dialog";
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
@@ -63,6 +64,9 @@ namespace OpenRA.Widgets
|
||||
return Depressed;
|
||||
}
|
||||
|
||||
public override int2 ChildOrigin { get { return RenderOrigin +
|
||||
((Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0)); } }
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
@@ -70,13 +74,120 @@ namespace OpenRA.Widgets
|
||||
WidgetUtils.DrawPanel(Depressed ? "dialog3" : "dialog2", RenderBounds);
|
||||
|
||||
var text = GetText();
|
||||
|
||||
font.DrawText(text,
|
||||
new int2(RenderOrigin.X + Bounds.Width / 2, RenderOrigin.Y + Bounds.Height / 2)
|
||||
new int2(RenderOrigin.X + UsableWidth / 2, RenderOrigin.Y + Bounds.Height / 2)
|
||||
- new int2(font.Measure(text).X / 2,
|
||||
font.Measure(text).Y / 2) + stateOffset, Color.White);
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new ButtonWidget(this); }
|
||||
public virtual int UsableWidth { get { return Bounds.Width; } }
|
||||
}
|
||||
|
||||
public class DropDownButtonWidget : ButtonWidget
|
||||
{
|
||||
public DropDownButtonWidget()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
protected DropDownButtonWidget(DropDownButtonWidget widget)
|
||||
: base(widget)
|
||||
{
|
||||
}
|
||||
|
||||
public override void DrawInner(WorldRenderer wr)
|
||||
{
|
||||
base.DrawInner(wr);
|
||||
var stateOffset = (Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0);
|
||||
|
||||
var image = ChromeProvider.GetImage("scrollbar", "down_arrow");
|
||||
WidgetUtils.DrawRGBA( image,
|
||||
stateOffset + new float2( RenderBounds.Right - RenderBounds.Height + 4,
|
||||
RenderBounds.Top + (RenderBounds.Height - image.bounds.Height) / 2 ));
|
||||
|
||||
WidgetUtils.FillRectWithColor(new Rectangle(stateOffset.X + RenderBounds.Right - RenderBounds.Height,
|
||||
stateOffset.Y + RenderBounds.Top + 3, 1, RenderBounds.Height - 6),
|
||||
Color.White);
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new DropDownButtonWidget(this); }
|
||||
public override int UsableWidth { get { return Bounds.Width - Bounds.Height; } } /* space for button */
|
||||
|
||||
public static void ShowDropPanel(Widget w, Widget panel, IEnumerable<Widget> dismissAfter, Func<bool> onDismiss)
|
||||
{
|
||||
var fullscreenMask = new ContainerWidget();
|
||||
// Don't use initializers - breaks on mono 2.6.7
|
||||
fullscreenMask.Bounds = new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height);
|
||||
fullscreenMask.ClickThrough = false;
|
||||
fullscreenMask.Visible = true;
|
||||
Widget.RootWidget.AddChild(fullscreenMask);
|
||||
|
||||
Action HideDropDown = () =>
|
||||
{
|
||||
Widget.RootWidget.Children.Remove(fullscreenMask);
|
||||
Widget.RootWidget.Children.Remove(panel);
|
||||
};
|
||||
|
||||
fullscreenMask.OnMouseDown = mi =>
|
||||
{
|
||||
if (onDismiss()) HideDropDown();
|
||||
return false;
|
||||
};
|
||||
|
||||
var oldBounds = panel.Bounds;
|
||||
panel.Bounds = new Rectangle(w.RenderOrigin.X, w.RenderOrigin.Y + w.Bounds.Height, oldBounds.Width, oldBounds.Height);
|
||||
panel.ClickThrough = false;
|
||||
panel.Visible = true;
|
||||
panel.OnMouseUp = mi => true;
|
||||
|
||||
foreach (var ww in dismissAfter)
|
||||
{
|
||||
var origMouseUp = ww.OnMouseUp;
|
||||
ww.OnMouseUp = mi => { var result = origMouseUp(mi); if (onDismiss()) HideDropDown(); return result; };
|
||||
}
|
||||
Widget.RootWidget.AddChild(panel);
|
||||
}
|
||||
|
||||
public static void ShowDropDown<T>(Widget w, IEnumerable<T> ts, Func<T, int, LabelWidget> ft)
|
||||
{
|
||||
var dropDown = new ScrollPanelWidget
|
||||
{
|
||||
Bounds = new Rectangle(w.RenderOrigin.X, w.RenderOrigin.Y + w.Bounds.Height, w.Bounds.Width, 100),
|
||||
Visible = true,
|
||||
ClickThrough = false,
|
||||
OnMouseUp = mi => true,
|
||||
};
|
||||
|
||||
var y = 0;
|
||||
List<LabelWidget> items = new List<LabelWidget>();
|
||||
List<Widget> dismissAfter = new List<Widget>();
|
||||
foreach (var t in ts)
|
||||
{
|
||||
var ww = ft(t, dropDown.Bounds.Width);
|
||||
dismissAfter.Add(ww);
|
||||
ww.ClickThrough = false;
|
||||
ww.IsVisible = () => true;
|
||||
ww.Bounds = new Rectangle(1, y, ww.Bounds.Width, ww.Bounds.Height);
|
||||
|
||||
ww.OnMouseMove = mi =>
|
||||
{
|
||||
items.Do(lw =>
|
||||
{
|
||||
lw.Background = null; ww.Background = "dialog2";
|
||||
}); return true;
|
||||
};
|
||||
|
||||
dropDown.AddChild(ww);
|
||||
items.Add(ww);
|
||||
|
||||
y += ww.Bounds.Height;
|
||||
}
|
||||
|
||||
dropDown.ContentHeight = y;
|
||||
dropDown.Bounds.Height = y + 2;
|
||||
ShowDropPanel(w,dropDown, dismissAfter, () => true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
@@ -24,6 +25,7 @@ namespace OpenRA.Widgets
|
||||
public TextAlign Align = TextAlign.Left;
|
||||
public TextVAlign VAlign = TextVAlign.Middle;
|
||||
public bool Bold = false;
|
||||
public bool WordWrap = false;
|
||||
public Func<string> GetText;
|
||||
public Func<string> GetBackground;
|
||||
|
||||
@@ -58,7 +60,7 @@ namespace OpenRA.Widgets
|
||||
|
||||
int2 textSize = font.Measure(text);
|
||||
int2 position = RenderOrigin;
|
||||
|
||||
|
||||
if (VAlign == TextVAlign.Middle)
|
||||
position += new int2(0, (Bounds.Height - textSize.Y)/2);
|
||||
|
||||
@@ -69,7 +71,58 @@ namespace OpenRA.Widgets
|
||||
position += new int2((Bounds.Width - textSize.X)/2, 0);
|
||||
|
||||
if (Align == TextAlign.Right)
|
||||
position += new int2(Bounds.Width - textSize.X,0);
|
||||
position += new int2(Bounds.Width - textSize.X,0);
|
||||
|
||||
if (WordWrap)
|
||||
{
|
||||
if (textSize.X > Bounds.Width)
|
||||
{
|
||||
string[] lines = text.Split('\n');
|
||||
List<string> newLines = new List<string>();
|
||||
int i = 0;
|
||||
string line = lines[i++];
|
||||
while (true)
|
||||
{
|
||||
newLines.Add(line);
|
||||
int2 m = font.Measure(line);
|
||||
int spaceIndex = 0, start = line.Length - 1;
|
||||
|
||||
if (m.X <= Bounds.Width)
|
||||
{
|
||||
if (i < lines.Length - 1)
|
||||
{
|
||||
line = lines[i++];
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
while (m.X > Bounds.Width)
|
||||
{
|
||||
if (-1 == (spaceIndex = line.LastIndexOf(' ', start)))
|
||||
break;
|
||||
start = spaceIndex - 1;
|
||||
m = font.Measure(line.Substring(0, spaceIndex));
|
||||
}
|
||||
|
||||
if (spaceIndex != -1)
|
||||
{
|
||||
newLines.RemoveAt(newLines.Count - 1);
|
||||
newLines.Add(line.Substring(0, spaceIndex));
|
||||
line = line.Substring(spaceIndex + 1);
|
||||
}
|
||||
else if (i < lines.Length - 1)
|
||||
{
|
||||
line = lines[i++];
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
text = string.Join("\n", newLines.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
font.DrawText(text, position, Color.White);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace OpenRA.Widgets
|
||||
|
||||
public int2 ConvertToPreview(MapStub map, int2 point)
|
||||
{
|
||||
return new int2(MapRect.X + (int)(PreviewScale*(point.X - map.TopLeft.X)) , MapRect.Y + (int)(PreviewScale*(point.Y - map.TopLeft.Y)));
|
||||
return new int2(MapRect.X + (int)(PreviewScale*(point.X - map.Bounds.Left)) , MapRect.Y + (int)(PreviewScale*(point.Y - map.Bounds.Top)));
|
||||
}
|
||||
|
||||
public override bool HandleInputInner(MouseInput mi)
|
||||
@@ -91,14 +91,14 @@ namespace OpenRA.Widgets
|
||||
mapChooserSheet = new Sheet(new Size( preview.Width, preview.Height ) );
|
||||
|
||||
mapChooserSheet.Texture.SetData( preview );
|
||||
mapChooserSprite = new Sprite( mapChooserSheet, new Rectangle( 0, 0, map.Width, map.Height ), TextureChannel.Alpha );
|
||||
mapChooserSprite = new Sprite( mapChooserSheet, new Rectangle( 0, 0, map.Bounds.Width, map.Bounds.Height ), TextureChannel.Alpha );
|
||||
|
||||
// Update map rect
|
||||
PreviewScale = Math.Min(RenderBounds.Width * 1.0f / map.Width, RenderBounds.Height * 1.0f / map.Height);
|
||||
var size = Math.Max(map.Width, map.Height);
|
||||
var dw = (int)(PreviewScale * (size - map.Width)) / 2;
|
||||
var dh = (int)(PreviewScale * (size - map.Height)) / 2;
|
||||
MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Width * PreviewScale), (int)(map.Height * PreviewScale));
|
||||
PreviewScale = Math.Min(RenderBounds.Width * 1.0f / map.Bounds.Width, RenderBounds.Height * 1.0f / map.Bounds.Height);
|
||||
var size = Math.Max(map.Bounds.Width, map.Bounds.Height);
|
||||
var dw = (int)(PreviewScale * (size - map.Bounds.Width)) / 2;
|
||||
var dh = (int)(PreviewScale * (size - map.Bounds.Height)) / 2;
|
||||
MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Bounds.Width * PreviewScale), (int)(map.Bounds.Height * PreviewScale));
|
||||
}
|
||||
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite( mapChooserSprite,
|
||||
|
||||
@@ -16,46 +16,13 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
public class PasswordFieldWidget : TextFieldWidget
|
||||
{
|
||||
public PasswordFieldWidget()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
protected PasswordFieldWidget(PasswordFieldWidget widget)
|
||||
: base(widget)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PasswordFieldWidget() : base() {}
|
||||
protected PasswordFieldWidget(PasswordFieldWidget widget) : base(widget) {}
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
int margin = 5;
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
var cursor = (showCursor && Focused) ? "|" : "";
|
||||
var textSize = font.Measure(new string('*', Text.Length) + "|");
|
||||
var pos = RenderOrigin;
|
||||
|
||||
WidgetUtils.DrawPanel("dialog3",
|
||||
new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height));
|
||||
|
||||
// Inset text by the margin and center vertically
|
||||
var textPos = pos + new int2(margin, (Bounds.Height - textSize.Y) / 2 - VisualHeight);
|
||||
|
||||
// Right align when editing and scissor when the text overflows
|
||||
if (textSize.X > Bounds.Width - 2 * margin)
|
||||
{
|
||||
if (Focused)
|
||||
textPos += new int2(Bounds.Width - 2 * margin - textSize.X, 0);
|
||||
|
||||
Game.Renderer.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2 * margin, Bounds.Bottom);
|
||||
}
|
||||
|
||||
font.DrawText(new string('*', Text.Length) + cursor, textPos, Color.White);
|
||||
|
||||
if (textSize.X > Bounds.Width - 2 * margin)
|
||||
Game.Renderer.DisableScissor();
|
||||
DrawWithString(new string('*', Text.Length));
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new PasswordFieldWidget(this); }
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Widgets
|
||||
{
|
||||
public class ListBoxWidget : Widget
|
||||
public class ScrollPanelWidget : Widget
|
||||
{
|
||||
public readonly string Background = "dialog3";
|
||||
public readonly int ScrollbarWidth = 24;
|
||||
@@ -30,8 +30,8 @@ namespace OpenRA.Widgets
|
||||
Rectangle backgroundRect;
|
||||
Rectangle scrollbarRect;
|
||||
|
||||
public ListBoxWidget() : base() {}
|
||||
protected ListBoxWidget(ListBoxWidget other)
|
||||
public ScrollPanelWidget() : base() {}
|
||||
protected ScrollPanelWidget(ScrollPanelWidget other)
|
||||
: base(other)
|
||||
{
|
||||
Background = other.Background;
|
||||
@@ -71,7 +71,7 @@ namespace OpenRA.Widgets
|
||||
WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", "down_arrow"),
|
||||
new float2(downButtonRect.Left + downOffset, downButtonRect.Top + downOffset));
|
||||
|
||||
Game.Renderer.EnableScissor(backgroundRect.X, backgroundRect.Y + HeaderHeight, backgroundRect.Width, backgroundRect.Height - HeaderHeight);
|
||||
Game.Renderer.EnableScissor(backgroundRect.X+1, backgroundRect.Y + HeaderHeight+1, backgroundRect.Width-2, backgroundRect.Height - HeaderHeight-2);
|
||||
|
||||
foreach (var child in Children)
|
||||
child.Draw( wr );
|
||||
@@ -90,6 +90,8 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
if (UpPressed && ListOffset <= 0) ListOffset += ScrollVelocity;
|
||||
if (DownPressed) ListOffset -= ScrollVelocity;
|
||||
|
||||
if (ListOffset > 0) ListOffset = 0;
|
||||
}
|
||||
|
||||
public override bool LoseFocus (MouseInput mi)
|
||||
@@ -115,6 +117,6 @@ namespace OpenRA.Widgets
|
||||
return (UpPressed || DownPressed);
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new ListBoxWidget(this); }
|
||||
public override Widget Clone() { return new ScrollPanelWidget(this); }
|
||||
}
|
||||
}
|
||||
@@ -23,12 +23,9 @@ namespace OpenRA.Widgets
|
||||
public Func<bool> OnEnterKey = () => false;
|
||||
public Func<bool> OnTabKey = () => false;
|
||||
public Action OnLoseFocus = () => { };
|
||||
public int CursorPosition { get; protected set; }
|
||||
|
||||
public TextFieldWidget()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public TextFieldWidget() : base() {}
|
||||
protected TextFieldWidget(TextFieldWidget widget)
|
||||
: base(widget)
|
||||
{
|
||||
@@ -59,8 +56,32 @@ namespace OpenRA.Widgets
|
||||
|
||||
blinkCycle = 10;
|
||||
showCursor = true;
|
||||
CursorPosition = ClosestCursorPosition(mi.Location.X);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public int ClosestCursorPosition(int x)
|
||||
{
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
var textSize = font.Measure(Text);
|
||||
|
||||
var start = RenderOrigin.X + margin;
|
||||
if (textSize.X > Bounds.Width - 2 * margin && Focused)
|
||||
start += Bounds.Width - 2 * margin - textSize.X;
|
||||
|
||||
int minIndex = -1;
|
||||
int minValue = int.MaxValue;
|
||||
for (int i = 0; i <= Text.Length; i++)
|
||||
{
|
||||
var dist = Math.Abs(start + font.Measure(Text.Substring(0,i)).X - x);
|
||||
if (dist > minValue)
|
||||
break;
|
||||
minValue = dist;
|
||||
minIndex = i;
|
||||
}
|
||||
return minIndex;
|
||||
}
|
||||
|
||||
public override bool HandleKeyPressInner(KeyInput e)
|
||||
{
|
||||
@@ -76,23 +97,55 @@ namespace OpenRA.Widgets
|
||||
if (e.KeyChar == '\t' && OnTabKey())
|
||||
return true;
|
||||
|
||||
if (e.KeyName == "left")
|
||||
{
|
||||
if (CursorPosition > 0)
|
||||
CursorPosition--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.KeyName == "right")
|
||||
{
|
||||
if (CursorPosition <= Text.Length-1)
|
||||
CursorPosition++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.KeyName == "delete")
|
||||
{
|
||||
if (Text.Length > 0 && CursorPosition < Text.Length)
|
||||
{
|
||||
Text = Text.Remove(CursorPosition, 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeChar(e.KeyChar);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void TypeChar(char c)
|
||||
{
|
||||
// backspace
|
||||
if (c == '\b' || c == 0x7f)
|
||||
{
|
||||
if (Text.Length > 0)
|
||||
Text = Text.Remove(Text.Length - 1);
|
||||
if (Text.Length > 0 && CursorPosition > 0)
|
||||
{
|
||||
Text = Text.Remove(CursorPosition - 1, 1);
|
||||
|
||||
CursorPosition--;
|
||||
}
|
||||
}
|
||||
else if (!char.IsControl(c))
|
||||
{
|
||||
if (MaxLength > 0 && Text.Length >= MaxLength)
|
||||
return;
|
||||
|
||||
Text += c;
|
||||
Text = Text.Insert(CursorPosition, c.ToString());
|
||||
|
||||
CursorPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,17 +158,24 @@ namespace OpenRA.Widgets
|
||||
blinkCycle = 20;
|
||||
showCursor ^= true;
|
||||
}
|
||||
|
||||
base.Tick();
|
||||
}
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
|
||||
int margin = 5;
|
||||
public virtual void DrawWithString(string text)
|
||||
{
|
||||
int margin = 5;
|
||||
if (text == null) text = "";
|
||||
|
||||
var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont;
|
||||
var cursor = (showCursor && Focused) ? "|" : "";
|
||||
var textSize = font.Measure(Text + "|");
|
||||
var pos = RenderOrigin;
|
||||
|
||||
if (CursorPosition > text.Length)
|
||||
CursorPosition = text.Length;
|
||||
|
||||
var textSize = font.Measure(text);
|
||||
var cursorPosition = font.Measure(text.Substring(0,CursorPosition));
|
||||
|
||||
WidgetUtils.DrawPanel("dialog3",
|
||||
new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height));
|
||||
|
||||
@@ -131,11 +191,19 @@ namespace OpenRA.Widgets
|
||||
Game.Renderer.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2 * margin, Bounds.Bottom);
|
||||
}
|
||||
|
||||
font.DrawText(Text + cursor, textPos, Color.White);
|
||||
font.DrawText(text, textPos, Color.White);
|
||||
|
||||
if (showCursor && Focused)
|
||||
font.DrawText("|", new float2(textPos.X + cursorPosition.X - 2, textPos.Y), Color.White);
|
||||
|
||||
if (textSize.X > Bounds.Width - 2 * margin)
|
||||
Game.Renderer.DisableScissor();
|
||||
}
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
DrawWithString(Text);
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new TextFieldWidget(this); }
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace OpenRA.Widgets
|
||||
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
var s = WorldUtils.FormatTime(Game.LocalTick);
|
||||
var s = WidgetUtils.FormatTime(Game.LocalTick);
|
||||
var size = Game.Renderer.TitleFont.Measure(s);
|
||||
Game.Renderer.TitleFont.DrawText(s, new float2(RenderBounds.Left - size.X / 2, RenderBounds.Top - 20), Color.White);
|
||||
}
|
||||
|
||||
@@ -345,12 +345,27 @@ namespace OpenRA.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
class ContainerWidget : Widget {
|
||||
public ContainerWidget() : base() { }
|
||||
public class ContainerWidget : Widget {
|
||||
public Func<string> GetBackground;
|
||||
public string Background = null;
|
||||
|
||||
public ContainerWidget() : base()
|
||||
{
|
||||
GetBackground = () => Background;
|
||||
}
|
||||
|
||||
public ContainerWidget(ContainerWidget other) : base(other)
|
||||
{
|
||||
Background = other.Background;
|
||||
GetBackground = other.GetBackground;
|
||||
}
|
||||
|
||||
public ContainerWidget(Widget other) : base(other) { }
|
||||
|
||||
public override void DrawInner( WorldRenderer wr ) { }
|
||||
public override void DrawInner( WorldRenderer wr )
|
||||
{
|
||||
var bg = GetBackground();
|
||||
if (bg != null)
|
||||
WidgetUtils.DrawPanel(bg, RenderBounds );
|
||||
}
|
||||
|
||||
public override string GetCursor(int2 pos) { return null; }
|
||||
public override Widget Clone() { return new ContainerWidget(this); }
|
||||
|
||||
@@ -41,7 +41,9 @@ namespace OpenRA
|
||||
public Widget LoadWidget( Dictionary<string, object> args, Widget parent, MiniYamlNode node)
|
||||
{
|
||||
var widget = NewWidget(node.Key, args);
|
||||
parent.AddChild( widget );
|
||||
|
||||
if (parent != null)
|
||||
parent.AddChild( widget );
|
||||
|
||||
foreach (var child in node.Value.Nodes)
|
||||
if (child.Key != "Children")
|
||||
|
||||
@@ -128,6 +128,18 @@ namespace OpenRA.Widgets
|
||||
if (ps.HasFlags(PanelSides.Right | PanelSides.Bottom))
|
||||
DrawRGBA(ss[7], new float2(Bounds.Right - ss[7].size.X, Bounds.Bottom - ss[7].size.Y));
|
||||
}
|
||||
|
||||
|
||||
public static string FormatTime(int ticks)
|
||||
{
|
||||
var seconds = ticks / 25;
|
||||
var minutes = seconds / 60;
|
||||
|
||||
if (minutes >= 60)
|
||||
return "{0:D}:{1:D2}:{2:D2}".F(minutes / 60, minutes % 60, seconds % 60);
|
||||
else
|
||||
return "{0:D2}:{1:D2}".F(minutes, seconds % 60);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace OpenRA.Widgets
|
||||
IEnumerable<Actor> SelectActorsInBox(World world, float2 a, float2 b)
|
||||
{
|
||||
return world.FindUnits(a, b)
|
||||
.Where( x => x.HasTrait<Selectable>() && x.IsVisible(world.LocalPlayer) )
|
||||
.Where( x => x.HasTrait<Selectable>() && world.LocalShroud.IsVisible(x) )
|
||||
.GroupBy(x => (x.Owner == world.LocalPlayer) ? x.Info.Traits.Get<SelectableInfo>().Priority : 0)
|
||||
.OrderByDescending(g => g.Key)
|
||||
.Select( g => g.AsEnumerable() )
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace OpenRA
|
||||
{
|
||||
get { return players.ContainsKey(localPlayerIndex) ? players[localPlayerIndex] : null; }
|
||||
}
|
||||
public readonly Shroud LocalShroud;
|
||||
|
||||
public void SetLocalPlayer(int index)
|
||||
{
|
||||
@@ -51,7 +52,6 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
public readonly Actor WorldActor;
|
||||
|
||||
public readonly Map Map;
|
||||
public readonly TileSet TileSet;
|
||||
|
||||
@@ -98,6 +98,8 @@ namespace OpenRA
|
||||
SharedRandom = new XRandom(orderManager.LobbyInfo.GlobalSettings.RandomSeed);
|
||||
|
||||
WorldActor = CreateActor( "World", new TypeDictionary() );
|
||||
LocalShroud = WorldActor.Trait<Shroud>();
|
||||
|
||||
Queries = new AllQueries(this);
|
||||
|
||||
// Add players
|
||||
|
||||
@@ -15,6 +15,7 @@ using OpenRA.FileFormats;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
using System;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace OpenRA
|
||||
public static IEnumerable<Actor> FindUnitsAtMouse(this World world, int2 mouseLocation)
|
||||
{
|
||||
var loc = mouseLocation + Game.viewport.Location;
|
||||
return FindUnits(world, loc, loc).Where(a => a.IsVisible(world.LocalPlayer));
|
||||
return FindUnits(world, loc, loc).Where(a => world.LocalShroud.IsVisible(a));
|
||||
}
|
||||
|
||||
public static IEnumerable<Actor> FindUnits(this World world, float2 a, float2 b)
|
||||
@@ -52,13 +53,8 @@ namespace OpenRA
|
||||
|
||||
public static IEnumerable<int2> FindTilesInCircle(this World world, int2 a, int r)
|
||||
{
|
||||
var min = a - new int2(r, r);
|
||||
var max = a + new int2(r, r);
|
||||
if (min.X < world.Map.XOffset) min.X = world.Map.XOffset;
|
||||
if (min.Y < world.Map.YOffset) min.Y = world.Map.YOffset;
|
||||
if (max.X > world.Map.XOffset + world.Map.Width - 1) max.X = world.Map.XOffset + world.Map.Width - 1;
|
||||
if (max.Y > world.Map.YOffset + world.Map.Height - 1) max.Y = world.Map.YOffset + world.Map.Height - 1;
|
||||
|
||||
var min = world.ClampToWorld(a - new int2(r, r));
|
||||
var max = world.ClampToWorld(a + new int2(r, r));
|
||||
for (var j = min.Y; j <= max.Y; j++)
|
||||
for (var i = min.X; i <= max.X; i++)
|
||||
if (r * r >= (new int2(i, j) - a).LengthSquared)
|
||||
@@ -76,25 +72,9 @@ namespace OpenRA
|
||||
return world.TileSet.Terrain[world.GetTerrainType(cell)];
|
||||
}
|
||||
|
||||
public static bool IsVisible(this Actor a, Player byPlayer) /* must never be relied on in synced code! */
|
||||
{
|
||||
if (byPlayer == null) return true; // Observer
|
||||
if (a.World.LocalPlayer != null && a.World.LocalPlayer.Shroud.Disabled)
|
||||
return true;
|
||||
|
||||
var shroud = a.World.WorldActor.Trait<Shroud>();
|
||||
if (!Shroud.GetVisOrigins(a).Any(o => a.World.Map.IsInMap(o) && shroud.exploredCells[o.X, o.Y])) // covered by shroud
|
||||
return false;
|
||||
|
||||
if (a.TraitsImplementing<IVisibilityModifier>().Any(t => !t.IsVisible(a, byPlayer)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int2 ClampToWorld( this World world, int2 xy )
|
||||
{
|
||||
return int2.Min(world.Map.BottomRight, int2.Max(world.Map.TopLeft, xy));
|
||||
return xy.Clamp(world.Map.Bounds);
|
||||
}
|
||||
|
||||
public static int2 ChooseRandomEdgeCell(this World w)
|
||||
@@ -103,17 +83,17 @@ namespace OpenRA
|
||||
var edge = w.SharedRandom.Next(2) == 0;
|
||||
|
||||
return new int2(
|
||||
isX ? w.SharedRandom.Next(w.Map.XOffset, w.Map.XOffset + w.Map.Width)
|
||||
: (edge ? w.Map.XOffset : w.Map.XOffset + w.Map.Width),
|
||||
!isX ? w.SharedRandom.Next(w.Map.YOffset, w.Map.YOffset + w.Map.Height)
|
||||
: (edge ? w.Map.YOffset : w.Map.YOffset + w.Map.Height));
|
||||
isX ? w.SharedRandom.Next(w.Map.Bounds.Left, w.Map.Bounds.Right)
|
||||
: (edge ? w.Map.Bounds.Left : w.Map.Bounds.Right),
|
||||
!isX ? w.SharedRandom.Next(w.Map.Bounds.Top, w.Map.Bounds.Bottom)
|
||||
: (edge ? w.Map.Bounds.Top : w.Map.Bounds.Bottom));
|
||||
}
|
||||
|
||||
public static int2 ChooseRandomCell(this World w, Thirdparty.Random r)
|
||||
{
|
||||
return new int2(
|
||||
r.Next(w.Map.XOffset, w.Map.XOffset + w.Map.Width),
|
||||
r.Next(w.Map.YOffset, w.Map.YOffset + w.Map.Height));
|
||||
r.Next(w.Map.Bounds.Left, w.Map.Bounds.Right),
|
||||
r.Next(w.Map.Bounds.Top, w.Map.Bounds.Bottom));
|
||||
}
|
||||
|
||||
public static IEnumerable<CountryInfo> GetCountries(this World w)
|
||||
@@ -134,17 +114,6 @@ namespace OpenRA
|
||||
return new float2(Gauss1D(r, samples), Gauss1D(r, samples));
|
||||
}
|
||||
|
||||
public static string FormatTime(int ticks)
|
||||
{
|
||||
var seconds = ticks / 25;
|
||||
var minutes = seconds / 60;
|
||||
|
||||
if (minutes >= 60)
|
||||
return "{0:D}:{1:D2}:{2:D2}".F(minutes / 60, minutes % 60, seconds % 60);
|
||||
else
|
||||
return "{0:D2}:{1:D2}".F(minutes, seconds % 60);
|
||||
}
|
||||
|
||||
public static bool HasVoice(this Actor a)
|
||||
{
|
||||
return a.Info.Traits.Contains<SelectableInfo>() && a.Info.Traits.Get<SelectableInfo>().Voice != null;
|
||||
|
||||
39
OpenRA.Launcher.Mac/Controller.h
Normal file
39
OpenRA.Launcher.Mac/Controller.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
@class Mod;
|
||||
@class SidebarEntry;
|
||||
@class GameInstall;
|
||||
@class JSBridge;
|
||||
@class Download;
|
||||
@interface Controller : NSObject
|
||||
{
|
||||
SidebarEntry *sidebarItems;
|
||||
GameInstall *game;
|
||||
NSDictionary *allMods;
|
||||
NSMutableDictionary *downloads;
|
||||
BOOL hasMono;
|
||||
|
||||
IBOutlet NSWindow *window;
|
||||
IBOutlet NSOutlineView *outlineView;
|
||||
IBOutlet WebView *webView;
|
||||
}
|
||||
@property(readonly) NSDictionary *allMods;
|
||||
@property(readonly) WebView *webView;
|
||||
|
||||
- (void)launchMod:(NSString *)mod;
|
||||
- (void)populateModInfo;
|
||||
- (SidebarEntry *)sidebarModsTree;
|
||||
- (SidebarEntry *)sidebarOtherTree;
|
||||
|
||||
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filePath:(NSString *)path;
|
||||
- (Download *)downloadWithKey:(NSString *)key;
|
||||
- (BOOL)hasSupportedMono;
|
||||
@end
|
||||
303
OpenRA.Launcher.Mac/Controller.m
Normal file
303
OpenRA.Launcher.Mac/Controller.m
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import "Controller.h"
|
||||
#import "Mod.h"
|
||||
#import "SidebarEntry.h"
|
||||
#import "GameInstall.h"
|
||||
#import "ImageAndTextCell.h"
|
||||
#import "JSBridge.h"
|
||||
#import "Download.h"
|
||||
|
||||
@implementation Controller
|
||||
@synthesize allMods;
|
||||
@synthesize webView;
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults]
|
||||
registerDefaults:[NSDictionary dictionaryWithObject:[[NSBundle mainBundle] resourcePath]
|
||||
forKey:@"gamepath"]];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
NSString *gamePath = [[NSUserDefaults standardUserDefaults] stringForKey:@"gamepath"];
|
||||
|
||||
game = [[GameInstall alloc] initWithPath:gamePath];
|
||||
[[JSBridge sharedInstance] setController:self];
|
||||
downloads = [[NSMutableDictionary alloc] init];
|
||||
hasMono = [self hasSupportedMono];
|
||||
if (hasMono)
|
||||
{
|
||||
NSTableColumn *col = [outlineView tableColumnWithIdentifier:@"mods"];
|
||||
ImageAndTextCell *imageAndTextCell = [[[ImageAndTextCell alloc] init] autorelease];
|
||||
[col setDataCell:imageAndTextCell];
|
||||
|
||||
sidebarItems = [[SidebarEntry headerWithTitle:@""] retain];
|
||||
[self populateModInfo];
|
||||
id modsRoot = [self sidebarModsTree];
|
||||
[sidebarItems addChild:modsRoot];
|
||||
//id otherRoot = [self sidebarOtherTree];
|
||||
//[sidebarItems addChild:otherRoot];
|
||||
|
||||
|
||||
[outlineView reloadData];
|
||||
[outlineView expandItem:modsRoot expandChildren:YES];
|
||||
|
||||
if ([[modsRoot children] count] > 0)
|
||||
{
|
||||
id firstMod = [[modsRoot children] objectAtIndex:0];
|
||||
int row = [outlineView rowForItem:firstMod];
|
||||
[outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
|
||||
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL: [firstMod url]]];
|
||||
}
|
||||
|
||||
//[outlineView expandItem:otherRoot expandChildren:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
if (!hasMono)
|
||||
{
|
||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Mono Framework"
|
||||
defaultButton:@"Download Mono"
|
||||
alternateButton:@"Quit"
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"OpenRA requires the Mono Framework version 2.6.7 or later."];
|
||||
|
||||
[alert beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(monoAlertEnded:code:context:) contextInfo:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)monoAlertEnded:(NSAlert *)alert
|
||||
code:(int)button
|
||||
context:(void *)v
|
||||
{
|
||||
if (button == NSAlertDefaultReturn)
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.go-mono.com/mono-downloads/download.html"]];
|
||||
|
||||
[[NSApplication sharedApplication] terminate:self];
|
||||
}
|
||||
|
||||
- (BOOL)hasSupportedMono
|
||||
{
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:@"/Library/Frameworks/Mono.framework/Commands/mono"])
|
||||
return NO;
|
||||
|
||||
NSPipe *outPipe = [NSPipe pipe];
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:@"/Library/Frameworks/Mono.framework/Commands/mono"];
|
||||
[task setArguments:[NSMutableArray arrayWithObject:@"--version"]];
|
||||
[task setStandardOutput:outPipe];
|
||||
[task setStandardError:[task standardOutput]];
|
||||
[task launch];
|
||||
|
||||
NSData *data = [[outPipe fileHandleForReading] readDataToEndOfFile];
|
||||
[task waitUntilExit];
|
||||
[task release];
|
||||
|
||||
NSString *ret = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
|
||||
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int point = 0;
|
||||
sscanf([ret UTF8String], "Mono JIT compiler version %d.%d.%d", &major, &minor, &point);
|
||||
[ret release];
|
||||
|
||||
return (major > 2 ||
|
||||
(major == 2 && minor > 6) ||
|
||||
(major == 2 && minor == 6 && point >= 7));
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[sidebarItems release]; sidebarItems = nil;
|
||||
[downloads release]; downloads = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)populateModInfo
|
||||
{
|
||||
// Get info for all installed mods
|
||||
[allMods autorelease];
|
||||
allMods = [[game infoForMods:[game installedMods]] retain];
|
||||
}
|
||||
|
||||
- (SidebarEntry *)sidebarModsTree
|
||||
{
|
||||
SidebarEntry *rootItem = [SidebarEntry headerWithTitle:@"MODS"];
|
||||
for (id key in allMods)
|
||||
{
|
||||
id aMod = [allMods objectForKey:key];
|
||||
if ([aMod standalone])
|
||||
{
|
||||
id path = [[game gamePath] stringByAppendingPathComponent:@"mods"];
|
||||
id child = [SidebarEntry entryWithMod:aMod allMods:allMods baseURL:[NSURL URLWithString:path]];
|
||||
[rootItem addChild:child];
|
||||
}
|
||||
}
|
||||
|
||||
return rootItem;
|
||||
}
|
||||
|
||||
- (SidebarEntry *)sidebarOtherTree
|
||||
{
|
||||
SidebarEntry *rootItem = [SidebarEntry headerWithTitle:@"OTHER"];
|
||||
[rootItem addChild:[SidebarEntry entryWithTitle:@"Support" url:nil icon:nil]];
|
||||
[rootItem addChild:[SidebarEntry entryWithTitle:@"Credits" url:nil icon:nil]];
|
||||
|
||||
return rootItem;
|
||||
}
|
||||
|
||||
- (void)launchMod:(NSString *)mod
|
||||
{
|
||||
[game launchMod:mod];
|
||||
}
|
||||
|
||||
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filePath:(NSString *)path;
|
||||
{
|
||||
if ([downloads objectForKey:key] != nil)
|
||||
return NO;
|
||||
|
||||
[downloads setObject:[Download downloadWithURL:url filename:path key:key game:game]
|
||||
forKey:key];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (Download *)downloadWithKey:(NSString *)key
|
||||
{
|
||||
return [downloads objectForKey:key];
|
||||
}
|
||||
|
||||
#pragma mark Sidebar Datasource and Delegate
|
||||
- (NSInteger)outlineView:(NSOutlineView *)anOutlineView numberOfChildrenOfItem:(id)item
|
||||
{
|
||||
// Can be called before awakeFromNib; return nothing
|
||||
if (sidebarItems == nil)
|
||||
return 0;
|
||||
|
||||
// Root item
|
||||
if (item == nil)
|
||||
return [[sidebarItems children] count];
|
||||
|
||||
return [[item children] count];
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
|
||||
{
|
||||
return (item == nil) ? YES : [[item children] count] != 0;
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView *)outlineView
|
||||
child:(NSInteger)index
|
||||
ofItem:(id)item
|
||||
{
|
||||
if (item == nil)
|
||||
return [[sidebarItems children] objectAtIndex:index];
|
||||
|
||||
return [[item children] objectAtIndex:index];
|
||||
}
|
||||
|
||||
-(BOOL)outlineView:(NSOutlineView*)outlineView isGroupItem:(id)item
|
||||
{
|
||||
if (item == nil)
|
||||
return NO;
|
||||
|
||||
return [item isHeader];
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView *)outlineView
|
||||
objectValueForTableColumn:(NSTableColumn *)tableColumn
|
||||
byItem:(id)item
|
||||
{
|
||||
return [item title];
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
|
||||
{
|
||||
// don't allow headers to be selected
|
||||
if ([item isHeader] || [item url] == nil)
|
||||
return NO;
|
||||
|
||||
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[item url]]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||
{
|
||||
if ([[tableColumn identifier] isEqualToString:@"mods"])
|
||||
{
|
||||
if ([cell isKindOfClass:[ImageAndTextCell class]])
|
||||
{
|
||||
[(ImageAndTextCell*)cell setImage:[item icon]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark WebView delegates
|
||||
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame
|
||||
{
|
||||
[windowObject setValue:[JSBridge sharedInstance] forKey:@"external"];
|
||||
}
|
||||
|
||||
- (void)webView:(WebView *)webView addMessageToConsole:(NSDictionary *)dictionary
|
||||
{
|
||||
NSLog(@"%@",dictionary);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Application delegates
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
int count = 0;
|
||||
for (NSString *key in downloads)
|
||||
if ([[(Download *)[downloads objectForKey:key] status] isEqualToString:@"DOWNLOADING"])
|
||||
count++;
|
||||
|
||||
if (count == 0)
|
||||
return NSTerminateNow;
|
||||
|
||||
NSString *format = count == 1 ? @"1 download is" : [NSString stringWithFormat:@"%d downloads are",count];
|
||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Are you sure you want to quit?"
|
||||
defaultButton:@"Wait"
|
||||
alternateButton:@"Quit"
|
||||
otherButton:nil
|
||||
informativeTextWithFormat:@"%@ in progress and will be cancelled if you quit.", format];
|
||||
|
||||
[alert beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(quitAlertEnded:code:context:) contextInfo:NULL];
|
||||
return NSTerminateLater;
|
||||
}
|
||||
|
||||
- (void)quitAlertEnded:(NSAlert *)alert
|
||||
code:(int)button
|
||||
context:(void *)v
|
||||
{
|
||||
NSApplicationTerminateReply reply = (button == NSAlertDefaultReturn) ? NSTerminateCancel : NSTerminateNow;
|
||||
[[NSApplication sharedApplication] replyToApplicationShouldTerminate:reply];
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
// Cancel all in-progress downloads
|
||||
for (NSString *key in downloads)
|
||||
{
|
||||
Download *d = [downloads objectForKey:key];
|
||||
if ([[d status] isEqualToString:@"DOWNLOADING"])
|
||||
[d cancel];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
36
OpenRA.Launcher.Mac/Download.h
Normal file
36
OpenRA.Launcher.Mac/Download.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class GameInstall;
|
||||
@interface Download : NSObject
|
||||
{
|
||||
NSString *key;
|
||||
NSString *url;
|
||||
NSString *filename;
|
||||
GameInstall *game;
|
||||
NSTask *task;
|
||||
NSString *status;
|
||||
NSString *error;
|
||||
int bytesCompleted;
|
||||
int bytesTotal;
|
||||
}
|
||||
|
||||
@property(readonly) NSString *key;
|
||||
@property(readonly) NSString *status;
|
||||
@property(readonly) int bytesCompleted;
|
||||
@property(readonly) int bytesTotal;
|
||||
@property(readonly) NSString *error;
|
||||
|
||||
+ (id)downloadWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame;
|
||||
- (id)initWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)game;
|
||||
- (BOOL)start;
|
||||
- (BOOL)cancel;
|
||||
- (BOOL)extractToPath:(NSString *)aPath;
|
||||
@end
|
||||
196
OpenRA.Launcher.Mac/Download.m
Normal file
196
OpenRA.Launcher.Mac/Download.m
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import "Download.h"
|
||||
#import "GameInstall.h"
|
||||
#import "JSBridge.h"
|
||||
|
||||
@implementation Download
|
||||
@synthesize key;
|
||||
@synthesize status;
|
||||
@synthesize bytesCompleted;
|
||||
@synthesize bytesTotal;
|
||||
@synthesize error;
|
||||
|
||||
+ (id)downloadWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame
|
||||
{
|
||||
id newObject = [[self alloc] initWithURL:aURL filename:aFilename key:aKey game:aGame];
|
||||
[newObject autorelease];
|
||||
return newObject;
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame;
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
url = [aURL retain];
|
||||
filename = [aFilename retain];
|
||||
key = [aKey retain];
|
||||
game = [aGame retain];
|
||||
error = @"";
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
|
||||
{
|
||||
status = @"DOWNLOADED";
|
||||
bytesCompleted = bytesTotal = [[[NSFileManager defaultManager] attributesOfItemAtPath:filename error:NULL] fileSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
status = @"AVAILABLE";
|
||||
bytesCompleted = bytesTotal = -1;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)start
|
||||
{
|
||||
status = @"DOWNLOADING";
|
||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
|
||||
delegate:self
|
||||
responseSelector:@selector(downloadResponded:)
|
||||
terminatedSelector:@selector(utilityTerminated:)];
|
||||
[task retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)cancel
|
||||
{
|
||||
status = @"ERROR";
|
||||
error = @"Download Cancelled";
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:filename error:NULL];
|
||||
bytesCompleted = bytesTotal = -1;
|
||||
|
||||
[[JSBridge sharedInstance] notifyDownloadProgress:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSFileHandleReadCompletionNotification
|
||||
object:[[task standardOutput] fileHandleForReading]];
|
||||
[task terminate];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)downloadResponded:(NSNotification *)n
|
||||
{
|
||||
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
||||
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||
|
||||
// Response can contain multiple lines, or no lines. Split into lines, and parse each in turn
|
||||
NSArray *lines = [response componentsSeparatedByString:@"\n"];
|
||||
for (NSString *line in lines)
|
||||
{
|
||||
NSRange separator = [line rangeOfString:@":"];
|
||||
if (separator.location == NSNotFound)
|
||||
continue; // We only care about messages of the form key: value
|
||||
|
||||
NSString *type = [line substringToIndex:separator.location];
|
||||
NSString *message = [[line substringFromIndex:separator.location+1]
|
||||
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
if ([type isEqualToString:@"Error"])
|
||||
{
|
||||
status = @"ERROR";
|
||||
[error autorelease];
|
||||
if ([[message substringToIndex:36] isEqualToString:@"The remote server returned an error:"])
|
||||
error = [[message substringFromIndex:37] retain];
|
||||
else
|
||||
error = [message retain];
|
||||
}
|
||||
|
||||
else if ([type isEqualToString:@"Status"])
|
||||
{
|
||||
if ([message isEqualToString:@"Completed"])
|
||||
{
|
||||
status = @"DOWNLOADED";
|
||||
}
|
||||
|
||||
// Parse download status info
|
||||
int done,total;
|
||||
if (sscanf([message UTF8String], "%*d%% %d/%d bytes", &done, &total) == 2)
|
||||
{
|
||||
bytesCompleted = done;
|
||||
bytesTotal = total;
|
||||
}
|
||||
}
|
||||
}
|
||||
[[JSBridge sharedInstance] notifyDownloadProgress:self];
|
||||
|
||||
// Keep reading
|
||||
if ([n object] != nil)
|
||||
[[n object] readInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
- (BOOL)extractToPath:(NSString *)aPath
|
||||
{
|
||||
status = @"EXTRACTING";
|
||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--extract-zip=%@,%@",filename,aPath]
|
||||
delegate:self
|
||||
responseSelector:@selector(extractResponded:)
|
||||
terminatedSelector:@selector(utilityTerminated:)];
|
||||
[task retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)extractResponded:(NSNotification *)n
|
||||
{
|
||||
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
||||
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||
|
||||
// Response can contain multiple lines, or no lines. Split into lines, and parse each in turn
|
||||
NSArray *lines = [response componentsSeparatedByString:@"\n"];
|
||||
for (NSString *line in lines)
|
||||
{
|
||||
NSLog(@"%@",line);
|
||||
NSRange separator = [line rangeOfString:@":"];
|
||||
if (separator.location == NSNotFound)
|
||||
continue; // We only care about messages of the form key: value
|
||||
|
||||
NSString *type = [line substringToIndex:separator.location];
|
||||
NSString *message = [[line substringFromIndex:separator.location+1]
|
||||
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
if ([type isEqualToString:@"Error"])
|
||||
{
|
||||
status = @"ERROR";
|
||||
[error autorelease];
|
||||
error = [message retain];
|
||||
}
|
||||
|
||||
else if ([type isEqualToString:@"Status"])
|
||||
{
|
||||
if ([message isEqualToString:@"Completed"])
|
||||
{
|
||||
status = @"EXTRACTED";
|
||||
}
|
||||
}
|
||||
}
|
||||
[[JSBridge sharedInstance] notifyExtractProgress:self];
|
||||
|
||||
// Keep reading
|
||||
if ([n object] != nil)
|
||||
[[n object] readInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
- (void)utilityTerminated:(NSNotification *)n
|
||||
{
|
||||
NSLog(@"download terminated");
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]];
|
||||
[nc removeObserver:self name:NSTaskDidTerminateNotification object:task];
|
||||
[task release]; task = nil;
|
||||
|
||||
if (status == @"ERROR")
|
||||
{
|
||||
[[NSFileManager defaultManager] removeItemAtPath:filename error:NULL];
|
||||
bytesCompleted = bytesTotal = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
29
OpenRA.Launcher.Mac/GameInstall.h
Normal file
29
OpenRA.Launcher.Mac/GameInstall.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class Mod;
|
||||
@class Controller;
|
||||
@interface GameInstall : NSObject {
|
||||
NSString *gamePath;
|
||||
Controller *controller;
|
||||
NSMutableDictionary *downloadTasks;
|
||||
}
|
||||
@property(readonly) NSString *gamePath;
|
||||
|
||||
-(id)initWithPath:(NSString *)path;
|
||||
-(void)launchMod:(NSString *)mod;
|
||||
- (NSString *)runUtilityQuery:(NSString *)arg;
|
||||
- (NSArray *)installedMods;
|
||||
- (NSDictionary *)infoForMods:(NSArray *)mods;
|
||||
- (NSTask *)runAsyncUtilityWithArg:(NSString *)arg
|
||||
delegate:(id)object
|
||||
responseSelector:(SEL)response
|
||||
terminatedSelector:(SEL)terminated;
|
||||
@end
|
||||
178
OpenRA.Launcher.Mac/GameInstall.m
Normal file
178
OpenRA.Launcher.Mac/GameInstall.m
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import "GameInstall.h"
|
||||
#import "Controller.h"
|
||||
#import "Mod.h"
|
||||
|
||||
@implementation GameInstall
|
||||
@synthesize gamePath;
|
||||
|
||||
-(id)initWithPath:(NSString *)path
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
gamePath = [path retain];
|
||||
downloadTasks = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[gamePath release]; gamePath = nil;
|
||||
[downloadTasks release]; downloadTasks = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSArray *)installedMods
|
||||
{
|
||||
id raw = [self runUtilityQuery:@"-l"];
|
||||
id mods = [raw stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
return [mods componentsSeparatedByString:@"\n"];
|
||||
}
|
||||
|
||||
- (NSDictionary *)infoForMods:(NSArray *)mods
|
||||
{
|
||||
id query = [NSString stringWithFormat:@"-i=%@",[mods componentsJoinedByString:@","]];
|
||||
NSArray *lines = [[self runUtilityQuery:query] componentsSeparatedByString:@"\n"];
|
||||
|
||||
NSMutableDictionary *ret = [NSMutableDictionary dictionary];
|
||||
NSMutableDictionary *fields = nil;
|
||||
NSString *current = nil;
|
||||
for (id l in lines)
|
||||
{
|
||||
NSString *line = [l stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
if (line == nil || [line length] == 0)
|
||||
continue;
|
||||
|
||||
id kv = [line componentsSeparatedByString:@":"];
|
||||
if ([kv count] < 2)
|
||||
continue;
|
||||
|
||||
id key = [kv objectAtIndex:0];
|
||||
id value = [kv objectAtIndex:1];
|
||||
|
||||
if ([key isEqualToString:@"Error"])
|
||||
{
|
||||
NSLog(@"Error: %@",value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([key isEqualToString:@"Mod"])
|
||||
{
|
||||
// Commit prev mod
|
||||
if (current != nil)
|
||||
{
|
||||
id path = [gamePath stringByAppendingPathComponent:[NSString stringWithFormat:@"mods/%@",current]];
|
||||
[ret setObject:[Mod modWithId:current fields:fields baseURL:[NSURL URLWithString:path]] forKey:current];
|
||||
}
|
||||
NSLog(@"Parsing mod %@",value);
|
||||
current = value;
|
||||
fields = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
if (fields != nil)
|
||||
[fields setObject:[value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
|
||||
forKey:key];
|
||||
}
|
||||
if (current != nil)
|
||||
{
|
||||
id path = [gamePath stringByAppendingPathComponent:[NSString stringWithFormat:@"mods/%@",current]];
|
||||
[ret setObject:[Mod modWithId:current fields:fields baseURL:[NSURL URLWithString:path]] forKey:current];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
-(void)launchMod:(NSString *)mod
|
||||
{
|
||||
// Use LaunchServices because neither NSTask or NSWorkspace support Info.plist _and_ arguments pre-10.6
|
||||
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"OpenRA.app/Contents/MacOS/OpenRA"];
|
||||
|
||||
// First argument is the directory to run in
|
||||
// Second...Nth arguments are passed to OpenRA.Game.exe
|
||||
// Launcher wrapper sets mono --debug, gl renderer and support dir.
|
||||
NSArray *args = [NSArray arrayWithObjects:gamePath,
|
||||
[NSString stringWithFormat:@"Game.Mods=%@",mod],
|
||||
nil];
|
||||
|
||||
FSRef appRef;
|
||||
CFURLGetFSRef((CFURLRef)[NSURL URLWithString:path], &appRef);
|
||||
|
||||
// Set the launch parameters
|
||||
LSApplicationParameters params;
|
||||
params.version = 0;
|
||||
params.flags = kLSLaunchDefaults;
|
||||
params.application = &appRef;
|
||||
params.asyncLaunchRefCon = NULL;
|
||||
params.environment = NULL; // CFDictionaryRef of environment variables; could be useful
|
||||
params.argv = (CFArrayRef)args;
|
||||
params.initialEvent = NULL;
|
||||
|
||||
ProcessSerialNumber psn;
|
||||
OSStatus err = LSOpenApplication(¶ms, &psn);
|
||||
|
||||
// Bring the game window to the front
|
||||
if (err == noErr)
|
||||
SetFrontProcess(&psn);
|
||||
}
|
||||
|
||||
- (NSString *)runUtilityQuery:(NSString *)arg
|
||||
{
|
||||
NSPipe *outPipe = [NSPipe pipe];
|
||||
NSMutableArray *taskArgs = [NSMutableArray arrayWithObject:@"OpenRA.Utility.exe"];
|
||||
[taskArgs addObject:arg];
|
||||
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setCurrentDirectoryPath:gamePath];
|
||||
[task setLaunchPath:@"/Library/Frameworks/Mono.framework/Commands/mono"];
|
||||
[task setArguments:taskArgs];
|
||||
[task setStandardOutput:outPipe];
|
||||
[task setStandardError:[task standardOutput]];
|
||||
[task launch];
|
||||
NSData *data = [[outPipe fileHandleForReading] readDataToEndOfFile];
|
||||
[task waitUntilExit];
|
||||
[task release];
|
||||
|
||||
return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||
}
|
||||
|
||||
- (NSTask *)runAsyncUtilityWithArg:(NSString *)arg
|
||||
delegate:(id)object
|
||||
responseSelector:(SEL)response
|
||||
terminatedSelector:(SEL)terminated
|
||||
{
|
||||
NSTask *task = [[[NSTask alloc] init] autorelease];
|
||||
NSPipe *pipe = [NSPipe pipe];
|
||||
|
||||
NSMutableArray *taskArgs = [NSMutableArray arrayWithObject:@"OpenRA.Utility.exe"];
|
||||
[taskArgs addObject:arg];
|
||||
|
||||
[task setCurrentDirectoryPath:gamePath];
|
||||
[task setLaunchPath:@"/Library/Frameworks/Mono.framework/Commands/mono"];
|
||||
[task setArguments:taskArgs];
|
||||
[task setStandardOutput:pipe];
|
||||
|
||||
NSFileHandle *readHandle = [pipe fileHandleForReading];
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc addObserver:object
|
||||
selector:response
|
||||
name:NSFileHandleReadCompletionNotification
|
||||
object:readHandle];
|
||||
[nc addObserver:object
|
||||
selector:terminated
|
||||
name:NSTaskDidTerminateNotification
|
||||
object:task];
|
||||
[task launch];
|
||||
[readHandle readInBackgroundAndNotify];
|
||||
return task;
|
||||
}
|
||||
|
||||
@end
|
||||
62
OpenRA.Launcher.Mac/ImageAndTextCell.h
Executable file
62
OpenRA.Launcher.Mac/ImageAndTextCell.h
Executable file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// File: ImageAndTextCell.h
|
||||
//
|
||||
// Abstract: Subclass of NSTextFieldCell which can display text and an image simultaneously.
|
||||
//
|
||||
// Version: 1.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple")
|
||||
// in consideration of your agreement to the following terms, and your use,
|
||||
// installation, modification or redistribution of this Apple software
|
||||
// constitutes acceptance of these terms. If you do not agree with these
|
||||
// terms, please do not use, install, modify or redistribute this Apple
|
||||
// software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non - exclusive
|
||||
// license, under Apple's copyrights in this original Apple software ( the
|
||||
// "Apple Software" ), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and / or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following text
|
||||
// and disclaimers in all such redistributions of the Apple Software. Neither
|
||||
// the name, trademarks, service marks or logos of Apple Inc. may be used to
|
||||
// endorse or promote products derived from the Apple Software without specific
|
||||
// prior written permission from Apple. Except as expressly stated in this
|
||||
// notice, no other rights or licenses, express or implied, are granted by
|
||||
// Apple herein, including but not limited to any patent rights that may be
|
||||
// infringed by your derivative works or by other works in which the Apple
|
||||
// Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
|
||||
// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
|
||||
// ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
|
||||
// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
|
||||
// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
|
||||
// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2007 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ImageAndTextCell : NSTextFieldCell
|
||||
{
|
||||
@private
|
||||
NSImage *image;
|
||||
}
|
||||
|
||||
- (void)setImage:(NSImage *)anImage;
|
||||
- (NSImage*)image;
|
||||
|
||||
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
|
||||
- (NSSize)cellSize;
|
||||
|
||||
@end
|
||||
252
OpenRA.Launcher.Mac/ImageAndTextCell.m
Executable file
252
OpenRA.Launcher.Mac/ImageAndTextCell.m
Executable file
@@ -0,0 +1,252 @@
|
||||
//
|
||||
// File: ImageAndTextCell.m
|
||||
//
|
||||
// Abstract: Subclass of NSTextFieldCell which can display text and an image simultaneously.
|
||||
//
|
||||
// Version: 1.0
|
||||
//
|
||||
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple")
|
||||
// in consideration of your agreement to the following terms, and your use,
|
||||
// installation, modification or redistribution of this Apple software
|
||||
// constitutes acceptance of these terms. If you do not agree with these
|
||||
// terms, please do not use, install, modify or redistribute this Apple
|
||||
// software.
|
||||
//
|
||||
// In consideration of your agreement to abide by the following terms, and
|
||||
// subject to these terms, Apple grants you a personal, non - exclusive
|
||||
// license, under Apple's copyrights in this original Apple software ( the
|
||||
// "Apple Software" ), to use, reproduce, modify and redistribute the Apple
|
||||
// Software, with or without modifications, in source and / or binary forms;
|
||||
// provided that if you redistribute the Apple Software in its entirety and
|
||||
// without modifications, you must retain this notice and the following text
|
||||
// and disclaimers in all such redistributions of the Apple Software. Neither
|
||||
// the name, trademarks, service marks or logos of Apple Inc. may be used to
|
||||
// endorse or promote products derived from the Apple Software without specific
|
||||
// prior written permission from Apple. Except as expressly stated in this
|
||||
// notice, no other rights or licenses, express or implied, are granted by
|
||||
// Apple herein, including but not limited to any patent rights that may be
|
||||
// infringed by your derivative works or by other works in which the Apple
|
||||
// Software may be incorporated.
|
||||
//
|
||||
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
|
||||
// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
|
||||
// ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
//
|
||||
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
|
||||
// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
|
||||
// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
|
||||
// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (C) 2007 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#import "ImageAndTextCell.h"
|
||||
//#import "BaseNode.h"
|
||||
|
||||
@implementation ImageAndTextCell
|
||||
|
||||
#define kIconImageSize 16.0
|
||||
|
||||
#define kImageOriginXOffset 3
|
||||
#define kImageOriginYOffset 1
|
||||
|
||||
#define kTextOriginXOffset 2
|
||||
#define kTextOriginYOffset 2
|
||||
#define kTextHeightAdjust 4
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// init:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
// we want a smaller font
|
||||
[self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// dealloc:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)dealloc
|
||||
{
|
||||
[image release];
|
||||
image = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// copyWithZone:zone
|
||||
// -------------------------------------------------------------------------------
|
||||
- (id)copyWithZone:(NSZone*)zone
|
||||
{
|
||||
ImageAndTextCell *cell = (ImageAndTextCell*)[super copyWithZone:zone];
|
||||
cell->image = [image retain];
|
||||
return cell;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// setImage:anImage
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)setImage:(NSImage*)anImage
|
||||
{
|
||||
if (anImage != image)
|
||||
{
|
||||
[image autorelease];
|
||||
image = [anImage retain];
|
||||
[image setSize:NSMakeSize(kIconImageSize, kIconImageSize)];
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// image:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (NSImage*)image
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// isGroupCell:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (BOOL)isGroupCell
|
||||
{
|
||||
return ([self image] == nil && [[self title] length] > 0);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// titleRectForBounds:cellRect
|
||||
//
|
||||
// Returns the proper bound for the cell's title while being edited
|
||||
// -------------------------------------------------------------------------------
|
||||
- (NSRect)titleRectForBounds:(NSRect)cellRect
|
||||
{
|
||||
// the cell has an image: draw the normal item cell
|
||||
NSSize imageSize;
|
||||
NSRect imageFrame;
|
||||
|
||||
imageSize = [image size];
|
||||
NSDivideRect(cellRect, &imageFrame, &cellRect, 3 + imageSize.width, NSMinXEdge);
|
||||
|
||||
imageFrame.origin.x += kImageOriginXOffset;
|
||||
imageFrame.origin.y -= kImageOriginYOffset;
|
||||
imageFrame.size = imageSize;
|
||||
|
||||
imageFrame.origin.y += ceil((cellRect.size.height - imageFrame.size.height) / 2);
|
||||
|
||||
NSRect newFrame = cellRect;
|
||||
newFrame.origin.x += kTextOriginXOffset;
|
||||
newFrame.origin.y += kTextOriginYOffset;
|
||||
newFrame.size.height -= kTextHeightAdjust;
|
||||
|
||||
return newFrame;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// editWithFrame:inView:editor:delegate:event
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)editWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObj delegate:(id)anObject event:(NSEvent*)theEvent
|
||||
{
|
||||
NSRect textFrame = [self titleRectForBounds:aRect];
|
||||
[super editWithFrame:textFrame inView:controlView editor:textObj delegate:anObject event:theEvent];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// selectWithFrame:inView:editor:delegate:event:start:length
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)selectWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength
|
||||
{
|
||||
NSRect textFrame = [self titleRectForBounds:aRect];
|
||||
[super selectWithFrame:textFrame inView:controlView editor:textObj delegate:anObject start:selStart length:selLength];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// drawWithFrame:cellFrame:controlView:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
|
||||
{
|
||||
if (image != nil)
|
||||
{
|
||||
// the cell has an image: draw the normal item cell
|
||||
NSSize imageSize;
|
||||
NSRect imageFrame;
|
||||
|
||||
imageSize = [image size];
|
||||
NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
|
||||
|
||||
imageFrame.origin.x += kImageOriginXOffset;
|
||||
imageFrame.origin.y -= kImageOriginYOffset;
|
||||
imageFrame.size = imageSize;
|
||||
|
||||
if ([controlView isFlipped])
|
||||
imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2);
|
||||
else
|
||||
imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
|
||||
[image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
|
||||
|
||||
NSRect newFrame = cellFrame;
|
||||
newFrame.origin.x += kTextOriginXOffset;
|
||||
newFrame.origin.y += kTextOriginYOffset;
|
||||
newFrame.size.height -= kTextHeightAdjust;
|
||||
[super drawWithFrame:newFrame inView:controlView];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([self isGroupCell])
|
||||
{
|
||||
// Center the text in the cellFrame, and call super to do thew ork of actually drawing.
|
||||
CGFloat yOffset = floor((NSHeight(cellFrame) - [[self attributedStringValue] size].height) / 2.0);
|
||||
cellFrame.origin.y += yOffset;
|
||||
cellFrame.size.height -= (kTextOriginYOffset*yOffset);
|
||||
[super drawWithFrame:cellFrame inView:controlView];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// cellSize:
|
||||
// -------------------------------------------------------------------------------
|
||||
- (NSSize)cellSize
|
||||
{
|
||||
NSSize cellSize = [super cellSize];
|
||||
cellSize.width += (image ? [image size].width : 0) + 3;
|
||||
return cellSize;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// hitTestForEvent:
|
||||
//
|
||||
// In 10.5, we need you to implement this method for blocking drag and drop of a given cell.
|
||||
// So NSCell hit testing will determine if a row can be dragged or not.
|
||||
//
|
||||
// NSTableView calls this cell method when starting a drag, if the hit cell returns
|
||||
// NSCellHitTrackableArea, the particular row will be tracked instead of dragged.
|
||||
//
|
||||
// -------------------------------------------------------------------------------
|
||||
/*
|
||||
- (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView
|
||||
{
|
||||
NSInteger result = NSCellHitContentArea;
|
||||
|
||||
NSOutlineView* hostingOutlineView = (NSOutlineView*)[self controlView];
|
||||
if (hostingOutlineView)
|
||||
{
|
||||
NSInteger selectedRow = [hostingOutlineView selectedRow];
|
||||
BaseNode* node = [[hostingOutlineView itemAtRow:selectedRow] representedObject];
|
||||
|
||||
if (![node isDraggable]) // is the node isDraggable (i.e. non-file system based objects)
|
||||
result = NSCellHitTrackableArea;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
@end
|
||||
|
||||
24
OpenRA.Launcher.Mac/JSBridge.h
Normal file
24
OpenRA.Launcher.Mac/JSBridge.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class Controller;
|
||||
@class Download;
|
||||
@interface JSBridge : NSObject {
|
||||
Controller *controller;
|
||||
NSDictionary *methods;
|
||||
}
|
||||
@property(readonly) NSDictionary *methods;
|
||||
|
||||
+ (JSBridge *)sharedInstance;
|
||||
- (void)setController:(Controller *)aController;
|
||||
- (void)notifyDownloadProgress:(Download *)download;
|
||||
- (void)notifyExtractProgress:(Download *)download;
|
||||
@end
|
||||
214
OpenRA.Launcher.Mac/JSBridge.m
Normal file
214
OpenRA.Launcher.Mac/JSBridge.m
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import "JSBridge.h"
|
||||
#import "Controller.h"
|
||||
#import "Download.h"
|
||||
#import "Mod.h"
|
||||
|
||||
static JSBridge *SharedInstance;
|
||||
|
||||
@implementation JSBridge
|
||||
@synthesize methods;
|
||||
|
||||
+ (JSBridge *)sharedInstance
|
||||
{
|
||||
if (SharedInstance == nil)
|
||||
SharedInstance = [[JSBridge alloc] init];
|
||||
|
||||
return SharedInstance;
|
||||
}
|
||||
|
||||
+ (NSString *)webScriptNameForSelector:(SEL)sel
|
||||
{
|
||||
return [[[JSBridge sharedInstance] methods] objectForKey:NSStringFromSelector(sel)];
|
||||
}
|
||||
|
||||
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)sel
|
||||
{
|
||||
return [[[JSBridge sharedInstance] methods] objectForKey:NSStringFromSelector(sel)] == nil;
|
||||
}
|
||||
|
||||
-(id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
methods = [[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"launchMod", NSStringFromSelector(@selector(launchMod:)),
|
||||
@"log", NSStringFromSelector(@selector(log:)),
|
||||
@"existsInMod", NSStringFromSelector(@selector(fileExists:inMod:)),
|
||||
|
||||
// File downloading
|
||||
@"registerDownload", NSStringFromSelector(@selector(registerDownload:withURL:filename:)),
|
||||
@"startDownload", NSStringFromSelector(@selector(startDownload:)),
|
||||
@"cancelDownload", NSStringFromSelector(@selector(cancelDownload:)),
|
||||
@"downloadStatus", NSStringFromSelector(@selector(downloadStatus:)),
|
||||
@"downloadError", NSStringFromSelector(@selector(downloadError:)),
|
||||
@"bytesCompleted", NSStringFromSelector(@selector(bytesCompleted:)),
|
||||
@"bytesTotal", NSStringFromSelector(@selector(bytesTotal:)),
|
||||
@"extractDownload", NSStringFromSelector(@selector(extractDownload:toPath:inMod:)),
|
||||
nil] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setController:(Controller *)aController
|
||||
{
|
||||
controller = [aController retain];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[controller release]; controller = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark JS API methods
|
||||
|
||||
- (BOOL)launchMod:(NSString *)aMod
|
||||
{
|
||||
// Build the list of mods to launch
|
||||
NSMutableArray *mods = [NSMutableArray array];
|
||||
NSString *current = aMod;
|
||||
|
||||
// Assemble the mods in the reverse order to work around an engine bug
|
||||
while (current != nil)
|
||||
{
|
||||
Mod *mod = [[controller allMods] objectForKey:current];
|
||||
if (mod == nil)
|
||||
{
|
||||
NSLog(@"Unknown mod: %@", current);
|
||||
return NO;
|
||||
}
|
||||
[mods addObject:current];
|
||||
|
||||
if ([mod standalone])
|
||||
current = nil;
|
||||
else
|
||||
current = [mod requires];
|
||||
}
|
||||
// Todo: Reverse the array ordering once the engine bug is fixed
|
||||
|
||||
[controller launchMod:[mods componentsJoinedByString:@","]];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filename:(NSString *)filename
|
||||
{
|
||||
// Disallow traversing directories; take only the last component
|
||||
id path = [[@"~/Library/Application Support/OpenRA/Downloads/" stringByAppendingPathComponent:[filename lastPathComponent]] stringByExpandingTildeInPath];
|
||||
return [controller registerDownload:key withURL:url filePath:path];
|
||||
}
|
||||
|
||||
- (NSString *)downloadStatus:(NSString *)key
|
||||
{
|
||||
Download *d = [controller downloadWithKey:key];
|
||||
if (d == nil)
|
||||
return @"NOT_REGISTERED";
|
||||
|
||||
return [d status];
|
||||
}
|
||||
|
||||
- (NSString *)downloadError:(NSString *)key
|
||||
{
|
||||
Download *d = [controller downloadWithKey:key];
|
||||
if (d == nil)
|
||||
return @"";
|
||||
|
||||
return [d error];
|
||||
}
|
||||
|
||||
- (BOOL)startDownload:(NSString *)key
|
||||
{
|
||||
Download *d = [controller downloadWithKey:key];
|
||||
return (d == nil) ? NO : [d start];
|
||||
}
|
||||
|
||||
- (BOOL)cancelDownload:(NSString *)key
|
||||
{
|
||||
Download *d = [controller downloadWithKey:key];
|
||||
return (d == nil) ? NO : [d cancel];
|
||||
}
|
||||
|
||||
- (int)bytesCompleted:(NSString *)key
|
||||
{
|
||||
Download *d = [controller downloadWithKey:key];
|
||||
return (d == nil) ? -1 : [d bytesCompleted];
|
||||
}
|
||||
|
||||
- (int)bytesTotal:(NSString *)key
|
||||
{
|
||||
Download *d = [controller downloadWithKey:key];
|
||||
return (d == nil) ? -1 : [d bytesTotal];
|
||||
}
|
||||
|
||||
- (void)notifyDownloadProgress:(Download *)download
|
||||
{
|
||||
[[[controller webView] windowScriptObject] evaluateWebScript:
|
||||
[NSString stringWithFormat:@"downloadProgressed('%@')",[download key]]];
|
||||
}
|
||||
|
||||
- (void)notifyExtractProgress:(Download *)download
|
||||
{
|
||||
[[[controller webView] windowScriptObject] evaluateWebScript:
|
||||
[NSString stringWithFormat:@"extractProgressed('%@')",[download key]]];
|
||||
}
|
||||
|
||||
- (BOOL)extractDownload:(NSString *)key toPath:(NSString *)aFile inMod:(NSString *)aMod
|
||||
{
|
||||
Download *d = [controller downloadWithKey:key];
|
||||
if (d == nil)
|
||||
{
|
||||
NSLog(@"Unknown download");
|
||||
return NO;
|
||||
}
|
||||
if (![[d status] isEqualToString:@"DOWNLOADED"])
|
||||
{
|
||||
NSLog(@"Invalid download status");
|
||||
return NO;
|
||||
}
|
||||
|
||||
id mod = [[controller allMods] objectForKey:aMod];
|
||||
if (mod == nil)
|
||||
{
|
||||
NSLog(@"Invalid or unknown mod: %@", aMod);
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Disallow traversing up the directory tree
|
||||
id path = [aMod stringByAppendingPathComponent:[aFile stringByReplacingOccurrencesOfString:@"../"
|
||||
withString:@""]];
|
||||
|
||||
[d extractToPath:path];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)log:(NSString *)message
|
||||
{
|
||||
NSLog(@"js: %@",message);
|
||||
}
|
||||
|
||||
- (BOOL)fileExists:(NSString *)aFile inMod:(NSString *)aMod
|
||||
{
|
||||
id mod = [[controller allMods] objectForKey:aMod];
|
||||
if (mod == nil)
|
||||
{
|
||||
NSLog(@"Invalid or unknown mod: %@", aMod);
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Disallow traversing up the directory tree
|
||||
id path = [[[mod baseURL] absoluteString]
|
||||
stringByAppendingPathComponent:[aFile stringByReplacingOccurrencesOfString:@"../"
|
||||
withString:@""]];
|
||||
|
||||
return [[NSFileManager defaultManager] fileExistsAtPath:path];
|
||||
}
|
||||
|
||||
@end
|
||||
33
OpenRA.Launcher.Mac/Mod.h
Normal file
33
OpenRA.Launcher.Mac/Mod.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface Mod : NSObject {
|
||||
NSURL *baseURL;
|
||||
NSString *mod;
|
||||
NSString *title;
|
||||
NSString *version;
|
||||
NSString *author;
|
||||
NSString *requires;
|
||||
NSString *description;
|
||||
BOOL standalone;
|
||||
}
|
||||
|
||||
@property (readonly) NSString *mod;
|
||||
@property (readonly) NSString *title;
|
||||
@property (readonly) NSString *version;
|
||||
@property (readonly) NSString *author;
|
||||
@property (readonly) NSString *description;
|
||||
@property (readonly) NSString *requires;
|
||||
@property (readonly) NSURL *baseURL;
|
||||
@property (readonly) BOOL standalone;
|
||||
|
||||
+ (id)modWithId:(NSString *)mid fields:(id)fields baseURL:(NSURL *)url;
|
||||
- (id)initWithId:(NSString *)anId fields:(NSDictionary *)fields baseURL:(NSURL *)url;
|
||||
@end
|
||||
58
OpenRA.Launcher.Mac/Mod.m
Normal file
58
OpenRA.Launcher.Mac/Mod.m
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import "Mod.h"
|
||||
|
||||
|
||||
@implementation Mod
|
||||
@synthesize mod;
|
||||
@synthesize title;
|
||||
@synthesize version;
|
||||
@synthesize author;
|
||||
@synthesize description;
|
||||
@synthesize requires;
|
||||
@synthesize standalone;
|
||||
@synthesize baseURL;
|
||||
|
||||
+ (id)modWithId:(NSString *)mod fields:(id)fields baseURL:(NSURL *)url
|
||||
{
|
||||
id newObject = [[self alloc] initWithId:mod fields:fields baseURL:url];
|
||||
[newObject autorelease];
|
||||
return newObject;
|
||||
}
|
||||
|
||||
- (id)initWithId:(NSString *)anId fields:(NSDictionary *)fields baseURL:(NSURL *)url
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
mod = [anId retain];
|
||||
baseURL = [url retain];
|
||||
title = [[fields objectForKey:@"Title"] retain];
|
||||
version = [[fields objectForKey:@"Version"] retain];
|
||||
author = [[fields objectForKey:@"Author"] retain];
|
||||
description = [[fields objectForKey:@"Description"] retain];
|
||||
requires = [[fields objectForKey:@"Requires"] retain];
|
||||
standalone = ([[fields objectForKey:@"Standalone"] isEqualToString:@"True"]);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[mod release]; mod = nil;
|
||||
[baseURL release]; baseURL = nil;
|
||||
[title release]; title = nil;
|
||||
[version release]; version = nil;
|
||||
[author release]; author = nil;
|
||||
[description release]; description = nil;
|
||||
[requires release]; requires = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -5,25 +5,27 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<string>OpenRA</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>OpenRA.icns</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>OpenRA Launcher</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>OpenRA Launcher</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<string>org.open-ra.launcher</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
0
packaging/osx/launcher/OpenRA.app/Contents/Info.plist → OpenRA.Launcher.Mac/OpenRA.app/Contents/Info.plist
Normal file → Executable file
0
packaging/osx/launcher/OpenRA.app/Contents/Info.plist → OpenRA.Launcher.Mac/OpenRA.app/Contents/Info.plist
Normal file → Executable file
11
OpenRA.Launcher.Mac/OpenRA.app/Contents/MacOS/OpenRA
Executable file
11
OpenRA.Launcher.Mac/OpenRA.app/Contents/MacOS/OpenRA
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
# This file is part of OpenRA, which is free software. It is made
|
||||
# available to you under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation. For more information,
|
||||
# see LICENSE.
|
||||
|
||||
export DYLD_LIBRARY_PATH="$1:$DYLD_LIBRARY_PATH"
|
||||
echo "Launching OpenRA from $1"
|
||||
cd $1
|
||||
mono --debug OpenRA.Game.exe SupportDir=~/Library/"Application Support"/OpenRA ${@:2}
|
||||
1
OpenRA.Launcher.Mac/OpenRA.app/Contents/Resources/OpenRA.icns
Symbolic link
1
OpenRA.Launcher.Mac/OpenRA.app/Contents/Resources/OpenRA.icns
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../OpenRA.icns
|
||||
0
packaging/osx/launcher/OpenRA.app/Contents/Resources/OpenRA.icns → OpenRA.Launcher.Mac/OpenRA.icns
Normal file → Executable file
0
packaging/osx/launcher/OpenRA.app/Contents/Resources/OpenRA.icns → OpenRA.Launcher.Mac/OpenRA.icns
Normal file → Executable file
@@ -8,34 +8,50 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; };
|
||||
8990E7AF1151C0F20089C198 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = 8990E7AE1151C0F20089C198 /* Controller.m */; };
|
||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
|
||||
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
||||
DA1241101151F194002EFE2B /* OpenRA.icns in Resources */ = {isa = PBXBuildFile; fileRef = DA12410F1151F194002EFE2B /* OpenRA.icns */; };
|
||||
DA28A92A117878EC00342835 /* mods.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA28A929117878EC00342835 /* mods.plist */; };
|
||||
DAAB5C7911536D6500DCCB80 /* Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAB5C7811536D6500DCCB80 /* Settings.m */; };
|
||||
DAFD657B11520799001F4C97 /* launcher.ini in Resources */ = {isa = PBXBuildFile; fileRef = DAFD657A11520799001F4C97 /* launcher.ini */; };
|
||||
DA38212212925344003B0BB5 /* JSBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = DA38212112925344003B0BB5 /* JSBridge.m */; };
|
||||
DA7D85671295E92900E58547 /* Download.m in Sources */ = {isa = PBXBuildFile; fileRef = DA7D85661295E92900E58547 /* Download.m */; };
|
||||
DA81FA821290F5C800C48F2F /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = DA81FA811290F5C800C48F2F /* Controller.m */; };
|
||||
DA81FAAA1290FA0000C48F2F /* Mod.m in Sources */ = {isa = PBXBuildFile; fileRef = DA81FAA91290FA0000C48F2F /* Mod.m */; };
|
||||
DA81FB9312910A8B00C48F2F /* ImageAndTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DA81FB9212910A8B00C48F2F /* ImageAndTextCell.m */; };
|
||||
DA81FBDC12910E4900C48F2F /* OpenRA.icns in Resources */ = {isa = PBXBuildFile; fileRef = DA81FBDB12910E4900C48F2F /* OpenRA.icns */; };
|
||||
DA81FC3F12911E2B00C48F2F /* GameInstall.m in Sources */ = {isa = PBXBuildFile; fileRef = DA81FC3E12911E2B00C48F2F /* GameInstall.m */; };
|
||||
DA9292C81291DF2D00EDB02E /* OpenRA.app in Resources */ = {isa = PBXBuildFile; fileRef = DA9292C71291DF2D00EDB02E /* OpenRA.app */; };
|
||||
DA9295A712921DF900EDB02E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9295A612921DF900EDB02E /* WebKit.framework */; };
|
||||
DA9296901292328200EDB02E /* SidebarEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DA92968F1292328200EDB02E /* SidebarEntry.m */; };
|
||||
DAB887F5129E5D6C00C99407 /* SDL in Resources */ = {isa = PBXBuildFile; fileRef = DAB887EE129E5D6100C99407 /* SDL */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||
1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
256AC3F00F4B6AF500CF3369 /* OpenRA_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenRA_Prefix.pch; sourceTree = "<group>"; };
|
||||
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||
8990E7AD1151C0F20089C198 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
|
||||
8990E7AE1151C0F20089C198 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
|
||||
8D1107310486CEB800E47090 /* OpenRA-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "OpenRA-Info.plist"; sourceTree = "<group>"; };
|
||||
8D1107320486CEB800E47090 /* OpenRA.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenRA.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DA12410F1151F194002EFE2B /* OpenRA.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = OpenRA.icns; sourceTree = "<group>"; };
|
||||
DA28A929117878EC00342835 /* mods.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = mods.plist; sourceTree = "<group>"; };
|
||||
DAAB5C7711536D6500DCCB80 /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Settings.h; sourceTree = "<group>"; };
|
||||
DAAB5C7811536D6500DCCB80 /* Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Settings.m; sourceTree = "<group>"; };
|
||||
DAFD657A11520799001F4C97 /* launcher.ini */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = launcher.ini; sourceTree = "<group>"; };
|
||||
DA38212012925344003B0BB5 /* JSBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBridge.h; sourceTree = "<group>"; };
|
||||
DA38212112925344003B0BB5 /* JSBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSBridge.m; sourceTree = "<group>"; };
|
||||
DA7D85651295E92900E58547 /* Download.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Download.h; sourceTree = "<group>"; };
|
||||
DA7D85661295E92900E58547 /* Download.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Download.m; sourceTree = "<group>"; };
|
||||
DA81FA801290F5C800C48F2F /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
|
||||
DA81FA811290F5C800C48F2F /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
|
||||
DA81FAA81290FA0000C48F2F /* Mod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mod.h; sourceTree = "<group>"; };
|
||||
DA81FAA91290FA0000C48F2F /* Mod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Mod.m; sourceTree = "<group>"; };
|
||||
DA81FB9112910A8B00C48F2F /* ImageAndTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageAndTextCell.h; sourceTree = "<group>"; };
|
||||
DA81FB9212910A8B00C48F2F /* ImageAndTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageAndTextCell.m; sourceTree = "<group>"; };
|
||||
DA81FBDB12910E4900C48F2F /* OpenRA.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = OpenRA.icns; sourceTree = "<group>"; };
|
||||
DA81FC3D12911E2B00C48F2F /* GameInstall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameInstall.h; sourceTree = "<group>"; };
|
||||
DA81FC3E12911E2B00C48F2F /* GameInstall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GameInstall.m; sourceTree = "<group>"; };
|
||||
DA9292C71291DF2D00EDB02E /* OpenRA.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = OpenRA.app; sourceTree = "<group>"; };
|
||||
DA9295A612921DF900EDB02E /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
|
||||
DA92968E1292328200EDB02E /* SidebarEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SidebarEntry.h; sourceTree = "<group>"; };
|
||||
DA92968F1292328200EDB02E /* SidebarEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SidebarEntry.m; sourceTree = "<group>"; };
|
||||
DAB887EE129E5D6100C99407 /* SDL */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = SDL; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -44,6 +60,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
|
||||
DA9295A712921DF900EDB02E /* WebKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -53,10 +70,20 @@
|
||||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8990E7AD1151C0F20089C198 /* Controller.h */,
|
||||
8990E7AE1151C0F20089C198 /* Controller.m */,
|
||||
DAAB5C7711536D6500DCCB80 /* Settings.h */,
|
||||
DAAB5C7811536D6500DCCB80 /* Settings.m */,
|
||||
DA81FB9112910A8B00C48F2F /* ImageAndTextCell.h */,
|
||||
DA81FB9212910A8B00C48F2F /* ImageAndTextCell.m */,
|
||||
DA81FA801290F5C800C48F2F /* Controller.h */,
|
||||
DA81FA811290F5C800C48F2F /* Controller.m */,
|
||||
DA81FAA81290FA0000C48F2F /* Mod.h */,
|
||||
DA81FAA91290FA0000C48F2F /* Mod.m */,
|
||||
DA81FC3D12911E2B00C48F2F /* GameInstall.h */,
|
||||
DA81FC3E12911E2B00C48F2F /* GameInstall.m */,
|
||||
DA7D85651295E92900E58547 /* Download.h */,
|
||||
DA7D85661295E92900E58547 /* Download.m */,
|
||||
DA92968E1292328200EDB02E /* SidebarEntry.h */,
|
||||
DA92968F1292328200EDB02E /* SidebarEntry.m */,
|
||||
DA38212012925344003B0BB5 /* JSBridge.h */,
|
||||
DA38212112925344003B0BB5 /* JSBridge.m */,
|
||||
);
|
||||
name = Classes;
|
||||
sourceTree = "<group>";
|
||||
@@ -73,8 +100,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29B97324FDCFA39411CA2CEA /* AppKit.framework */,
|
||||
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */,
|
||||
29B97325FDCFA39411CA2CEA /* Foundation.framework */,
|
||||
DA9295A612921DF900EDB02E /* WebKit.framework */,
|
||||
);
|
||||
name = "Other Frameworks";
|
||||
sourceTree = "<group>";
|
||||
@@ -111,12 +138,12 @@
|
||||
29B97317FDCFA39411CA2CEA /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAFD657A11520799001F4C97 /* launcher.ini */,
|
||||
DAB887EE129E5D6100C99407 /* SDL */,
|
||||
DA9292C71291DF2D00EDB02E /* OpenRA.app */,
|
||||
DA81FBDB12910E4900C48F2F /* OpenRA.icns */,
|
||||
8D1107310486CEB800E47090 /* OpenRA-Info.plist */,
|
||||
DA12410F1151F194002EFE2B /* OpenRA.icns */,
|
||||
089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
|
||||
1DDD58140DA1D0A300B32029 /* MainMenu.xib */,
|
||||
DA28A929117878EC00342835 /* mods.plist */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -140,7 +167,6 @@
|
||||
8D1107290486CEB800E47090 /* Resources */,
|
||||
8D11072C0486CEB800E47090 /* Sources */,
|
||||
8D11072E0486CEB800E47090 /* Frameworks */,
|
||||
DAFD652E1151FEA7001F4C97 /* Package Game */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -157,9 +183,19 @@
|
||||
/* Begin PBXProject section */
|
||||
29B97313FDCFA39411CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
ORGANIZATIONNAME = OpenRA;
|
||||
};
|
||||
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "OpenRA" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
Japanese,
|
||||
French,
|
||||
German,
|
||||
);
|
||||
mainGroup = 29B97314FDCFA39411CA2CEA /* OpenRA */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -174,42 +210,29 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DAB887F5129E5D6C00C99407 /* SDL in Resources */,
|
||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
|
||||
1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */,
|
||||
DA1241101151F194002EFE2B /* OpenRA.icns in Resources */,
|
||||
DAFD657B11520799001F4C97 /* launcher.ini in Resources */,
|
||||
DA28A92A117878EC00342835 /* mods.plist in Resources */,
|
||||
DA81FBDC12910E4900C48F2F /* OpenRA.icns in Resources */,
|
||||
DA9292C81291DF2D00EDB02E /* OpenRA.app in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
DAFD652E1151FEA7001F4C97 /* Package Game */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Package Game";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/bash;
|
||||
shellScript = "#./package.sh\ncp -r build/game/OpenRA.app ${TARGET_BUILD_DIR}/OpenRA.app/Contents/Resources/";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8D11072C0486CEB800E47090 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8D11072D0486CEB800E47090 /* main.m in Sources */,
|
||||
8990E7AF1151C0F20089C198 /* Controller.m in Sources */,
|
||||
DAAB5C7911536D6500DCCB80 /* Settings.m in Sources */,
|
||||
DA81FA821290F5C800C48F2F /* Controller.m in Sources */,
|
||||
DA81FAAA1290FA0000C48F2F /* Mod.m in Sources */,
|
||||
DA81FB9312910A8B00C48F2F /* ImageAndTextCell.m in Sources */,
|
||||
DA81FC3F12911E2B00C48F2F /* GameInstall.m in Sources */,
|
||||
DA9296901292328200EDB02E /* SidebarEntry.m in Sources */,
|
||||
DA38212212925344003B0BB5 /* JSBridge.m in Sources */,
|
||||
DA7D85671295E92900E58547 /* Download.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -248,6 +271,10 @@
|
||||
GCC_PREFIX_HEADER = OpenRA_Prefix.pch;
|
||||
INFOPLIST_FILE = "OpenRA-Info.plist";
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)\"",
|
||||
);
|
||||
PRODUCT_NAME = OpenRA;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -262,6 +289,10 @@
|
||||
GCC_PREFIX_HEADER = OpenRA_Prefix.pch;
|
||||
INFOPLIST_FILE = "OpenRA-Info.plist";
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)\"",
|
||||
);
|
||||
PRODUCT_NAME = OpenRA;
|
||||
};
|
||||
name = Release;
|
||||
@@ -287,6 +318,7 @@
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = macosx10.5;
|
||||
};
|
||||
7
OpenRA.Launcher.Mac/OpenRA_Prefix.pch
Normal file
7
OpenRA.Launcher.Mac/OpenRA_Prefix.pch
Normal file
@@ -0,0 +1,7 @@
|
||||
//
|
||||
// Prefix header for all source files of the 'OpenRA' target in the 'OpenRA' project
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
BIN
OpenRA.Launcher.Mac/SDL
Executable file
BIN
OpenRA.Launcher.Mac/SDL
Executable file
Binary file not shown.
32
OpenRA.Launcher.Mac/SidebarEntry.h
Normal file
32
OpenRA.Launcher.Mac/SidebarEntry.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class Mod;
|
||||
@interface SidebarEntry : NSObject
|
||||
{
|
||||
BOOL isHeader;
|
||||
NSString *title;
|
||||
NSImage *icon;
|
||||
NSURL *url;
|
||||
NSMutableArray *children;
|
||||
}
|
||||
|
||||
@property (readonly) BOOL isHeader;
|
||||
@property (readonly) NSString *title;
|
||||
@property (readonly) NSMutableArray* children;
|
||||
@property (readonly) NSImage* icon;
|
||||
|
||||
+ (id)headerWithTitle:(NSString *)aTitle;
|
||||
+ (id)entryWithTitle:(NSString *)aTitle url:(NSURL *)aURL icon:(id)anIcon;
|
||||
+ (id)entryWithMod:(Mod *)baseMod allMods:(NSDictionary *)allMods baseURL:(NSURL *)aURL;
|
||||
- (id)initWithTitle:(NSString *)aTitle url:(NSURL *)aURL icon:(id)anIcon isHeader:(BOOL)aHeader;
|
||||
- (void)addChild:(id)child;
|
||||
- (NSURL *)url;
|
||||
@end
|
||||
84
OpenRA.Launcher.Mac/SidebarEntry.m
Normal file
84
OpenRA.Launcher.Mac/SidebarEntry.m
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
|
||||
#import "SidebarEntry.h"
|
||||
#import "Mod.h"
|
||||
|
||||
@implementation SidebarEntry
|
||||
@synthesize isHeader;
|
||||
@synthesize title;
|
||||
@synthesize children;
|
||||
@synthesize icon;
|
||||
|
||||
+ (id)headerWithTitle:(NSString *)aTitle;
|
||||
{
|
||||
id newObject = [[self alloc] initWithTitle:aTitle url:nil icon:nil isHeader:YES];
|
||||
[newObject autorelease];
|
||||
return newObject;
|
||||
}
|
||||
|
||||
+ (id)entryWithTitle:(NSString *)aTitle url:(NSURL *)aURL icon:(id)anIcon
|
||||
{
|
||||
id newObject = [[self alloc] initWithTitle:aTitle url:aURL icon:anIcon isHeader:NO];
|
||||
[newObject autorelease];
|
||||
return newObject;
|
||||
}
|
||||
|
||||
+ (id)entryWithMod:(Mod *)baseMod allMods:(NSDictionary *)allMods baseURL:(NSURL *)baseURL
|
||||
{
|
||||
// TODO: Get the mod icon from the Mod
|
||||
// Temporary hack until mods define an icon
|
||||
NSString* imageName = [[NSBundle mainBundle] pathForResource:@"OpenRA" ofType:@"icns"];
|
||||
id icon = [[[NSImage alloc] initWithContentsOfFile:imageName] autorelease];
|
||||
id path = [[[baseURL absoluteString] stringByAppendingPathComponent:[baseMod mod]] stringByAppendingPathComponent:@"mod.html"];
|
||||
id ret = [SidebarEntry entryWithTitle:[baseMod title] url:[NSURL URLWithString:path] icon:icon];
|
||||
|
||||
for (id key in allMods)
|
||||
{
|
||||
id aMod = [allMods objectForKey:key];
|
||||
if (![[aMod requires] isEqualToString:[baseMod mod]])
|
||||
continue;
|
||||
|
||||
id child = [SidebarEntry entryWithMod:aMod allMods:allMods baseURL:baseURL];
|
||||
[ret addChild:child];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (id)initWithTitle:(NSString *)aTitle url:(NSURL *)aURL icon:(id)anIcon isHeader:(BOOL)isaHeader
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
isHeader = isaHeader;
|
||||
title = [aTitle retain];
|
||||
url = [aURL retain];
|
||||
icon = [anIcon retain];
|
||||
children = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addChild:(Mod *)child
|
||||
{
|
||||
[children addObject:child];
|
||||
}
|
||||
|
||||
- (NSURL *)url
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[title release]; title = nil;
|
||||
[url release]; url = nil;
|
||||
[icon release]; icon = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>OpenRA Launcher</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>OpenRA</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>OpenRA.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.open-ra.launcher</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>OpenRA Launcher</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.5</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
OpenRA.Launcher.Mac/build/Release/OpenRA.app/Contents/MacOS/OpenRA
Executable file
BIN
OpenRA.Launcher.Mac/build/Release/OpenRA.app/Contents/MacOS/OpenRA
Executable file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
APPL????
|
||||
Binary file not shown.
BIN
OpenRA.Launcher.Mac/build/Release/OpenRA.app/Contents/Resources/English.lproj/MainMenu.nib
generated
Normal file
BIN
OpenRA.Launcher.Mac/build/Release/OpenRA.app/Contents/Resources/English.lproj/MainMenu.nib
generated
Normal file
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
# This file is part of OpenRA, which is free software. It is made
|
||||
# available to you under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation. For more information,
|
||||
# see LICENSE.
|
||||
|
||||
export DYLD_LIBRARY_PATH="$1:$DYLD_LIBRARY_PATH"
|
||||
echo "Launching OpenRA from $1"
|
||||
cd $1
|
||||
mono --debug OpenRA.Game.exe SupportDir=~/Library/"Application Support"/OpenRA ${@:2}
|
||||
@@ -0,0 +1 @@
|
||||
../../../OpenRA.icns
|
||||
BIN
OpenRA.Launcher.Mac/build/Release/OpenRA.app/Contents/Resources/SDL
Executable file
BIN
OpenRA.Launcher.Mac/build/Release/OpenRA.app/Contents/Resources/SDL
Executable file
Binary file not shown.
14
OpenRA.Launcher.Mac/main.m
Normal file
14
OpenRA.Launcher.Mac/main.m
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// main.m
|
||||
// OpenRA
|
||||
//
|
||||
// Created by Paul Chote on 15/11/10.
|
||||
// Copyright 2010 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, (const char **) argv);
|
||||
}
|
||||
233
OpenRA.Launcher/ConfigureModsDialog.Designer.cs
generated
233
OpenRA.Launcher/ConfigureModsDialog.Designer.cs
generated
@@ -1,233 +0,0 @@
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
partial class ConfigureModsDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.installButton = new System.Windows.Forms.Button();
|
||||
this.installModDialog = new System.Windows.Forms.OpenFileDialog();
|
||||
this.treeView1 = new System.Windows.Forms.TreeView();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.addButton = new System.Windows.Forms.Button();
|
||||
this.removeButton = new System.Windows.Forms.Button();
|
||||
this.listView1 = new System.Windows.Forms.ListView();
|
||||
this.columnHeader1 = new System.Windows.Forms.ColumnHeader();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(446, 477);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 0;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.okButton.Location = new System.Drawing.Point(365, 477);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.okButton.TabIndex = 1;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// installButton
|
||||
//
|
||||
this.installButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.installButton.Location = new System.Drawing.Point(12, 477);
|
||||
this.installButton.Name = "installButton";
|
||||
this.installButton.Size = new System.Drawing.Size(116, 23);
|
||||
this.installButton.TabIndex = 2;
|
||||
this.installButton.Text = "Install Mod...";
|
||||
this.installButton.UseVisualStyleBackColor = true;
|
||||
this.installButton.Click += new System.EventHandler(this.InstallMod);
|
||||
//
|
||||
// installModDialog
|
||||
//
|
||||
this.installModDialog.Filter = "Zip files|*.zip";
|
||||
this.installModDialog.RestoreDirectory = true;
|
||||
//
|
||||
// treeView1
|
||||
//
|
||||
this.treeView1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.treeView1.Location = new System.Drawing.Point(3, 23);
|
||||
this.treeView1.Name = "treeView1";
|
||||
this.tableLayoutPanel1.SetRowSpan(this.treeView1, 2);
|
||||
this.treeView1.Size = new System.Drawing.Size(233, 212);
|
||||
this.treeView1.TabIndex = 3;
|
||||
this.treeView1.Enter += new System.EventHandler(this.treeView1_Enter);
|
||||
this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.TreeViewSelect);
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.tableLayoutPanel1.ColumnCount = 3;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 30F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.treeView1, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.addButton, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.removeButton, 2, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.listView1, 2, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.propertyGrid1, 0, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label2, 2, 0);
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 12);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 4;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(509, 459);
|
||||
this.tableLayoutPanel1.TabIndex = 4;
|
||||
//
|
||||
// addButton
|
||||
//
|
||||
this.addButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
|
||||
this.addButton.Location = new System.Drawing.Point(242, 103);
|
||||
this.addButton.Name = "addButton";
|
||||
this.addButton.Size = new System.Drawing.Size(24, 23);
|
||||
this.addButton.TabIndex = 5;
|
||||
this.addButton.Text = "+";
|
||||
this.addButton.UseVisualStyleBackColor = true;
|
||||
this.addButton.Click += new System.EventHandler(this.ActivateMod);
|
||||
//
|
||||
// removeButton
|
||||
//
|
||||
this.removeButton.Anchor = System.Windows.Forms.AnchorStyles.Top;
|
||||
this.removeButton.Location = new System.Drawing.Point(242, 132);
|
||||
this.removeButton.Name = "removeButton";
|
||||
this.removeButton.Size = new System.Drawing.Size(24, 23);
|
||||
this.removeButton.TabIndex = 6;
|
||||
this.removeButton.Text = "-";
|
||||
this.removeButton.UseVisualStyleBackColor = true;
|
||||
this.removeButton.Click += new System.EventHandler(this.DeactivateMod);
|
||||
//
|
||||
// listView1
|
||||
//
|
||||
this.listView1.Activation = System.Windows.Forms.ItemActivation.OneClick;
|
||||
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.columnHeader1});
|
||||
this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.listView1.FullRowSelect = true;
|
||||
this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
|
||||
this.listView1.Location = new System.Drawing.Point(272, 23);
|
||||
this.listView1.MultiSelect = false;
|
||||
this.listView1.Name = "listView1";
|
||||
this.tableLayoutPanel1.SetRowSpan(this.listView1, 2);
|
||||
this.listView1.Size = new System.Drawing.Size(234, 212);
|
||||
this.listView1.TabIndex = 8;
|
||||
this.listView1.TileSize = new System.Drawing.Size(10, 10);
|
||||
this.listView1.UseCompatibleStateImageBehavior = false;
|
||||
this.listView1.View = System.Windows.Forms.View.Details;
|
||||
this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListViewSelect);
|
||||
this.listView1.Enter += new System.EventHandler(this.ListViewSelect);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Anchor = System.Windows.Forms.AnchorStyles.None;
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(96, 3);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(47, 13);
|
||||
this.label1.TabIndex = 10;
|
||||
this.label1.Text = "All Mods";
|
||||
//
|
||||
// propertyGrid1
|
||||
//
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.propertyGrid1, 3);
|
||||
this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.propertyGrid1.Location = new System.Drawing.Point(3, 241);
|
||||
this.propertyGrid1.Name = "propertyGrid1";
|
||||
this.propertyGrid1.PropertySort = System.Windows.Forms.PropertySort.NoSort;
|
||||
this.propertyGrid1.Size = new System.Drawing.Size(503, 215);
|
||||
this.propertyGrid1.TabIndex = 9;
|
||||
this.propertyGrid1.ToolbarVisible = false;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.Anchor = System.Windows.Forms.AnchorStyles.None;
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(356, 3);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(66, 13);
|
||||
this.label2.TabIndex = 11;
|
||||
this.label2.Text = "Active Mods";
|
||||
//
|
||||
// ConfigureModsDialog
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(533, 512);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Controls.Add(this.installButton);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "ConfigureModsDialog";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Configure Mods";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.Button installButton;
|
||||
private System.Windows.Forms.OpenFileDialog installModDialog;
|
||||
private System.Windows.Forms.TreeView treeView1;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Button addButton;
|
||||
private System.Windows.Forms.Button removeButton;
|
||||
private System.Windows.Forms.ListView listView1;
|
||||
private System.Windows.Forms.PropertyGrid propertyGrid1;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
}
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.IO.Pipes;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
public partial class ConfigureModsDialog : Form
|
||||
{
|
||||
List<string> activeMods;
|
||||
|
||||
public List<string> ActiveMods
|
||||
{
|
||||
get { return activeMods; }
|
||||
}
|
||||
|
||||
Dictionary<string, Mod> allMods;
|
||||
public ConfigureModsDialog(string[] activeMods)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Util.UacShield(installButton);
|
||||
|
||||
this.activeMods = new List<string>(activeMods);
|
||||
|
||||
listView1.Items.AddRange(activeMods.Select(x => new ListViewItem(x)).ToArray());
|
||||
|
||||
RefreshMods();
|
||||
}
|
||||
|
||||
Mod GetMetadata(string mod)
|
||||
{
|
||||
string responseString;
|
||||
using (var response = UtilityProgram.Call("-i", mod))
|
||||
{
|
||||
responseString = response.ReadToEnd();
|
||||
}
|
||||
|
||||
if (Util.IsError(ref responseString)) return null;
|
||||
string[] lines = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
lines[i] = lines[i].Trim('\r');
|
||||
|
||||
string title = "", version = "", author = "", description = "", requires = "";
|
||||
bool standalone = false;
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string s = line.Trim(' ', '\r', '\n');
|
||||
int i = s.IndexOf(':');
|
||||
if (i + 2 > s.Length) continue;
|
||||
string value = s.Substring(i + 2);
|
||||
switch (s.Substring(0, i))
|
||||
{
|
||||
case "Title":
|
||||
title = value;
|
||||
break;
|
||||
case "Version":
|
||||
version = value;
|
||||
break;
|
||||
case "Author":
|
||||
author = value;
|
||||
break;
|
||||
case "Description":
|
||||
description = value;
|
||||
break;
|
||||
case "Requires":
|
||||
requires = value;
|
||||
break;
|
||||
case "Standalone":
|
||||
standalone = bool.Parse(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Mod(title, version, author, description, requires, standalone);
|
||||
}
|
||||
|
||||
void RefreshMods()
|
||||
{
|
||||
string responseString;
|
||||
using (var response = UtilityProgram.Call("--list-mods"))
|
||||
{
|
||||
responseString = response.ReadToEnd();
|
||||
}
|
||||
|
||||
string[] mods;
|
||||
if (!Util.IsError(ref responseString))
|
||||
mods = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
else
|
||||
throw new Exception(string.Format("Could not list mods: {0}", responseString));
|
||||
|
||||
for (int i = 0; i < mods.Length; i++)
|
||||
mods[i] = mods[i].Trim('\r');
|
||||
|
||||
allMods = mods.ToDictionary(x => x, x => GetMetadata(x));
|
||||
|
||||
RefreshModTree(treeView1, allMods.Keys.ToArray());
|
||||
}
|
||||
|
||||
private void InstallMod(object sender, EventArgs e)
|
||||
{
|
||||
if (installModDialog.ShowDialog() != DialogResult.OK) return;
|
||||
var p = UtilityProgram.CallWithAdmin("--install-mod", installModDialog.FileName);
|
||||
var pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
|
||||
pipe.Connect();
|
||||
|
||||
p.WaitForExit();
|
||||
|
||||
using (var response = new StreamReader(pipe))
|
||||
{
|
||||
string s = response.ReadToEnd();
|
||||
}
|
||||
|
||||
RefreshMods();
|
||||
}
|
||||
|
||||
void RefreshModTree(TreeView treeView, string[] modList)
|
||||
{
|
||||
treeView.Nodes.Clear();
|
||||
Dictionary<string, TreeNode> nodes;
|
||||
nodes = modList.Where(x => allMods[x].Standalone).ToDictionary(x => x, x => new TreeNode(x));
|
||||
string[] rootMods = modList.Where(x => allMods[x].Standalone).ToArray();
|
||||
string[] remaining = modList.Except(nodes.Keys).ToArray();
|
||||
|
||||
while (remaining.Length > 0)
|
||||
{
|
||||
bool progress = false;
|
||||
List<string> toRemove = new List<string>();
|
||||
foreach (string s in remaining)
|
||||
{
|
||||
var n = new TreeNode(s);
|
||||
if (allMods[s].Requires == null) continue;
|
||||
if (!nodes.ContainsKey(allMods[s].Requires)) continue;
|
||||
nodes[allMods[s].Requires].Nodes.Add(n);
|
||||
nodes.Add(s, n);
|
||||
toRemove.Add(s);
|
||||
progress = true;
|
||||
}
|
||||
|
||||
if (!progress)
|
||||
break;
|
||||
remaining = remaining.Except(toRemove).ToArray();
|
||||
}
|
||||
|
||||
foreach (string s in rootMods)
|
||||
treeView.Nodes.Add(nodes[s]);
|
||||
|
||||
if (remaining.Length > 0)
|
||||
{
|
||||
var n = new TreeNode("<Unspecified Dependency>");
|
||||
n.ForeColor = SystemColors.GrayText;
|
||||
var m = new TreeNode("<Missing Dependency>");
|
||||
m.ForeColor = SystemColors.GrayText;
|
||||
|
||||
foreach (var s in remaining)
|
||||
{
|
||||
if (allMods[s].Requires == null)
|
||||
n.Nodes.Add(new TreeNode(s) { ForeColor = SystemColors.GrayText });
|
||||
else if (!nodes.ContainsKey(allMods[s].Requires))
|
||||
m.Nodes.Add(new TreeNode(s) { ForeColor = SystemColors.GrayText });
|
||||
}
|
||||
|
||||
treeView.Nodes.Add(n);
|
||||
treeView.Nodes.Add(m);
|
||||
}
|
||||
|
||||
treeView.Invalidate();
|
||||
}
|
||||
|
||||
void TreeViewSelect(object sender, TreeViewEventArgs e)
|
||||
{
|
||||
SelectMod(e.Node.Text);
|
||||
}
|
||||
|
||||
void ListViewSelect(object sender, EventArgs e)
|
||||
{
|
||||
if (listView1.SelectedItems.Count > 0)
|
||||
SelectMod(listView1.SelectedItems[0].Text);
|
||||
else
|
||||
SelectMod("");
|
||||
}
|
||||
|
||||
void treeView1_Enter(object sender, EventArgs e)
|
||||
{
|
||||
if (treeView1.SelectedNode != null)
|
||||
SelectMod(treeView1.SelectedNode.Text);
|
||||
else
|
||||
SelectMod("");
|
||||
}
|
||||
|
||||
void SelectMod(string mod)
|
||||
{
|
||||
if (!allMods.ContainsKey(mod))
|
||||
propertyGrid1.SelectedObject = null;
|
||||
else
|
||||
propertyGrid1.SelectedObject = allMods[mod];
|
||||
}
|
||||
|
||||
void ActivateMod(object sender, EventArgs e)
|
||||
{
|
||||
if (treeView1.SelectedNode == null) return;
|
||||
string mod = treeView1.SelectedNode.Text;
|
||||
if (!allMods.ContainsKey(mod)) return;
|
||||
if (activeMods.Contains(mod)) return;
|
||||
|
||||
Mod m = allMods[mod];
|
||||
Stack<string> toAdd = new Stack<string>();
|
||||
toAdd.Push(mod);
|
||||
while (!string.IsNullOrEmpty(m.Requires))
|
||||
{
|
||||
string r = m.Requires;
|
||||
if (!allMods.ContainsKey(r))
|
||||
{
|
||||
MessageBox.Show(string.Format("A requirement for the mod \"{0}\" is missing. Please install \"{1}\" or the game may not run properly.", mod, r));
|
||||
return;
|
||||
}
|
||||
if (!activeMods.Contains(r))
|
||||
toAdd.Push(r);
|
||||
mod = r;
|
||||
m = allMods[mod];
|
||||
}
|
||||
|
||||
while (toAdd.Count > 0)
|
||||
activeMods.Add(toAdd.Pop());
|
||||
|
||||
listView1.Items.Clear();
|
||||
listView1.Items.AddRange(activeMods.Select(x => new ListViewItem(x)).ToArray());
|
||||
}
|
||||
|
||||
void DeactivateMod(object sender, EventArgs e)
|
||||
{
|
||||
if (listView1.SelectedItems.Count < 1) return;
|
||||
string mod = listView1.SelectedItems[0].Text;
|
||||
List<string> toRemove = new List<string>();
|
||||
|
||||
Stack<string> nodes = new Stack<string>();
|
||||
nodes.Push(mod);
|
||||
string currentNode;
|
||||
while (nodes.Count > 0)
|
||||
{
|
||||
currentNode = nodes.Pop();
|
||||
toRemove.Add(currentNode);
|
||||
foreach (string n in activeMods.Where(x => allMods[x].Requires == currentNode))
|
||||
nodes.Push(n);
|
||||
}
|
||||
|
||||
listView1.SuspendLayout();
|
||||
foreach (string s in toRemove)
|
||||
{
|
||||
listView1.Items.Remove(listView1.Items.OfType<ListViewItem>().Where(x => x.Text == s).SingleOrDefault());
|
||||
activeMods.Remove(s);
|
||||
}
|
||||
listView1.ResumeLayout();
|
||||
}
|
||||
}
|
||||
|
||||
class Mod
|
||||
{
|
||||
public string Title { get; private set; }
|
||||
public string Version { get; private set; }
|
||||
public string Author { get; private set; }
|
||||
public string Description { get; private set; }
|
||||
public string Requires { get; private set; }
|
||||
public bool Standalone { get; private set; }
|
||||
|
||||
public Mod(string title, string version, string author, string description, string requires, bool standalone)
|
||||
{
|
||||
Title = title;
|
||||
Version = version;
|
||||
Author = author;
|
||||
Description = description;
|
||||
Requires = requires;
|
||||
Standalone = standalone;
|
||||
}
|
||||
}
|
||||
}
|
||||
220
OpenRA.Launcher/Download.cs
Normal file
220
OpenRA.Launcher/Download.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
using System.IO.Pipes;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
public enum DownloadStatus
|
||||
{
|
||||
NOT_REGISTERED, AVAILABLE, DOWNLOADING, DOWNLOADED, EXTRACTING, EXTRACTED, ERROR
|
||||
}
|
||||
|
||||
class Download : IDisposable
|
||||
{
|
||||
DownloadStatus status = DownloadStatus.NOT_REGISTERED;
|
||||
string url = "", target = "", key = "";
|
||||
BackgroundWorker downloadBGWorker, extractBGWorker;
|
||||
int bytesTotal = 0, bytesDone = 0;
|
||||
string errorMessage = "";
|
||||
HtmlDocument document;
|
||||
|
||||
public string ErrorMessage
|
||||
{
|
||||
get { return errorMessage; }
|
||||
}
|
||||
|
||||
public int BytesDone
|
||||
{
|
||||
get { return bytesDone; }
|
||||
}
|
||||
|
||||
public int BytesTotal
|
||||
{
|
||||
get { return bytesTotal; }
|
||||
}
|
||||
|
||||
public DownloadStatus Status
|
||||
{
|
||||
get { return status; }
|
||||
}
|
||||
|
||||
public Download(HtmlDocument document, string key, string url, string filename)
|
||||
{
|
||||
this.url = url;
|
||||
this.key = key;
|
||||
this.document = document;
|
||||
target = Path.Combine(Path.GetTempPath(), filename);
|
||||
if (File.Exists(target))
|
||||
status = DownloadStatus.DOWNLOADED;
|
||||
else
|
||||
status = DownloadStatus.AVAILABLE;
|
||||
|
||||
downloadBGWorker = new BackgroundWorker()
|
||||
{
|
||||
WorkerReportsProgress = true,
|
||||
WorkerSupportsCancellation = true
|
||||
};
|
||||
|
||||
downloadBGWorker.DoWork += RunDownload;
|
||||
downloadBGWorker.ProgressChanged += UpdateProgress;
|
||||
downloadBGWorker.RunWorkerCompleted += DownloadFinished;
|
||||
|
||||
extractBGWorker = new BackgroundWorker();
|
||||
|
||||
extractBGWorker.DoWork += DoExtraction;
|
||||
extractBGWorker.RunWorkerCompleted += ExtractionFinished;
|
||||
}
|
||||
|
||||
public void StartDownload()
|
||||
{
|
||||
if (!downloadBGWorker.IsBusy)
|
||||
{
|
||||
status = DownloadStatus.DOWNLOADING;
|
||||
downloadBGWorker.RunWorkerAsync(new string[] { url, target });
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelDownload()
|
||||
{
|
||||
if (downloadBGWorker.IsBusy)
|
||||
downloadBGWorker.CancelAsync();
|
||||
}
|
||||
|
||||
public void ExtractDownload(string destPath)
|
||||
{
|
||||
if (!extractBGWorker.IsBusy)
|
||||
{
|
||||
status = DownloadStatus.EXTRACTING;
|
||||
extractBGWorker.RunWorkerAsync(new string[] { target, destPath });
|
||||
}
|
||||
}
|
||||
|
||||
static void RunDownload(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
var bgWorker = sender as BackgroundWorker;
|
||||
string[] args = e.Argument as string[];
|
||||
string url = args[0];
|
||||
string dest = args[1];
|
||||
var p = UtilityProgram.Call("--download-url", url, dest);
|
||||
Regex r = new Regex(@"(\d{1,3})% (\d+)/(\d+) bytes");
|
||||
|
||||
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
|
||||
pipe.Connect();
|
||||
|
||||
using (var response = new StreamReader(pipe))
|
||||
{
|
||||
while (!p.HasExited)
|
||||
{
|
||||
string s = response.ReadLine();
|
||||
if (string.IsNullOrEmpty(s)) continue;
|
||||
if (Util.IsError(ref s))
|
||||
throw new Exception(s);
|
||||
|
||||
if (bgWorker.CancellationPending)
|
||||
{
|
||||
e.Cancel = true;
|
||||
p.Kill();
|
||||
return;
|
||||
}
|
||||
if (!r.IsMatch(s)) continue;
|
||||
var m = r.Match(s);
|
||||
bgWorker.ReportProgress(int.Parse(m.Groups[1].Value),
|
||||
new string[] { m.Groups[2].Value, m.Groups[3].Value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateProgress(object sender, ProgressChangedEventArgs e)
|
||||
{
|
||||
string[] s = e.UserState as string[];
|
||||
bytesDone = int.Parse(s[0]);
|
||||
bytesTotal = int.Parse(s[1]);
|
||||
document.InvokeScript("downloadProgressed", new object[] { key });
|
||||
}
|
||||
|
||||
void DownloadFinished(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (e.Error != null)
|
||||
{
|
||||
status = DownloadStatus.ERROR;
|
||||
errorMessage = e.Error.Message;
|
||||
//if (File.Exists(target))
|
||||
// File.Delete(target);
|
||||
document.InvokeScript("downloadProgressed", new object[] { key });
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Cancelled)
|
||||
{
|
||||
status = DownloadStatus.ERROR;
|
||||
errorMessage = "Download Cancelled";
|
||||
//if (File.Exists(target))
|
||||
// File.Delete(target);
|
||||
document.InvokeScript("downloadProgressed", new object[] { key });
|
||||
return;
|
||||
}
|
||||
|
||||
status = DownloadStatus.DOWNLOADED;
|
||||
document.InvokeScript("downloadProgressed", new object[] { key });
|
||||
}
|
||||
|
||||
void DoExtraction(object sender, DoWorkEventArgs e)
|
||||
{
|
||||
var bgWorker = sender as BackgroundWorker;
|
||||
string[] args = e.Argument as string[];
|
||||
string zipFile = args[0];
|
||||
string destPath = args[1];
|
||||
|
||||
var p = UtilityProgram.CallWithAdmin("--extract-zip", zipFile, destPath);
|
||||
var pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
|
||||
|
||||
pipe.Connect();
|
||||
|
||||
using (var reader = new StreamReader(pipe))
|
||||
{
|
||||
while (!p.HasExited)
|
||||
{
|
||||
string s = reader.ReadLine();
|
||||
if (string.IsNullOrEmpty(s)) continue;
|
||||
if (Util.IsError(ref s))
|
||||
throw new Exception(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractionFinished(object sender, RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (e.Error != null)
|
||||
{
|
||||
status = DownloadStatus.ERROR;
|
||||
errorMessage = e.Error.Message;
|
||||
document.InvokeScript("extractProgressed", new object[] { key });
|
||||
}
|
||||
|
||||
|
||||
status = DownloadStatus.EXTRACTED;
|
||||
document.InvokeScript("extractProgressed", new object[] { key });
|
||||
}
|
||||
|
||||
bool disposed = false;
|
||||
|
||||
~Download()
|
||||
{
|
||||
if (!disposed)
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (status == DownloadStatus.DOWNLOADING && File.Exists(target))
|
||||
File.Delete(target);
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
186
OpenRA.Launcher/InstallPackagesDialog.Designer.cs
generated
186
OpenRA.Launcher/InstallPackagesDialog.Designer.cs
generated
@@ -1,186 +0,0 @@
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
partial class InstallPackagesDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.button2 = new System.Windows.Forms.Button();
|
||||
this.radioButton1 = new System.Windows.Forms.RadioButton();
|
||||
this.radioButton2 = new System.Windows.Forms.RadioButton();
|
||||
this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog();
|
||||
this.radioPanel = new System.Windows.Forms.Panel();
|
||||
this.progressPanel = new System.Windows.Forms.Panel();
|
||||
this.progressBar1 = new System.Windows.Forms.ProgressBar();
|
||||
this.progressLabel = new System.Windows.Forms.Label();
|
||||
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
|
||||
this.radioPanel.SuspendLayout();
|
||||
this.progressPanel.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Location = new System.Drawing.Point(13, 13);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(280, 89);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "label1";
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(218, 163);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.cancelButton.TabIndex = 1;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// button2
|
||||
//
|
||||
this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.button2.Location = new System.Drawing.Point(109, 163);
|
||||
this.button2.Name = "button2";
|
||||
this.button2.Size = new System.Drawing.Size(103, 23);
|
||||
this.button2.TabIndex = 2;
|
||||
this.button2.Text = "Continue...";
|
||||
this.button2.UseVisualStyleBackColor = true;
|
||||
this.button2.Click += new System.EventHandler(this.button2_Click);
|
||||
//
|
||||
// radioButton1
|
||||
//
|
||||
this.radioButton1.AutoSize = true;
|
||||
this.radioButton1.Checked = true;
|
||||
this.radioButton1.Location = new System.Drawing.Point(3, 3);
|
||||
this.radioButton1.Name = "radioButton1";
|
||||
this.radioButton1.Size = new System.Drawing.Size(138, 17);
|
||||
this.radioButton1.TabIndex = 3;
|
||||
this.radioButton1.TabStop = true;
|
||||
this.radioButton1.Text = "Download From Internet";
|
||||
this.radioButton1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// radioButton2
|
||||
//
|
||||
this.radioButton2.AutoSize = true;
|
||||
this.radioButton2.Location = new System.Drawing.Point(3, 26);
|
||||
this.radioButton2.Name = "radioButton2";
|
||||
this.radioButton2.Size = new System.Drawing.Size(96, 17);
|
||||
this.radioButton2.TabIndex = 4;
|
||||
this.radioButton2.TabStop = true;
|
||||
this.radioButton2.Text = "Install From CD";
|
||||
this.radioButton2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// folderBrowserDialog1
|
||||
//
|
||||
this.folderBrowserDialog1.RootFolder = System.Environment.SpecialFolder.MyComputer;
|
||||
this.folderBrowserDialog1.ShowNewFolderButton = false;
|
||||
//
|
||||
// radioPanel
|
||||
//
|
||||
this.radioPanel.Controls.Add(this.radioButton1);
|
||||
this.radioPanel.Controls.Add(this.radioButton2);
|
||||
this.radioPanel.Location = new System.Drawing.Point(12, 105);
|
||||
this.radioPanel.Name = "radioPanel";
|
||||
this.radioPanel.Size = new System.Drawing.Size(281, 52);
|
||||
this.radioPanel.TabIndex = 5;
|
||||
//
|
||||
// progressPanel
|
||||
//
|
||||
this.progressPanel.Controls.Add(this.progressLabel);
|
||||
this.progressPanel.Controls.Add(this.progressBar1);
|
||||
this.progressPanel.Location = new System.Drawing.Point(12, 105);
|
||||
this.progressPanel.Name = "progressPanel";
|
||||
this.progressPanel.Size = new System.Drawing.Size(281, 52);
|
||||
this.progressPanel.TabIndex = 6;
|
||||
this.progressPanel.Visible = false;
|
||||
//
|
||||
// progressBar1
|
||||
//
|
||||
this.progressBar1.Location = new System.Drawing.Point(3, 3);
|
||||
this.progressBar1.Name = "progressBar1";
|
||||
this.progressBar1.Size = new System.Drawing.Size(275, 23);
|
||||
this.progressBar1.TabIndex = 0;
|
||||
//
|
||||
// progressLabel
|
||||
//
|
||||
this.progressLabel.AutoSize = true;
|
||||
this.progressLabel.Location = new System.Drawing.Point(3, 29);
|
||||
this.progressLabel.Name = "progressLabel";
|
||||
this.progressLabel.Size = new System.Drawing.Size(0, 13);
|
||||
this.progressLabel.TabIndex = 1;
|
||||
//
|
||||
// backgroundWorker1
|
||||
//
|
||||
this.backgroundWorker1.WorkerReportsProgress = true;
|
||||
this.backgroundWorker1.WorkerSupportsCancellation = true;
|
||||
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
|
||||
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
|
||||
this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
|
||||
//
|
||||
// InstallPackagesDialog
|
||||
//
|
||||
this.AcceptButton = this.button2;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(305, 198);
|
||||
this.Controls.Add(this.progressPanel);
|
||||
this.Controls.Add(this.radioPanel);
|
||||
this.Controls.Add(this.button2);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.Controls.Add(this.label1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "InstallPackagesDialog";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Install Mod Files";
|
||||
this.radioPanel.ResumeLayout(false);
|
||||
this.radioPanel.PerformLayout();
|
||||
this.progressPanel.ResumeLayout(false);
|
||||
this.progressPanel.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Button button2;
|
||||
private System.Windows.Forms.RadioButton radioButton1;
|
||||
private System.Windows.Forms.RadioButton radioButton2;
|
||||
private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1;
|
||||
private System.Windows.Forms.Panel radioPanel;
|
||||
private System.Windows.Forms.Panel progressPanel;
|
||||
private System.Windows.Forms.Label progressLabel;
|
||||
private System.Windows.Forms.ProgressBar progressBar1;
|
||||
private System.ComponentModel.BackgroundWorker backgroundWorker1;
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO.Pipes;
|
||||
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
public partial class InstallPackagesDialog : Form
|
||||
{
|
||||
string mod;
|
||||
public InstallPackagesDialog(string mod)
|
||||
{
|
||||
InitializeComponent();
|
||||
Util.UacShield(button2);
|
||||
this.mod = mod;
|
||||
if (mod == "cnc") radioButton2.Enabled = false;
|
||||
label1.Text = string.Format("In order to play OpenRA with the mod \"{0}\", you must install the original game files. " +
|
||||
"These can either be downloaded or for some mods be installed from a CD copy of the original game. " +
|
||||
"Please select your choice below and click continue", mod);
|
||||
}
|
||||
|
||||
private void button2_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (radioButton1.Checked)
|
||||
{
|
||||
radioPanel.Visible = false;
|
||||
progressPanel.Visible = true;
|
||||
button2.Enabled = false;
|
||||
cancelButton.Enabled = false;
|
||||
backgroundWorker1.RunWorkerAsync();
|
||||
}
|
||||
|
||||
if (radioButton2.Checked && folderBrowserDialog1.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
var p = UtilityProgram.CallWithAdmin(string.Format("--install-{0}-packages", mod),
|
||||
folderBrowserDialog1.SelectedPath + Path.DirectorySeparatorChar);
|
||||
|
||||
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
|
||||
pipe.Connect();
|
||||
|
||||
p.WaitForExit();
|
||||
|
||||
using (var response = new StreamReader(pipe))
|
||||
{
|
||||
string s = response.ReadToEnd();
|
||||
if (Util.IsError(ref s))
|
||||
DialogResult = DialogResult.No;
|
||||
else
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
|
||||
{
|
||||
var p = UtilityProgram.CallWithAdmin("--download-packages", mod);
|
||||
Regex r = new Regex(@"(\d{1,3})% (\d+/\d+ bytes)");
|
||||
|
||||
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
|
||||
pipe.Connect();
|
||||
|
||||
using (var response = new StreamReader(pipe))
|
||||
{
|
||||
while (!p.HasExited)
|
||||
{
|
||||
string s = response.ReadLine();
|
||||
if (Util.IsError(ref s))
|
||||
{
|
||||
e.Cancel = true;
|
||||
e.Result = s;
|
||||
return;
|
||||
}
|
||||
if (!r.IsMatch(s)) continue;
|
||||
var m = r.Match(s);
|
||||
backgroundWorker1.ReportProgress(int.Parse(m.Groups[1].Value), m.Groups[2].Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
|
||||
{
|
||||
progressBar1.Value = e.ProgressPercentage;
|
||||
progressLabel.Text = (string)e.UserState;
|
||||
}
|
||||
|
||||
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
|
||||
{
|
||||
if (e.Cancelled)
|
||||
{
|
||||
MessageBox.Show((string)e.Result);
|
||||
DialogResult = DialogResult.No;
|
||||
}
|
||||
else
|
||||
DialogResult = DialogResult.OK;
|
||||
progressPanel.Visible = false;
|
||||
radioPanel.Visible = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="folderBrowserDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="backgroundWorker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>186, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
152
OpenRA.Launcher/JSBridge.cs
Normal file
152
OpenRA.Launcher/JSBridge.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
public class JSBridge
|
||||
{
|
||||
Dictionary<string, Mod> allMods = new Dictionary<string,Mod>();
|
||||
|
||||
public Dictionary<string, Mod> AllMods
|
||||
{
|
||||
get { return allMods; }
|
||||
set { allMods = value; }
|
||||
}
|
||||
Dictionary<string, Download> downloads = new Dictionary<string,Download>();
|
||||
|
||||
HtmlDocument document = null;
|
||||
|
||||
public HtmlDocument Document
|
||||
{
|
||||
get { return document; }
|
||||
set { document = value; }
|
||||
}
|
||||
|
||||
public bool existsInMod(string file, string mod)
|
||||
{
|
||||
string cleanedPath = CleanPath(file);
|
||||
return File.Exists(string.Format("mods{0}{1}{0}{2}", Path.DirectorySeparatorChar, mod, cleanedPath));
|
||||
}
|
||||
|
||||
public void log(string message)
|
||||
{
|
||||
Console.WriteLine("js: " + message);
|
||||
}
|
||||
|
||||
public bool launchMod(string mod)
|
||||
{
|
||||
string m = mod;
|
||||
List<string> modList = new List<string>();
|
||||
modList.Add(m);
|
||||
if (!allMods.ContainsKey(m))
|
||||
{
|
||||
System.Windows.Forms.MessageBox.Show("allMods does not contain " + m);
|
||||
return false;
|
||||
}
|
||||
while (!string.IsNullOrEmpty(allMods[m].Requires))
|
||||
{
|
||||
m = allMods[m].Requires;
|
||||
modList.Add(m);
|
||||
}
|
||||
|
||||
Process p = new Process();
|
||||
p.StartInfo.FileName = "OpenRA.Game.exe";
|
||||
p.StartInfo.Arguments = "Game.Mods=" + string.Join(",", modList.ToArray());
|
||||
p.StartInfo.Arguments += " Graphics.Renderer=" + Launcher.Renderer;
|
||||
p.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
Regex p = new Regex(@"\.\.[/\\]?");
|
||||
string CleanPath(string path)
|
||||
{
|
||||
string root = Path.GetPathRoot(path);
|
||||
string cleanedPath = path.Remove(0, root.Length);
|
||||
return p.Replace(cleanedPath, "");
|
||||
}
|
||||
|
||||
public void registerDownload(string key, string url, string filename)
|
||||
{
|
||||
string cleanedPath = CleanPath(filename);
|
||||
if (!downloads.ContainsKey(key))
|
||||
downloads.Add(key, new Download(document, key, url, cleanedPath));
|
||||
else
|
||||
downloads[key] = new Download(document, key, url, cleanedPath);
|
||||
}
|
||||
|
||||
public bool startDownload(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return false;
|
||||
|
||||
downloads[key].StartDownload();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool cancelDownload(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return false;
|
||||
|
||||
downloads[key].CancelDownload();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string downloadStatus(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return DownloadStatus.NOT_REGISTERED.ToString();
|
||||
|
||||
return downloads[key].Status.ToString();
|
||||
}
|
||||
|
||||
public string downloadError(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return "";
|
||||
|
||||
return downloads[key].ErrorMessage;
|
||||
}
|
||||
|
||||
public int bytesCompleted(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return -1;
|
||||
|
||||
return downloads[key].BytesDone;
|
||||
}
|
||||
|
||||
public int bytesTotal(string key)
|
||||
{
|
||||
if (!downloads.ContainsKey(key))
|
||||
return -1;
|
||||
|
||||
return downloads[key].BytesTotal;
|
||||
}
|
||||
|
||||
public bool extractDownload(string key, string targetDir, string mod)
|
||||
{
|
||||
string cleanedPath = CleanPath(targetDir);
|
||||
|
||||
string targetPath = Path.Combine(mod, cleanedPath);
|
||||
|
||||
if (!downloads.ContainsKey(key))
|
||||
return false;
|
||||
|
||||
if (downloads[key].Status != DownloadStatus.DOWNLOADED)
|
||||
return false;
|
||||
|
||||
downloads[key].ExtractDownload(targetPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
174
OpenRA.Launcher/Launcher.Designer.cs
generated
Normal file
174
OpenRA.Launcher/Launcher.Designer.cs
generated
Normal file
@@ -0,0 +1,174 @@
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
partial class Launcher
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Mods", -2, -2);
|
||||
this.installButton = new System.Windows.Forms.Button();
|
||||
this.installModDialog = new System.Windows.Forms.OpenFileDialog();
|
||||
this.treeView = new System.Windows.Forms.TreeView();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.webBrowser = new System.Windows.Forms.WebBrowser();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.cgButton = new System.Windows.Forms.RadioButton();
|
||||
this.glButton = new System.Windows.Forms.RadioButton();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// installButton
|
||||
//
|
||||
this.installButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.installButton.Location = new System.Drawing.Point(12, 12);
|
||||
this.installButton.Name = "installButton";
|
||||
this.installButton.Size = new System.Drawing.Size(116, 23);
|
||||
this.installButton.TabIndex = 2;
|
||||
this.installButton.Text = "Install Mod...";
|
||||
this.installButton.UseVisualStyleBackColor = true;
|
||||
this.installButton.Click += new System.EventHandler(this.InstallMod);
|
||||
//
|
||||
// installModDialog
|
||||
//
|
||||
this.installModDialog.Filter = "Zip files|*.zip";
|
||||
this.installModDialog.RestoreDirectory = true;
|
||||
//
|
||||
// treeView
|
||||
//
|
||||
this.treeView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.treeView.Location = new System.Drawing.Point(0, 0);
|
||||
this.treeView.Name = "treeView";
|
||||
treeNode1.ImageIndex = -2;
|
||||
treeNode1.Name = "ModsNode";
|
||||
treeNode1.SelectedImageIndex = -2;
|
||||
treeNode1.Text = "Mods";
|
||||
this.treeView.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
|
||||
treeNode1});
|
||||
this.treeView.ShowLines = false;
|
||||
this.treeView.Size = new System.Drawing.Size(160, 465);
|
||||
this.treeView.TabIndex = 3;
|
||||
this.treeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView_AfterSelect);
|
||||
//
|
||||
// splitContainer1
|
||||
//
|
||||
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
|
||||
this.splitContainer1.Name = "splitContainer1";
|
||||
//
|
||||
// splitContainer1.Panel1
|
||||
//
|
||||
this.splitContainer1.Panel1.Controls.Add(this.treeView);
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.webBrowser);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(671, 465);
|
||||
this.splitContainer1.SplitterDistance = 160;
|
||||
this.splitContainer1.TabIndex = 4;
|
||||
//
|
||||
// webBrowser
|
||||
//
|
||||
this.webBrowser.AllowWebBrowserDrop = false;
|
||||
this.webBrowser.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.webBrowser.Location = new System.Drawing.Point(0, 0);
|
||||
this.webBrowser.MinimumSize = new System.Drawing.Size(20, 20);
|
||||
this.webBrowser.Name = "webBrowser";
|
||||
this.webBrowser.ScrollBarsEnabled = false;
|
||||
this.webBrowser.Size = new System.Drawing.Size(507, 465);
|
||||
this.webBrowser.TabIndex = 0;
|
||||
//
|
||||
// panel1
|
||||
//
|
||||
this.panel1.Controls.Add(this.cgButton);
|
||||
this.panel1.Controls.Add(this.glButton);
|
||||
this.panel1.Controls.Add(this.installButton);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.panel1.Location = new System.Drawing.Point(0, 465);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(671, 47);
|
||||
this.panel1.TabIndex = 5;
|
||||
//
|
||||
// cgButton
|
||||
//
|
||||
this.cgButton.AutoSize = true;
|
||||
this.cgButton.Location = new System.Drawing.Point(481, 18);
|
||||
this.cgButton.Name = "cgButton";
|
||||
this.cgButton.Size = new System.Drawing.Size(87, 17);
|
||||
this.cgButton.TabIndex = 4;
|
||||
this.cgButton.TabStop = true;
|
||||
this.cgButton.Text = "CG Renderer";
|
||||
this.cgButton.UseVisualStyleBackColor = true;
|
||||
this.cgButton.CheckedChanged += new System.EventHandler(this.rendererChanged);
|
||||
//
|
||||
// glButton
|
||||
//
|
||||
this.glButton.AutoSize = true;
|
||||
this.glButton.Location = new System.Drawing.Point(574, 18);
|
||||
this.glButton.Name = "glButton";
|
||||
this.glButton.Size = new System.Drawing.Size(86, 17);
|
||||
this.glButton.TabIndex = 3;
|
||||
this.glButton.TabStop = true;
|
||||
this.glButton.Text = "GL Renderer";
|
||||
this.glButton.UseVisualStyleBackColor = true;
|
||||
this.glButton.CheckedChanged += new System.EventHandler(this.rendererChanged);
|
||||
//
|
||||
// Launcher
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(671, 512);
|
||||
this.Controls.Add(this.splitContainer1);
|
||||
this.Controls.Add(this.panel1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "Launcher";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "OpenRA Launcher";
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button installButton;
|
||||
private System.Windows.Forms.OpenFileDialog installModDialog;
|
||||
private System.Windows.Forms.TreeView treeView;
|
||||
private System.Windows.Forms.SplitContainer splitContainer1;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.WebBrowser webBrowser;
|
||||
private System.Windows.Forms.RadioButton cgButton;
|
||||
private System.Windows.Forms.RadioButton glButton;
|
||||
}
|
||||
}
|
||||
203
OpenRA.Launcher/Launcher.cs
Normal file
203
OpenRA.Launcher/Launcher.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.IO.Pipes;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Launcher
|
||||
{
|
||||
public partial class Launcher : Form
|
||||
{
|
||||
Dictionary<string, Mod> allMods;
|
||||
public static string Renderer = "Gl";
|
||||
static string SupportDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + Path.DirectorySeparatorChar + "OpenRA";
|
||||
|
||||
public Launcher()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Util.UacShield(installButton);
|
||||
|
||||
webBrowser.ObjectForScripting = new JSBridge();
|
||||
webBrowser.DocumentCompleted += (o, e) =>
|
||||
{
|
||||
var b = o as WebBrowser;
|
||||
(b.ObjectForScripting as JSBridge).Document = b.Document;
|
||||
};
|
||||
RefreshMods();
|
||||
string response = UtilityProgram.CallSimpleResponse("--settings-value", SupportDir, "Graphics.Renderer");
|
||||
if (Util.IsError(ref response) || response.Equals("gl", StringComparison.InvariantCultureIgnoreCase))
|
||||
glButton.Checked = true;
|
||||
else
|
||||
cgButton.Checked = true;
|
||||
}
|
||||
|
||||
Mod GetMetadata(string mod)
|
||||
{
|
||||
string responseString = UtilityProgram.CallSimpleResponse("-i", mod);
|
||||
|
||||
if (Util.IsError(ref responseString)) return null;
|
||||
string[] lines = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
lines[i] = lines[i].Trim('\r');
|
||||
|
||||
string title = "", version = "", author = "", description = "", requires = "";
|
||||
bool standalone = false;
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string s = line.Trim(' ', '\r', '\n');
|
||||
int i = s.IndexOf(':');
|
||||
if (i + 2 > s.Length) continue;
|
||||
string value = s.Substring(i + 2);
|
||||
switch (s.Substring(0, i))
|
||||
{
|
||||
case "Title":
|
||||
title = value;
|
||||
break;
|
||||
case "Version":
|
||||
version = value;
|
||||
break;
|
||||
case "Author":
|
||||
author = value;
|
||||
break;
|
||||
case "Description":
|
||||
description = value;
|
||||
break;
|
||||
case "Requires":
|
||||
requires = value;
|
||||
break;
|
||||
case "Standalone":
|
||||
standalone = bool.Parse(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Mod(title, version, author, description, requires, standalone);
|
||||
}
|
||||
|
||||
void RefreshMods()
|
||||
{
|
||||
string responseString = UtilityProgram.CallSimpleResponse("--list-mods");
|
||||
|
||||
string[] mods;
|
||||
if (!Util.IsError(ref responseString))
|
||||
mods = responseString.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
else
|
||||
throw new Exception(string.Format("Could not list mods: {0}", responseString));
|
||||
|
||||
for (int i = 0; i < mods.Length; i++)
|
||||
mods[i] = mods[i].Trim('\r');
|
||||
|
||||
allMods = mods.ToDictionary(x => x, x => GetMetadata(x));
|
||||
|
||||
(webBrowser.ObjectForScripting as JSBridge).AllMods = allMods;
|
||||
|
||||
RefreshModTree(treeView, allMods.Keys.ToArray());
|
||||
}
|
||||
|
||||
private void InstallMod(object sender, EventArgs e)
|
||||
{
|
||||
if (installModDialog.ShowDialog() != DialogResult.OK) return;
|
||||
var p = UtilityProgram.CallWithAdmin("--extract-zip", installModDialog.FileName, "");
|
||||
var pipe = new NamedPipeClientStream(".", "OpenRA.Utility", PipeDirection.In);
|
||||
pipe.Connect();
|
||||
|
||||
p.WaitForExit();
|
||||
|
||||
using (var response = new StreamReader(pipe))
|
||||
{
|
||||
string s = response.ReadToEnd();
|
||||
}
|
||||
|
||||
RefreshMods();
|
||||
}
|
||||
|
||||
void RefreshModTree(TreeView treeView, string[] modList)
|
||||
{
|
||||
treeView.Nodes["ModsNode"].Nodes.Clear();
|
||||
Dictionary<string, TreeNode> nodes;
|
||||
nodes = modList.Where(x => allMods[x].Standalone).ToDictionary(x => x,
|
||||
x => new TreeNode(allMods[x].Title) { Name = x });
|
||||
string[] rootMods = modList.Where(x => allMods[x].Standalone).ToArray();
|
||||
Stack<string> remaining = new Stack<string>(modList.Except(nodes.Keys));
|
||||
|
||||
bool progress = true;
|
||||
while (remaining.Count > 0 && progress)
|
||||
{
|
||||
progress = false;
|
||||
string s = remaining.Pop();
|
||||
var n = new TreeNode(allMods[s].Title) { Name = s };
|
||||
if (allMods[s].Requires == null) { remaining.Push(s); continue; }
|
||||
if (!nodes.ContainsKey(allMods[s].Requires)) { remaining.Push(s); continue; }
|
||||
nodes[allMods[s].Requires].Nodes.Add(n);
|
||||
nodes.Add(s, n);
|
||||
progress = true;
|
||||
}
|
||||
|
||||
foreach (string s in rootMods)
|
||||
treeView.Nodes["ModsNode"].Nodes.Add(nodes[s]);
|
||||
|
||||
if (remaining.Count > 0)
|
||||
{
|
||||
var unspecified = new TreeNode("<Unspecified Dependency>") { ForeColor = SystemColors.GrayText };
|
||||
var missing = new TreeNode("<Missing Dependency>") { ForeColor = SystemColors.GrayText };
|
||||
|
||||
foreach (var s in remaining)
|
||||
{
|
||||
if (allMods[s].Requires == null)
|
||||
unspecified.Nodes.Add(new TreeNode(allMods[s].Title)
|
||||
{ ForeColor = SystemColors.GrayText, Name = s });
|
||||
else if (!nodes.ContainsKey(allMods[s].Requires))
|
||||
missing.Nodes.Add(new TreeNode(allMods[s].Title)
|
||||
{ ForeColor = SystemColors.GrayText, Name = s });
|
||||
}
|
||||
string brokenKey = "BrokenModsNode";
|
||||
if (treeView.Nodes[brokenKey] != null)
|
||||
treeView.Nodes.RemoveByKey(brokenKey);
|
||||
treeView.Nodes.Add(brokenKey, "Broken Mods");
|
||||
treeView.Nodes[brokenKey].Nodes.Add(unspecified);
|
||||
treeView.Nodes[brokenKey].Nodes.Add(missing);
|
||||
}
|
||||
treeView.Nodes["ModsNode"].ExpandAll();
|
||||
treeView.Invalidate();
|
||||
|
||||
string responseString = UtilityProgram.CallSimpleResponse("--settings-value", SupportDir, "Game.Mods");
|
||||
|
||||
if (Util.IsError(ref responseString))
|
||||
treeView.SelectedNode = treeView.Nodes["ModsNode"].Nodes["ra"];
|
||||
else
|
||||
treeView.SelectedNode = treeView.Nodes["ModsNode"].Nodes[responseString];
|
||||
}
|
||||
|
||||
void treeView_AfterSelect(object sender, TreeViewEventArgs e)
|
||||
{
|
||||
Mod selectedMod;
|
||||
if (!allMods.TryGetValue(e.Node.Name, out selectedMod)) return;
|
||||
string modHtmlPath = string.Format("mods{0}{1}{0}mod.html", Path.DirectorySeparatorChar, e.Node.Name);
|
||||
if (!File.Exists(modHtmlPath)) return;
|
||||
webBrowser.Navigate(Path.GetFullPath(modHtmlPath));
|
||||
}
|
||||
|
||||
private void rendererChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (sender == glButton)
|
||||
Renderer = "Gl";
|
||||
else
|
||||
Renderer = "Cg";
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user