Merge branch 'master' into pr-downloader

This commit is contained in:
oy 2018-12-30 17:48:36 +01:00 committed by GitHub
commit a86c661651
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
280 changed files with 17299 additions and 9099 deletions

19
.circleci/config.yml Normal file
View file

@ -0,0 +1,19 @@
version: 2
jobs:
build:
docker:
- image: buildpack-deps:stretch
steps:
- checkout
- run:
name: Build bam
command: |
apt-get update -y
apt-get install libsdl2-dev libfreetype6-dev -y
git clone https://github.com/matricks/bam.git ~/bam
cd ~/bam/
git reset --hard f012dd9a3e38295b8a45af5a101d29573381f169
./make_unix.sh
- run:
name: Build teeworlds
command: ~/bam/bam conf=release all

3
.gitignore vendored
View file

@ -2,6 +2,8 @@
/.bam /.bam
/config.lua /config.lua
/build /build
/other/*/lib
/other/*/include
__pycache__/ __pycache__/
*.pyc *.pyc
*.pyo *.pyo
@ -11,3 +13,4 @@ scripts/work/
/autoexec.cfg /autoexec.cfg
other/freetype other/freetype
other/sdl other/sdl
_test.exe

2
.gitmodules vendored
View file

@ -1,6 +1,8 @@
[submodule "datasrc/languages"] [submodule "datasrc/languages"]
path = datasrc/languages path = datasrc/languages
url = git://github.com/teeworlds/teeworlds-translation.git url = git://github.com/teeworlds/teeworlds-translation.git
branch = master
[submodule "datasrc/maps"] [submodule "datasrc/maps"]
path = datasrc/maps path = datasrc/maps
url = git://github.com/teeworlds/teeworlds-maps.git url = git://github.com/teeworlds/teeworlds-maps.git
branch = master

77
bam.lua
View file

@ -1,4 +1,4 @@
CheckVersion("0.4") CheckVersion("0.5")
Import("configure.lua") Import("configure.lua")
Import("other/sdl/sdl.lua") Import("other/sdl/sdl.lua")
@ -8,7 +8,7 @@ Import("other/freetype/freetype.lua")
config = NewConfig() config = NewConfig()
config:Add(OptCCompiler("compiler")) config:Add(OptCCompiler("compiler"))
config:Add(OptTestCompileC("stackprotector", "int main(){return 0;}", "-fstack-protector -fstack-protector-all")) config:Add(OptTestCompileC("stackprotector", "int main(){return 0;}", "-fstack-protector -fstack-protector-all"))
config:Add(OptTestCompileC("minmacosxsdk", "int main(){return 0;}", "-mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk")) config:Add(OptTestCompileC("minmacosxsdk", "int main(){return 0;}", "-mmacosx-version-min=10.7 -isysroot /Developer/SDKs/MacOSX10.7.sdk"))
config:Add(OptLibrary("zlib", "zlib.h", false)) config:Add(OptLibrary("zlib", "zlib.h", false))
config:Add(SDL.OptFind("sdl", true)) config:Add(SDL.OptFind("sdl", true))
config:Add(FreeType.OptFind("freetype", true)) config:Add(FreeType.OptFind("freetype", true))
@ -76,7 +76,7 @@ function ContentCompile(action, output)
end end
function GenerateCommonSettings(settings) function GenerateCommonSettings(settings, conf, arch, compiler)
if compiler == "gcc" or compiler == "clang" then if compiler == "gcc" or compiler == "clang" then
settings.cc.flags:Add("-Wall", "-fno-exceptions") settings.cc.flags:Add("-Wall", "-fno-exceptions")
end end
@ -93,15 +93,16 @@ function GenerateCommonSettings(settings)
zlib = Compile(settings, Collect("src/engine/external/zlib/*.c")) zlib = Compile(settings, Collect("src/engine/external/zlib/*.c"))
end end
local md5 = Compile(settings, Collect("src/engine/external/md5/*.c"))
local wavpack = Compile(settings, Collect("src/engine/external/wavpack/*.c")) local wavpack = Compile(settings, Collect("src/engine/external/wavpack/*.c"))
local png = Compile(settings, Collect("src/engine/external/pnglite/*.c")) local png = Compile(settings, Collect("src/engine/external/pnglite/*.c"))
local json = Compile(settings, Collect("src/engine/external/json-parser/*.c")) local json = Compile(settings, Collect("src/engine/external/json-parser/*.c"))
-- globally available libs -- globally available libs
libs = {zlib=zlib, wavpack=wavpack, png=png, json=json} libs = {zlib=zlib, wavpack=wavpack, png=png, md5=md5, json=json}
end end
function GenerateMacOSXSettings(settings, conf, arch) function GenerateMacOSXSettings(settings, conf, arch, compiler)
if arch == "x86" then if arch == "x86" then
settings.cc.flags:Add("-arch i386") settings.cc.flags:Add("-arch i386")
settings.link.flags:Add("-arch i386") settings.link.flags:Add("-arch i386")
@ -119,17 +120,23 @@ function GenerateMacOSXSettings(settings, conf, arch)
os.exit(1) os.exit(1)
end end
settings.cc.flags:Add("-mmacosx-version-min=10.5") -- c++ stdlib needed
settings.link.flags:Add("-mmacosx-version-min=10.5") settings.cc.flags:Add("--stdlib=libc++")
settings.link.flags:Add("--stdlib=libc++")
-- this also needs the macOS min SDK version to be at least 10.7
settings.cc.flags:Add("-mmacosx-version-min=10.7")
settings.link.flags:Add("-mmacosx-version-min=10.7")
if config.minmacosxsdk.value == 1 then if config.minmacosxsdk.value == 1 then
settings.cc.flags:Add("-isysroot /Developer/SDKs/MacOSX10.5.sdk") settings.cc.flags:Add("-isysroot /Developer/SDKs/MacOSX10.7.sdk")
settings.link.flags:Add("-isysroot /Developer/SDKs/MacOSX10.5.sdk") settings.link.flags:Add("-isysroot /Developer/SDKs/MacOSX10.7.sdk")
end end
settings.link.frameworks:Add("Carbon") settings.link.frameworks:Add("Carbon")
settings.link.frameworks:Add("AppKit") settings.link.frameworks:Add("AppKit")
GenerateCommonSettings(settings, conf, arch) GenerateCommonSettings(settings, conf, arch, compiler)
-- Build server launcher before adding game stuff -- Build server launcher before adding game stuff
local serverlaunch = Link(settings, "serverlaunch", Compile(settings, "src/osxlaunch/server.m")) local serverlaunch = Link(settings, "serverlaunch", Compile(settings, "src/osxlaunch/server.m"))
@ -160,20 +167,23 @@ function GenerateMacOSXSettings(settings, conf, arch)
BuildContent(settings) BuildContent(settings)
end end
function GenerateLinuxSettings(settings, conf, arch) function GenerateLinuxSettings(settings, conf, arch, compiler)
if arch == "x86" then if arch == "x86" then
settings.cc.flags:Add("-msse2") -- for the _mm_pause call
settings.cc.flags:Add("-m32") settings.cc.flags:Add("-m32")
settings.link.flags:Add("-m32") settings.link.flags:Add("-m32")
elseif arch == "x86_64" then elseif arch == "x86_64" then
settings.cc.flags:Add("-m64") settings.cc.flags:Add("-m64")
settings.link.flags:Add("-m64") settings.link.flags:Add("-m64")
elseif arch == "armv7l" then
-- arm 32 bit
else else
print("Unknown Architecture '" .. arch .. "'. Supported: x86, x86_64") print("Unknown Architecture '" .. arch .. "'. Supported: x86, x86_64")
os.exit(1) os.exit(1)
end end
settings.link.libs:Add("pthread") settings.link.libs:Add("pthread")
GenerateCommonSettings(settings, conf, arch) GenerateCommonSettings(settings, conf, arch, compiler)
-- Master server, version server and tools -- Master server, version server and tools
BuildEngineCommon(settings) BuildEngineCommon(settings)
@ -197,29 +207,23 @@ function GenerateLinuxSettings(settings, conf, arch)
BuildContent(settings) BuildContent(settings)
end end
function GenerateSolarisSettings(settings, conf, arch) function GenerateSolarisSettings(settings, conf, arch, compiler)
settings.link.libs:Add("socket") settings.link.libs:Add("socket")
settings.link.libs:Add("nsl") settings.link.libs:Add("nsl")
GenerateLinuxSettings(settings, conf, arch) GenerateLinuxSettings(settings, conf, arch, compiler)
end end
function GenerateWindowsSettings(settings, conf, target_arch, compiler) function GenerateWindowsSettings(settings, conf, target_arch, compiler)
if compiler == "cl" then if compiler == "cl" then
if (target_arch == "x86" and arch ~= "ia32") or if (target_arch == "x86" and arch ~= "ia32") or
(target_arch == "x86_64" and arch ~= "x64" and arch ~= "x86_64") then (target_arch == "x86_64" and arch ~= "ia64" and arch ~= "amd64") then
print("Cross compiling is unsupported on Windows.") print("Cross compiling is unsupported on Windows.")
os.exit(1) os.exit(1)
end end
settings.cc.flags:Add("/wd4244") settings.cc.flags:Add("/wd4244", "/wd4577")
elseif compiler == "gcc" or config.compiler.driver == "clang" then elseif compiler == "gcc" or config.compiler.driver == "clang" then
if target_arch == "x86" then if target_arch ~= "x86" and target_arch ~= "x86_64" then
settings.cc.flags:Add("-m32")
settings.link.flags:Add("-m32")
elseif target_arch == "x86_64" then
settings.cc.flags:Add("-m64")
settings.link.flags:Add("-m64")
else
print("Unknown Architecture '" .. arch .. "'. Supported: x86, x86_64") print("Unknown Architecture '" .. arch .. "'. Supported: x86, x86_64")
os.exit(1) os.exit(1)
end end
@ -237,8 +241,9 @@ function GenerateWindowsSettings(settings, conf, target_arch, compiler)
settings.link.libs:Add("ws2_32") settings.link.libs:Add("ws2_32")
settings.link.libs:Add("ole32") settings.link.libs:Add("ole32")
settings.link.libs:Add("shell32") settings.link.libs:Add("shell32")
settings.link.libs:Add("advapi32")
GenerateCommonSettings(settings, conf, target_arch) GenerateCommonSettings(settings, conf, target_arch, compiler)
-- Master server, version server and tools -- Master server, version server and tools
BuildEngineCommon(settings) BuildEngineCommon(settings)
@ -271,7 +276,7 @@ function SharedCommonFiles()
if not shared_common_files then if not shared_common_files then
local network_source = ContentCompile("network_source", "generated/protocol.cpp") local network_source = ContentCompile("network_source", "generated/protocol.cpp")
local network_header = ContentCompile("network_header", "generated/protocol.h") local network_header = ContentCompile("network_header", "generated/protocol.h")
AddDependency(network_source, network_header) AddDependency(network_source, network_header, "src/engine/shared/protocol.h")
local nethash = CHash("generated/nethash.cpp", "src/engine/shared/protocol.h", "src/game/tuning.h", "src/game/gamecore.cpp", network_header) local nethash = CHash("generated/nethash.cpp", "src/engine/shared/protocol.h", "src/game/tuning.h", "src/game/gamecore.cpp", network_header)
shared_common_files = {network_source, nethash} shared_common_files = {network_source, nethash}
@ -334,7 +339,7 @@ function BuildClient(settings, family, platform)
local game_client = Compile(settings, CollectRecursive("src/game/client/*.cpp"), SharedClientFiles()) local game_client = Compile(settings, CollectRecursive("src/game/client/*.cpp"), SharedClientFiles())
local game_editor = Compile(settings, Collect("src/game/editor/*.cpp")) local game_editor = Compile(settings, Collect("src/game/editor/*.cpp"))
Link(settings, "teeworlds", libs["zlib"], libs["wavpack"], libs["png"], libs["json"], client, game_client, game_editor) Link(settings, "teeworlds", libs["zlib"], libs["md5"], libs["wavpack"], libs["png"], libs["json"], client, game_client, game_editor)
end end
function BuildServer(settings, family, platform) function BuildServer(settings, family, platform)
@ -342,24 +347,24 @@ function BuildServer(settings, family, platform)
local game_server = Compile(settings, CollectRecursive("src/game/server/*.cpp"), SharedServerFiles()) local game_server = Compile(settings, CollectRecursive("src/game/server/*.cpp"), SharedServerFiles())
return Link(settings, "teeworlds_srv", libs["zlib"], server, game_server) return Link(settings, "teeworlds_srv", libs["zlib"], libs["md5"], server, game_server)
end end
function BuildTools(settings) function BuildTools(settings)
local tools = {} local tools = {}
for i,v in ipairs(Collect("src/tools/*.cpp", "src/tools/*.c")) do for i,v in ipairs(Collect("src/tools/*.cpp", "src/tools/*.c")) do
local toolname = PathFilename(PathBase(v)) local toolname = PathFilename(PathBase(v))
tools[i] = Link(settings, toolname, Compile(settings, v), libs["zlib"], libs["wavpack"], libs["png"]) tools[i] = Link(settings, toolname, Compile(settings, v), libs["zlib"], libs["md5"], libs["wavpack"], libs["png"])
end end
PseudoTarget(settings.link.Output(settings, "pseudo_tools") .. settings.link.extension, tools) PseudoTarget(settings.link.Output(settings, "pseudo_tools") .. settings.link.extension, tools)
end end
function BuildMasterserver(settings) function BuildMasterserver(settings)
return Link(settings, "mastersrv", Compile(settings, Collect("src/mastersrv/*.cpp")), libs["zlib"]) return Link(settings, "mastersrv", Compile(settings, Collect("src/mastersrv/*.cpp")), libs["zlib"], libs["md5"])
end end
function BuildVersionserver(settings) function BuildVersionserver(settings)
return Link(settings, "versionsrv", Compile(settings, Collect("src/versionsrv/*.cpp")), libs["zlib"]) return Link(settings, "versionsrv", Compile(settings, Collect("src/versionsrv/*.cpp")), libs["zlib"], libs["md5"])
end end
function BuildContent(settings) function BuildContent(settings)
@ -380,6 +385,8 @@ function GenerateSettings(conf, arch, builddir, compiler)
elseif compiler == "cl" then elseif compiler == "cl" then
SetDriversCL(settings) SetDriversCL(settings)
else else
-- apply compiler settings
config.compiler:Apply(settings)
compiler = config.compiler.driver compiler = config.compiler.driver
end end
@ -413,11 +420,11 @@ function GenerateSettings(conf, arch, builddir, compiler)
GenerateWindowsSettings(settings, conf, arch, compiler) GenerateWindowsSettings(settings, conf, arch, compiler)
elseif family == "unix" then elseif family == "unix" then
if platform == "macosx" then if platform == "macosx" then
GenerateMacOSXSettings(settings, conf, arch) GenerateMacOSXSettings(settings, conf, arch, compiler)
elseif platform == "linux" then
GenerateLinuxSettings(settings, conf, arch)
elseif platform == "solaris" then elseif platform == "solaris" then
GenerateSolarisSettings(settings, conf, arch) GenerateSolarisSettings(settings, conf, arch, compiler)
else -- Linux, BSD
GenerateLinuxSettings(settings, conf, arch, compiler)
end end
end end
@ -452,7 +459,7 @@ if ScriptArgs['arch'] then
else else
if arch == "ia32" then if arch == "ia32" then
archs = {"x86"} archs = {"x86"}
elseif arch == "x64" or arch == "amd64" then elseif arch == "ia64" or arch == "amd64" then
archs = {"x86_64"} archs = {"x86_64"}
else else
archs = {arch} archs = {arch}

View file

@ -72,13 +72,13 @@ function NewConfig(on_configured_callback)
end end
config.Load = function(self, filename) config.Load = function(self, filename)
local options_func = loadfile(filename)
local options_table = {} local options_table = {}
local options_func = loadfile(filename, nil, options_table)
if not options_func then if not options_func then
print("auto configuration") print("auto configuration")
self:Config(filename) self:Config(filename)
options_func = loadfile(filename) options_func = loadfile(filename, nil, options_table)
end end
if options_func then if options_func then
@ -86,7 +86,6 @@ function NewConfig(on_configured_callback)
for k,v in pairs(self.options) do for k,v in pairs(self.options) do
options_table[v.name] = {} options_table[v.name] = {}
end end
setfenv(options_func, options_table)
-- this is to make sure that we get nice error messages when -- this is to make sure that we get nice error messages when
-- someone sets an option that isn't valid. -- someone sets an option that isn't valid.
@ -360,10 +359,10 @@ function OptCCompiler(name, default_driver, default_c, default_cxx, desc)
-- no need todo anything if we have a driver -- no need todo anything if we have a driver
-- TODO: test if we can find the compiler -- TODO: test if we can find the compiler
else else
if ExecuteSilent("cl") == 0 then if ExecuteSilent("g++ -v") == 0 then
option.driver = "cl"
elseif ExecuteSilent("g++ -v") == 0 then
option.driver = "gcc" option.driver = "gcc"
elseif ExecuteSilent("cl") == 0 then
option.driver = "cl"
else else
error("no c/c++ compiler found") error("no c/c++ compiler found")
end end

View file

@ -1,4 +1,5 @@
import os, imp, sys import os
import sys
from datatypes import * from datatypes import *
import content import content
import network import network
@ -127,11 +128,11 @@ if gen_network_header:
class CNetObjHandler class CNetObjHandler
{ {
const char *m_pMsgFailedOn; const char *m_pMsgFailedOn;
const char *m_pObjCorrectedOn;
char m_aMsgData[1024]; char m_aMsgData[1024];
int m_NumObjCorrections; const char *m_pObjFailedOn;
int ClampInt(const char *pErrorMsg, int Value, int Min, int Max); int m_NumObjFailures;
int ClampFlag(const char *pErrorMsg, int Value, int Mask); bool CheckInt(const char *pErrorMsg, int Value, int Min, int Max);
bool CheckFlag(const char *pErrorMsg, int Value, int Mask);
static const char *ms_apObjNames[]; static const char *ms_apObjNames[];
static int ms_aObjSizes[]; static int ms_aObjSizes[];
@ -143,8 +144,8 @@ public:
int ValidateObj(int Type, const void *pData, int Size); int ValidateObj(int Type, const void *pData, int Size);
const char *GetObjName(int Type) const; const char *GetObjName(int Type) const;
int GetObjSize(int Type) const; int GetObjSize(int Type) const;
int NumObjCorrections() const; const char *FailedObjOn() const;
const char *CorrectedObjOn() const; int NumObjFailures() const;
const char *GetMsgName(int Type) const; const char *GetMsgName(int Type) const;
void *SecureUnpackMsg(int Type, CUnpacker *pUnpacker); void *SecureUnpackMsg(int Type, CUnpacker *pUnpacker);
@ -167,34 +168,32 @@ if gen_network_source:
lines += ['CNetObjHandler::CNetObjHandler()'] lines += ['CNetObjHandler::CNetObjHandler()']
lines += ['{'] lines += ['{']
lines += ['\tm_pMsgFailedOn = "";'] lines += ['\tm_pMsgFailedOn = "";']
lines += ['\tm_pObjCorrectedOn = "";'] lines += ['\tm_pObjFailedOn = "";']
lines += ['\tm_NumObjCorrections = 0;'] lines += ['\tm_NumObjFailures = 0;']
lines += ['}'] lines += ['}']
lines += [''] lines += ['']
lines += ['int CNetObjHandler::NumObjCorrections() const { return m_NumObjCorrections; }'] lines += ['const char *CNetObjHandler::FailedObjOn() const { return m_pObjFailedOn; }']
lines += ['const char *CNetObjHandler::CorrectedObjOn() const { return m_pObjCorrectedOn; }'] lines += ['int CNetObjHandler::NumObjFailures() const { return m_NumObjFailures; }']
lines += ['const char *CNetObjHandler::FailedMsgOn() const { return m_pMsgFailedOn; }'] lines += ['const char *CNetObjHandler::FailedMsgOn() const { return m_pMsgFailedOn; }']
lines += [''] lines += ['']
lines += [''] lines += ['']
lines += [''] lines += ['']
lines += [''] lines += ['']
lines += ['']
lines += ['static const int max_int = 0x7fffffff;'] lines += ['static const int max_int = 0x7fffffff;']
lines += [''] lines += ['']
lines += ['int CNetObjHandler::ClampInt(const char *pErrorMsg, int Value, int Min, int Max)'] lines += ['bool CNetObjHandler::CheckInt(const char *pErrorMsg, int Value, int Min, int Max)']
lines += ['{'] lines += ['{']
lines += ['\tif(Value < Min) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return Min; }'] lines += ['\tif(Value < Min || Value > Max) { m_pObjFailedOn = pErrorMsg; m_NumObjFailures++; return false; }']
lines += ['\tif(Value > Max) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return Max; }'] lines += ['\treturn true;']
lines += ['\treturn Value;']
lines += ['}'] lines += ['}']
lines += [''] lines += ['']
lines += ['int CNetObjHandler::ClampFlag(const char *pErrorMsg, int Value, int Mask)'] lines += ['bool CNetObjHandler::CheckFlag(const char *pErrorMsg, int Value, int Mask)']
lines += ['{'] lines += ['{']
lines += ['\tif((Value&Mask) != Value) { m_pObjCorrectedOn = pErrorMsg; m_NumObjCorrections++; return (Value&Mask); }'] lines += ['\tif((Value&Mask) != Value) { m_pObjFailedOn = pErrorMsg; m_NumObjFailures++; return false; }']
lines += ['\treturn Value;'] lines += ['\treturn true;']
lines += ['}'] lines += ['}']
lines += [''] lines += ['']
@ -300,6 +299,7 @@ if gen_network_source:
lines += ['void *CNetObjHandler::SecureUnpackMsg(int Type, CUnpacker *pUnpacker)'] lines += ['void *CNetObjHandler::SecureUnpackMsg(int Type, CUnpacker *pUnpacker)']
lines += ['{'] lines += ['{']
lines += ['\tm_pMsgFailedOn = 0;'] lines += ['\tm_pMsgFailedOn = 0;']
lines += ['\tm_pObjFailedOn = 0;']
lines += ['\tswitch(Type)'] lines += ['\tswitch(Type)']
lines += ['\t{'] lines += ['\t{']
@ -317,9 +317,15 @@ if gen_network_source:
lines += ['\tif(pUnpacker->Error())'] lines += ['\tif(pUnpacker->Error())']
lines += ['\t\tm_pMsgFailedOn = "(unpack error)";'] lines += ['\t\tm_pMsgFailedOn = "(unpack error)";']
lines += ['\t'] lines += ['\t']
lines += ['\tif(m_pMsgFailedOn)'] lines += ['\tif(m_pMsgFailedOn || m_pObjFailedOn) {']
lines += ['\t\tif(!m_pMsgFailedOn)']
lines += ['\t\t\tm_pMsgFailedOn = "";']
lines += ['\t\tif(!m_pObjFailedOn)']
lines += ['\t\t\tm_pObjFailedOn = "";']
lines += ['\t\treturn 0;'] lines += ['\t\treturn 0;']
lines += ['\t}']
lines += ['\tm_pMsgFailedOn = "";'] lines += ['\tm_pMsgFailedOn = "";']
lines += ['\tm_pObjFailedOn = "";']
lines += ['\treturn m_aMsgData;'] lines += ['\treturn m_aMsgData;']
lines += ['};'] lines += ['};']
lines += [''] lines += ['']

View file

@ -17,10 +17,11 @@ class SoundSet(Struct):
self.sounds.Add(Sound(name)) self.sounds.Add(Sound(name))
class Image(Struct): class Image(Struct):
def __init__(self, name="", filename=""): def __init__(self, name="", filename="", linear_mapping=0):
Struct.__init__(self, "CDataImage") Struct.__init__(self, "CDataImage")
self.name = String(name) self.name = String(name)
self.filename = String(filename) self.filename = String(filename)
self.flag = Int(linear_mapping)
self.id = TextureHandle() self.id = TextureHandle()
class SpriteSet(Struct): class SpriteSet(Struct):
@ -233,15 +234,20 @@ container.sounds.Add(SoundSet("menu", ["audio/music_menu.wv"]))
image_null = Image("null", "") image_null = Image("null", "")
image_particles = Image("particles", "particles.png") image_particles = Image("particles", "particles.png")
image_game = Image("game", "game.png") image_game = Image("game", "game.png")
image_browseicons = Image("browseicons", "ui/icons/browse.png") image_browseicons = Image("browseicons", "ui/icons/browse.png", 1)
image_emoticons = Image("emoticons", "emoticons.png") image_emoticons = Image("emoticons", "emoticons.png")
image_demobuttons = Image("demobuttons", "ui/demo_buttons.png") image_demobuttons = Image("demobuttons", "ui/demo_buttons.png", 1)
image_fileicons = Image("fileicons", "ui/file_icons.png") image_fileicons = Image("fileicons", "ui/file_icons.png", 1)
image_guibuttons = Image("guibuttons", "ui/gui_buttons.png") image_guibuttons = Image("guibuttons", "ui/gui_buttons.png", 1)
image_guiicons = Image("guiicons", "ui/gui_icons.png") image_guiicons = Image("guiicons", "ui/gui_icons.png", 1)
image_menuicons = Image("menuicons", "ui/icons/menu.png") image_menuicons = Image("menuicons", "ui/icons/menu.png", 1)
image_toolicons = Image("toolicons", "ui/icons/tools.png") image_toolicons = Image("toolicons", "ui/icons/tools.png", 1)
image_infoicons = Image("infoicons", "ui/icons/info.png") image_arrowicons = Image("arrowicons", "ui/icons/arrows.png", 1)
image_friendicons = Image("friendicons", "ui/icons/friend.png", 1)
image_infoicons = Image("infoicons", "ui/icons/info.png", 1)
image_levelicons = Image("levelicons", "ui/icons/level.png", 1)
image_sidebaricons = Image("sidebaricons", "ui/icons/sidebar.png", 1)
image_chatwhisper = Image("chatwhisper", "ui/icons/chat_whisper.png", 1)
container.images.Add(image_null) container.images.Add(image_null)
container.images.Add(image_game) container.images.Add(image_game)
@ -260,7 +266,12 @@ container.images.Add(image_guiicons)
container.images.Add(Image("no_skinpart", "ui/no_skinpart.png")) container.images.Add(Image("no_skinpart", "ui/no_skinpart.png"))
container.images.Add(image_menuicons) container.images.Add(image_menuicons)
container.images.Add(image_toolicons) container.images.Add(image_toolicons)
container.images.Add(image_arrowicons)
container.images.Add(image_friendicons)
container.images.Add(image_infoicons) container.images.Add(image_infoicons)
container.images.Add(image_levelicons)
container.images.Add(image_sidebaricons)
container.images.Add(image_chatwhisper)
container.pickups.Add(Pickup("health")) container.pickups.Add(Pickup("health"))
container.pickups.Add(Pickup("armor")) container.pickups.Add(Pickup("armor"))
@ -277,6 +288,7 @@ set_tee_decoration = SpriteSet("tee_decoration", image_null, 2, 1)
set_tee_hands = SpriteSet("tee_hands", image_null, 2, 1) set_tee_hands = SpriteSet("tee_hands", image_null, 2, 1)
set_tee_feet = SpriteSet("tee_feet", image_null, 2, 1) set_tee_feet = SpriteSet("tee_feet", image_null, 2, 1)
set_tee_eyes = SpriteSet("tee_eyes", image_null, 2, 4) set_tee_eyes = SpriteSet("tee_eyes", image_null, 2, 4)
set_tee_hats = SpriteSet("tee_hats", image_null, 1, 4)
set_browseicons = SpriteSet("browseicons", image_browseicons, 4, 2) set_browseicons = SpriteSet("browseicons", image_browseicons, 4, 2)
set_emoticons = SpriteSet("emoticons", image_emoticons, 4, 4) set_emoticons = SpriteSet("emoticons", image_emoticons, 4, 4)
set_demobuttons = SpriteSet("demobuttons", image_demobuttons, 5, 1) set_demobuttons = SpriteSet("demobuttons", image_demobuttons, 5, 1)
@ -285,7 +297,11 @@ set_guibuttons = SpriteSet("guibuttons", image_guibuttons, 12, 4)
set_guiicons = SpriteSet("guiicons", image_guiicons, 8, 2) set_guiicons = SpriteSet("guiicons", image_guiicons, 8, 2)
set_menuicons = SpriteSet("menuicons", image_menuicons, 2, 2) set_menuicons = SpriteSet("menuicons", image_menuicons, 2, 2)
set_toolicons = SpriteSet("toolicons", image_toolicons, 4, 2) set_toolicons = SpriteSet("toolicons", image_toolicons, 4, 2)
set_arrowicons = SpriteSet("arrowicons", image_arrowicons, 4, 3)
set_friendicons = SpriteSet("friendicons", image_friendicons, 2, 2)
set_infoicons = SpriteSet("infoicons", image_infoicons, 1, 2) set_infoicons = SpriteSet("infoicons", image_infoicons, 1, 2)
set_levelicons = SpriteSet("levelicons", image_levelicons, 4, 4)
set_sidebaricons = SpriteSet("sidebaricons", image_sidebaricons, 4, 2)
container.spritesets.Add(set_particles) container.spritesets.Add(set_particles)
container.spritesets.Add(set_game) container.spritesets.Add(set_game)
@ -295,6 +311,7 @@ container.spritesets.Add(set_tee_decoration)
container.spritesets.Add(set_tee_hands) container.spritesets.Add(set_tee_hands)
container.spritesets.Add(set_tee_feet) container.spritesets.Add(set_tee_feet)
container.spritesets.Add(set_tee_eyes) container.spritesets.Add(set_tee_eyes)
container.spritesets.Add(set_tee_hats)
container.spritesets.Add(set_browseicons) container.spritesets.Add(set_browseicons)
container.spritesets.Add(set_emoticons) container.spritesets.Add(set_emoticons)
container.spritesets.Add(set_demobuttons) container.spritesets.Add(set_demobuttons)
@ -303,7 +320,12 @@ container.spritesets.Add(set_guibuttons)
container.spritesets.Add(set_guiicons) container.spritesets.Add(set_guiicons)
container.spritesets.Add(set_menuicons) container.spritesets.Add(set_menuicons)
container.spritesets.Add(set_toolicons) container.spritesets.Add(set_toolicons)
container.spritesets.Add(set_arrowicons)
container.spritesets.Add(set_friendicons)
container.spritesets.Add(set_infoicons) container.spritesets.Add(set_infoicons)
container.spritesets.Add(set_levelicons)
container.spritesets.Add(set_sidebaricons)
container.sprites.Add(Sprite("part_slice", set_particles, 0,0,1,1)) container.sprites.Add(Sprite("part_slice", set_particles, 0,0,1,1))
container.sprites.Add(Sprite("part_ball", set_particles, 1,0,1,1)) container.sprites.Add(Sprite("part_ball", set_particles, 1,0,1,1))
@ -383,6 +405,11 @@ container.sprites.Add(Sprite("pickup_ninja", set_game, 2,10,8,2))
container.sprites.Add(Sprite("flag_blue", set_game, 12,8,4,8)) container.sprites.Add(Sprite("flag_blue", set_game, 12,8,4,8))
container.sprites.Add(Sprite("flag_red", set_game, 16,8,4,8)) container.sprites.Add(Sprite("flag_red", set_game, 16,8,4,8))
container.sprites.Add(Sprite("ninja_bar_full_left", set_game, 21,4,1,2))
container.sprites.Add(Sprite("ninja_bar_full", set_game, 22,4,1,2))
container.sprites.Add(Sprite("ninja_bar_empty", set_game, 23,4,1,2))
container.sprites.Add(Sprite("ninja_bar_empty_right", set_game, 24,4,1,2))
container.sprites.Add(Sprite("tee_body_outline", set_tee_body, 0,0,1,1)) container.sprites.Add(Sprite("tee_body_outline", set_tee_body, 0,0,1,1))
container.sprites.Add(Sprite("tee_body", set_tee_body, 1,0,1,1)) container.sprites.Add(Sprite("tee_body", set_tee_body, 1,0,1,1))
container.sprites.Add(Sprite("tee_body_shadow", set_tee_body, 0,1,1,1)) container.sprites.Add(Sprite("tee_body_shadow", set_tee_body, 0,1,1,1))
@ -405,6 +432,11 @@ container.sprites.Add(Sprite("tee_eyes_pain", set_tee_eyes, 0,1,1,1))
container.sprites.Add(Sprite("tee_eyes_happy", set_tee_eyes, 1,1,1,1)) container.sprites.Add(Sprite("tee_eyes_happy", set_tee_eyes, 1,1,1,1))
container.sprites.Add(Sprite("tee_eyes_surprise", set_tee_eyes, 0,2,1,1)) container.sprites.Add(Sprite("tee_eyes_surprise", set_tee_eyes, 0,2,1,1))
container.sprites.Add(Sprite("tee_hats_top1", set_tee_hats, 0,0,1,1))
container.sprites.Add(Sprite("tee_hats_top2", set_tee_hats, 0,1,1,1))
container.sprites.Add(Sprite("tee_hats_side1", set_tee_hats, 0,2,1,1))
container.sprites.Add(Sprite("tee_hats_side2", set_tee_hats, 0,3,1,1))
container.sprites.Add(Sprite("oop", set_emoticons, 0, 0, 1, 1)) container.sprites.Add(Sprite("oop", set_emoticons, 0, 0, 1, 1))
container.sprites.Add(Sprite("exclamation", set_emoticons, 1, 0, 1, 1)) container.sprites.Add(Sprite("exclamation", set_emoticons, 1, 0, 1, 1))
container.sprites.Add(Sprite("hearts", set_emoticons, 2, 0, 1, 1)) container.sprites.Add(Sprite("hearts", set_emoticons, 2, 0, 1, 1))
@ -468,9 +500,45 @@ container.sprites.Add(Sprite("tool_edit_b", set_toolicons, 2,1,1,1))
container.sprites.Add(Sprite("tool_x_a", set_toolicons, 3,0,1,1)) container.sprites.Add(Sprite("tool_x_a", set_toolicons, 3,0,1,1))
container.sprites.Add(Sprite("tool_x_b", set_toolicons, 3,1,1,1)) container.sprites.Add(Sprite("tool_x_b", set_toolicons, 3,1,1,1))
container.sprites.Add(Sprite("arrow_left_a", set_arrowicons, 0,0,1,1))
container.sprites.Add(Sprite("arrow_left_b", set_arrowicons, 0,1,1,1))
container.sprites.Add(Sprite("arrow_left_c", set_arrowicons, 0,2,1,1))
container.sprites.Add(Sprite("arrow_up_a", set_arrowicons, 1,0,1,1))
container.sprites.Add(Sprite("arrow_up_b", set_arrowicons, 1,1,1,1))
container.sprites.Add(Sprite("arrow_up_c", set_arrowicons, 1,2,1,1))
container.sprites.Add(Sprite("arrow_right_a", set_arrowicons, 2,0,1,1))
container.sprites.Add(Sprite("arrow_right_b", set_arrowicons, 2,1,1,1))
container.sprites.Add(Sprite("arrow_right_c", set_arrowicons, 2,2,1,1))
container.sprites.Add(Sprite("arrow_down_a", set_arrowicons, 3,0,1,1))
container.sprites.Add(Sprite("arrow_down_b", set_arrowicons, 3,1,1,1))
container.sprites.Add(Sprite("arrow_down_c", set_arrowicons, 3,2,1,1))
container.sprites.Add(Sprite("friend_plus_a", set_friendicons, 0,0,1,1))
container.sprites.Add(Sprite("friend_plus_b", set_friendicons, 0,1,1,1))
container.sprites.Add(Sprite("friend_x_a", set_friendicons, 1,0,1,1))
container.sprites.Add(Sprite("friend_x_b", set_friendicons, 1,1,1,1))
container.sprites.Add(Sprite("info_a", set_infoicons, 0,0,1,1)) container.sprites.Add(Sprite("info_a", set_infoicons, 0,0,1,1))
container.sprites.Add(Sprite("info_b", set_infoicons, 0,1,1,1)) container.sprites.Add(Sprite("info_b", set_infoicons, 0,1,1,1))
container.sprites.Add(Sprite("level_a_on", set_levelicons, 0,0,1,1))
container.sprites.Add(Sprite("level_a_a", set_levelicons, 0,1,1,1))
container.sprites.Add(Sprite("level_a_b", set_levelicons, 0,2,1,1))
container.sprites.Add(Sprite("level_b_on", set_levelicons, 1,0,1,1))
container.sprites.Add(Sprite("level_b_a", set_levelicons, 1,1,1,1))
container.sprites.Add(Sprite("level_b_b", set_levelicons, 1,2,1,1))
container.sprites.Add(Sprite("level_c_on", set_levelicons, 2,0,1,1))
container.sprites.Add(Sprite("level_c_a", set_levelicons, 2,1,1,1))
container.sprites.Add(Sprite("level_c_b", set_levelicons, 2,2,1,1))
container.sprites.Add(Sprite("sidebar_refresh_a", set_sidebaricons, 0,0,1,1))
container.sprites.Add(Sprite("sidebar_refresh_b", set_sidebaricons, 0,1,1,1))
container.sprites.Add(Sprite("sidebar_friend_a", set_sidebaricons, 1,0,1,1))
container.sprites.Add(Sprite("sidebar_friend_b", set_sidebaricons, 1,1,1,1))
container.sprites.Add(Sprite("sidebar_filter_a", set_sidebaricons, 2,0,1,1))
container.sprites.Add(Sprite("sidebar_filter_b", set_sidebaricons, 2,1,1,1))
container.sprites.Add(Sprite("sidebar_info_a", set_sidebaricons, 3,0,1,1))
container.sprites.Add(Sprite("sidebar_info_b", set_sidebaricons, 3,1,1,1))
anim = Animation("base") anim = Animation("base")
anim.body.frames.Add(AnimKeyframe(0, 0, -4, 0)) anim.body.frames.Add(AnimKeyframe(0, 0, -4, 0))
@ -543,7 +611,7 @@ weapon.damage.Set(1)
weapon.ammoregentime.Set(500) weapon.ammoregentime.Set(500)
weapon.visual_size.Set(64) weapon.visual_size.Set(64)
weapon.offsetx.Set(32) weapon.offsetx.Set(32)
weapon.offsety.Set(4) weapon.offsety.Set(-4)
weapon.muzzleoffsetx.Set(50) weapon.muzzleoffsetx.Set(50)
weapon.muzzleoffsety.Set(6) weapon.muzzleoffsety.Set(6)
container.weapons.gun.base.Set(weapon) container.weapons.gun.base.Set(weapon)

BIN
datasrc/countryflags/PS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -20,6 +20,26 @@
"id": "XWA", "id": "XWA",
"code": 904 "code": 904
}, },
{
"id": "XBZ",
"code": 950,
"blocked": true
},
{
"id": "XCA",
"code": 951,
"blocked": true
},
{
"id": "XES",
"code": 952,
"blocked": true
},
{
"id": "XGA",
"code": 953,
"blocked": true
},
{ {
"id": "default", "id": "default",
"code": -1 "code": -1
@ -738,6 +758,10 @@
"id": "PR", "id": "PR",
"code": 630 "code": 630
}, },
{
"id": "PS",
"code": 275
},
{ {
"id": "PT", "id": "PT",
"code": 620 "code": 620

View file

@ -147,7 +147,7 @@ class Float(BaseType):
def Set(self, value): def Set(self, value):
self.value = value self.value = value
def EmitDefinition(self, name): def EmitDefinition(self, name):
return ["%f"%self.value] return ["%ff"%self.value]
#return ["%d /* %s */"%(self.value, self._target_name)] #return ["%d /* %s */"%(self.value, self._target_name)]
class String(BaseType): class String(BaseType):
@ -328,9 +328,9 @@ class NetIntRange(NetIntAny):
self.min = str(min) self.min = str(min)
self.max = str(max) self.max = str(max)
def emit_validate(self): def emit_validate(self):
return ["ClampInt(\"%s\", pObj->%s, %s, %s);"%(self.name,self.name, self.min, self.max)] return ["if(!CheckInt(\"%s\", pObj->%s, %s, %s)) return -1;"%(self.name, self.name, self.min, self.max)]
def emit_unpack_check(self): def emit_unpack_check(self):
return ["if(pMsg->%s < %s || pMsg->%s > %s) { m_pMsgFailedOn = \"%s\"; break; }" % (self.name, self.min, self.name, self.max, self.name)] return ["if(!CheckInt(\"%s\", pMsg->%s, %s, %s)) break;"%(self.name, self.name, self.min, self.max)]
class NetEnum(NetIntRange): class NetEnum(NetIntRange):
def __init__(self, name, enum): def __init__(self, name, enum):
@ -346,9 +346,9 @@ class NetFlag(NetIntAny):
else: else:
self.mask = "0" self.mask = "0"
def emit_validate(self): def emit_validate(self):
return ["ClampFlag(\"%s\", pObj->%s, %s);"%(self.name, self.name, self.mask)] return ["if(!CheckFlag(\"%s\", pObj->%s, %s)) return -1;"%(self.name, self.name, self.mask)]
def emit_unpack_check(self): def emit_unpack_check(self):
return ["if((pMsg->%s & (%s)) != pMsg->%s) { m_pMsgFailedOn = \"%s\"; break; }" % (self.name, self.mask, self.name, self.name)] return ["if(!CheckFlag(\"%s\", pMsg->%s, %s)) break;"%(self.name, self.name, self.mask)]
class NetBool(NetIntRange): class NetBool(NetIntRange):
def __init__(self, name): def __init__(self, name):

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 137 KiB

@ -1 +1 @@
Subproject commit 68c3ccfe095d88028bfe1e2f27f44983a244c7d7 Subproject commit d5143007d8492481b687d4adab04b1968107196b

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 B

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

@ -1 +1 @@
Subproject commit 7673ace6ac831f3496870fe3c4c79e8423307c0d Subproject commit 7fefdb4c643f4e623f179460b8e68cd51f4d5e9d

View file

@ -3,9 +3,10 @@ from datatypes import *
Pickups = Enum("PICKUP", ["HEALTH", "ARMOR", "GRENADE", "SHOTGUN", "LASER", "NINJA"]) Pickups = Enum("PICKUP", ["HEALTH", "ARMOR", "GRENADE", "SHOTGUN", "LASER", "NINJA"])
Emotes = Enum("EMOTE", ["NORMAL", "PAIN", "HAPPY", "SURPRISE", "ANGRY", "BLINK"]) Emotes = Enum("EMOTE", ["NORMAL", "PAIN", "HAPPY", "SURPRISE", "ANGRY", "BLINK"])
Emoticons = Enum("EMOTICON", ["OOP", "EXCLAMATION", "HEARTS", "DROP", "DOTDOT", "MUSIC", "SORRY", "GHOST", "SUSHI", "SPLATTEE", "DEVILTEE", "ZOMG", "ZZZ", "WTF", "EYES", "QUESTION"]) Emoticons = Enum("EMOTICON", ["OOP", "EXCLAMATION", "HEARTS", "DROP", "DOTDOT", "MUSIC", "SORRY", "GHOST", "SUSHI", "SPLATTEE", "DEVILTEE", "ZOMG", "ZZZ", "WTF", "EYES", "QUESTION"])
Votes = Enum("VOTE", ["UNKNOWN", "START_OP", "START_KICK", "START_SPEC", "END_ABORT", "END_PASS", "END_FAIL"]) Votes = Enum("VOTE", ["UNKNOWN", "START_OP", "START_KICK", "START_SPEC", "END_ABORT", "END_PASS", "END_FAIL"]) # todo: add RUN_OP, RUN_KICK, RUN_SPEC; rem UNKNOWN
ChatModes = Enum("CHAT", ["NONE", "ALL", "TEAM", "WHISPER"])
PlayerFlags = Flags("PLAYERFLAG", ["ADMIN", "CHATTING", "SCOREBOARD", "READY", "DEAD", "WATCHING"]) PlayerFlags = Flags("PLAYERFLAG", ["ADMIN", "CHATTING", "SCOREBOARD", "READY", "DEAD", "WATCHING", "BOT"])
GameFlags = Flags("GAMEFLAG", ["TEAMS", "FLAGS", "SURVIVAL"]) GameFlags = Flags("GAMEFLAG", ["TEAMS", "FLAGS", "SURVIVAL"])
GameStateFlags = Flags("GAMESTATEFLAG", ["WARMUP", "SUDDENDEATH", "ROUNDOVER", "GAMEOVER", "PAUSED", "STARTCOUNTDOWN"]) GameStateFlags = Flags("GAMESTATEFLAG", ["WARMUP", "SUDDENDEATH", "ROUNDOVER", "GAMEOVER", "PAUSED", "STARTCOUNTDOWN"])
CoreEventFlags = Flags("COREEVENTFLAG", ["GROUND_JUMP", "AIR_JUMP", "HOOK_ATTACH_PLAYER", "HOOK_ATTACH_GROUND", "HOOK_HIT_NOHOOK"]) CoreEventFlags = Flags("COREEVENTFLAG", ["GROUND_JUMP", "AIR_JUMP", "HOOK_ATTACH_PLAYER", "HOOK_ATTACH_GROUND", "HOOK_HIT_NOHOOK"])
@ -37,7 +38,11 @@ enum
FLAG_ATSTAND, FLAG_ATSTAND,
FLAG_TAKEN, FLAG_TAKEN,
SPEC_FREEVIEW=-1, SPEC_FREEVIEW=0,
SPEC_PLAYER,
SPEC_FLAGRED,
SPEC_FLAGBLUE,
NUM_SPECMODES,
}; };
''' '''
@ -51,6 +56,7 @@ Enums = [
Emotes, Emotes,
Emoticons, Emoticons,
Votes, Votes,
ChatModes,
GameMsgIDs, GameMsgIDs,
] ]
@ -147,6 +153,8 @@ Objects = [
NetIntAny("m_HookX"), NetIntAny("m_HookX"),
NetIntAny("m_HookY"), NetIntAny("m_HookY"),
NetIntAny("m_HookDx"),
NetIntAny("m_HookDy"),
]), ]),
NetObject("Character:CharacterCore", [ NetObject("Character:CharacterCore", [
@ -166,7 +174,8 @@ Objects = [
]), ]),
NetObject("SpectatorInfo", [ NetObject("SpectatorInfo", [
NetIntRange("m_SpectatorID", 'SPEC_FREEVIEW', 'MAX_CLIENTS-1'), NetIntRange("m_SpecMode", 0, 'NUM_SPECMODES-1'),
NetIntRange("m_SpectatorID", -1, 'MAX_CLIENTS-1'),
NetIntAny("m_X"), NetIntAny("m_X"),
NetIntAny("m_Y"), NetIntAny("m_Y"),
]), ]),
@ -199,7 +208,7 @@ Objects = [
NetObject("De_TuneParams", [ NetObject("De_TuneParams", [
# todo: should be done differently # todo: should be done differently
NetArray(NetIntAny("m_aTuneParams"), 33), NetArray(NetIntAny("m_aTuneParams"), 32),
]), ]),
## Events ## Events
@ -222,8 +231,12 @@ Objects = [
NetIntRange("m_SoundID", 0, 'NUM_SOUNDS-1'), NetIntRange("m_SoundID", 0, 'NUM_SOUNDS-1'),
]), ]),
NetEvent("DamageInd:Common", [ NetEvent("Damage:Common", [ # Unused yet
NetIntRange("m_ClientID", 0, 'MAX_CLIENTS-1'),
NetIntAny("m_Angle"), NetIntAny("m_Angle"),
NetIntRange("m_HealthAmount", 0, 9),
NetIntRange("m_ArmorAmount", 0, 9),
NetBool("m_Self"),
]), ]),
] ]
@ -234,9 +247,14 @@ Messages = [
NetString("m_pMessage"), NetString("m_pMessage"),
]), ]),
NetMessage("Sv_Broadcast", [
NetString("m_pMessage"),
]),
NetMessage("Sv_Chat", [ NetMessage("Sv_Chat", [
NetIntRange("m_Team", 'TEAM_SPECTATORS', 'TEAM_BLUE'), NetIntRange("m_Mode", 0, 'NUM_CHATS-1'),
NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'), NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'),
NetIntRange("m_TargetID", -1, 'MAX_CLIENTS-1'),
NetStringStrict("m_pMessage"), NetStringStrict("m_pMessage"),
]), ]),
@ -313,6 +331,7 @@ Messages = [
NetArray(NetStringStrict("m_apSkinPartNames"), 6), NetArray(NetStringStrict("m_apSkinPartNames"), 6),
NetArray(NetBool("m_aUseCustomColors"), 6), NetArray(NetBool("m_aUseCustomColors"), 6),
NetArray(NetIntAny("m_aSkinPartColors"), 6), NetArray(NetIntAny("m_aSkinPartColors"), 6),
NetBool("m_Silent"),
]), ]),
NetMessage("Sv_GameInfo", [ NetMessage("Sv_GameInfo", [
@ -328,6 +347,7 @@ Messages = [
NetMessage("Sv_ClientDrop", [ NetMessage("Sv_ClientDrop", [
NetIntRange("m_ClientID", 0, 'MAX_CLIENTS-1'), NetIntRange("m_ClientID", 0, 'MAX_CLIENTS-1'),
NetStringStrict("m_pReason"), NetStringStrict("m_pReason"),
NetBool("m_Silent"),
]), ]),
NetMessage("Sv_GameMsg", []), NetMessage("Sv_GameMsg", []),
@ -335,17 +355,20 @@ Messages = [
## Demo messages ## Demo messages
NetMessage("De_ClientEnter", [ NetMessage("De_ClientEnter", [
NetStringStrict("m_pName"), NetStringStrict("m_pName"),
NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'),
NetIntRange("m_Team", 'TEAM_SPECTATORS', 'TEAM_BLUE'), NetIntRange("m_Team", 'TEAM_SPECTATORS', 'TEAM_BLUE'),
]), ]),
NetMessage("De_ClientLeave", [ NetMessage("De_ClientLeave", [
NetStringStrict("m_pName"), NetStringStrict("m_pName"),
NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'),
NetStringStrict("m_pReason"), NetStringStrict("m_pReason"),
]), ]),
### Client messages ### Client messages
NetMessage("Cl_Say", [ NetMessage("Cl_Say", [
NetBool("m_Team"), NetIntRange("m_Mode", 0, 'NUM_CHATS-1'),
NetIntRange("m_Target", -1, 'MAX_CLIENTS-1'),
NetStringStrict("m_pMessage"), NetStringStrict("m_pMessage"),
]), ]),
@ -354,7 +377,8 @@ Messages = [
]), ]),
NetMessage("Cl_SetSpectatorMode", [ NetMessage("Cl_SetSpectatorMode", [
NetIntRange("m_SpectatorID", 'SPEC_FREEVIEW', 'MAX_CLIENTS-1'), NetIntRange("m_SpecMode", 0, 'NUM_SPECMODES-1'),
NetIntRange("m_SpectatorID", -1, 'MAX_CLIENTS-1'),
]), ]),
NetMessage("Cl_StartInfo", [ NetMessage("Cl_StartInfo", [

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -11,8 +11,8 @@
"custom_colors": "true", "custom_colors": "true",
"hue": 0, "hue": 0,
"sat": 0, "sat": 0,
"lgt": 255, "lgt": 64,
"alp": 127 "alp": 255
}, },
"hands": { "hands": {
"filename": "standard", "filename": "standard",

BIN
datasrc/skins/xmas_hat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
datasrc/ui/gametypes/dm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
datasrc/ui/icons/arrows.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
datasrc/ui/icons/friend.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
datasrc/ui/icons/level.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

BIN
datasrc/ui/themes/none.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

View file

@ -1,4 +1,4 @@
Copyright (C) 2007-2014 Magnus Auvinen Copyright (C) 2007-2018 Magnus Auvinen
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@ -18,9 +18,14 @@ freely, subject to the following restrictions:
------------------------------------------------------------------------ ------------------------------------------------------------------------
All content under 'data' except the font (which has its own license) is All content under 'data' and 'datasrc' except the font (which has its own license) is
released under CC-BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/). released under CC-BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/).
Authors: android272, Chi11y (chi1), Crises, Daniel, Echchouik, Fisico,
Landil, Lappi, LordSk, maikka, matricks, Pocram, red_com,
serpis, SkizZ, somerunce, Sonix, Stephanator, teetow, Ubu,
Zatline
------------------------------------------------------------------------ ------------------------------------------------------------------------
IMPORTANT NOTE! The source under src/engine/external are stripped IMPORTANT NOTE! The source under src/engine/external are stripped

View file

@ -4,11 +4,15 @@ FreeType = {
OptFind = function (name, required) OptFind = function (name, required)
local check = function(option, settings) local check = function(option, settings)
option.value = false option.value = false
option.use_pkgconfig = false
option.use_ftconfig = false option.use_ftconfig = false
option.use_winlib = 0 option.use_winlib = 0
option.lib_path = nil option.lib_path = nil
if ExecuteSilent("freetype-config") > 0 and ExecuteSilent("freetype-config --cflags") == 0 then if ExecuteSilent("pkg-config freetype2") == 0 then
option.value = true
option.use_pkgconfig = true
elseif ExecuteSilent("freetype-config") > 0 and ExecuteSilent("freetype-config --cflags") == 0 then
option.value = true option.value = true
option.use_ftconfig = true option.use_ftconfig = true
end end
@ -23,15 +27,18 @@ FreeType = {
end end
local apply = function(option, settings) local apply = function(option, settings)
if option.use_ftconfig == true then if option.use_pkgconfig == true then
settings.cc.flags:Add("`pkg-config --cflags freetype2`")
settings.link.flags:Add("`pkg-config --libs freetype2`")
elseif option.use_ftconfig == true then
settings.cc.flags:Add("`freetype-config --cflags`") settings.cc.flags:Add("`freetype-config --cflags`")
settings.link.flags:Add("`freetype-config --libs`") settings.link.flags:Add("`freetype-config --libs`")
elseif option.use_winlib > 0 then elseif option.use_winlib > 0 then
settings.cc.includes:Add(FreeType.basepath .. "/include") settings.cc.includes:Add(FreeType.basepath .. "/include")
if option.use_winlib == 32 then if option.use_winlib == 32 then
settings.link.libpath:Add(FreeType.basepath .. "/lib32") settings.link.libpath:Add(FreeType.basepath .. "/lib/x86")
else else
settings.link.libpath:Add(FreeType.basepath .. "/lib64") settings.link.libpath:Add(FreeType.basepath .. "/lib/x64")
end end
settings.link.libs:Add("freetype") settings.link.libs:Add("freetype")
end end
@ -39,12 +46,14 @@ FreeType = {
local save = function(option, output) local save = function(option, output)
output:option(option, "value") output:option(option, "value")
output:option(option, "use_pkgconfig")
output:option(option, "use_ftconfig") output:option(option, "use_ftconfig")
output:option(option, "use_winlib") output:option(option, "use_winlib")
end end
local display = function(option) local display = function(option)
if option.value == true then if option.value == true then
if option.use_pkgconfig == true then return "using pkg-config" end
if option.use_ftconfig == true then return "using freetype-config" end if option.use_ftconfig == true then return "using freetype-config" end
if option.use_winlib == 32 then return "using supplied win32 libraries" end if option.use_winlib == 32 then return "using supplied win32 libraries" end
if option.use_winlib == 64 then return "using supplied win64 libraries" end if option.use_winlib == 64 then return "using supplied win64 libraries" end

View file

@ -1 +1 @@
1.2.15 2.0.5

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<application>
<id type="desktop">teeworlds.desktop</id>
<license>Zlib and CC-BY-SA-3.0</license>
<metadata_license>CC0-1.0</metadata_license>
<summary>Online multiplayer shooter game</summary>
<description>
<p>
Teeworlds is a free online multiplayer game. Battle with up to 16 players
in a variety of game modes, including Team Deathmatch and Capture The Flag.
You can even design your own maps!
</p>
</description>
<url type="homepage">https://www.teeworlds.com/</url>
<screenshots>
<screenshot>https://www.teeworlds.com/images/screens/screenshot_desert.png</screenshot>
<screenshot>https://www.teeworlds.com/images/screens/screenshot_grass.png</screenshot>
<screenshot>https://www.teeworlds.com/images/screens/screenshot_winter.png</screenshot>
<screenshot>https://www.teeworlds.com/images/screens/screenshot_jungle.png</screenshot>
</screenshots>
</application>

9
other/teeworlds.desktop Normal file
View file

@ -0,0 +1,9 @@
[Desktop Entry]
Name=Teeworlds
GenericName=Online multi-player 2D platform shooter
Type=Application
Terminal=false
Exec=teeworlds
Icon=teeworlds
Comment=Teeworlds: Jumping the Gun
Categories=Game;ArcadeGame;

View file

@ -1,4 +1,4 @@
Teeworlds Teeworlds [![CircleCI](https://circleci.com/gh/teeworlds/teeworlds.svg?style=svg)](https://circleci.com/gh/teeworlds/teeworlds)
========= =========
A retro multiplayer shooter A retro multiplayer shooter
@ -17,4 +17,8 @@ text including copyright information.
Please visit https://www.teeworlds.com/ for up-to-date information about Please visit https://www.teeworlds.com/ for up-to-date information about
the game, including new versions, custom maps and much more. the game, including new versions, custom maps and much more.
Instructions to build the game can be found at
https://teeworlds.com/?page=docs&wiki=compiling_everything. In
particular, you will need SDL2 and FreeType installed.
Originally written by Magnus Auvinen. Originally written by Magnus Auvinen.

View file

@ -52,7 +52,7 @@ def parse_source():
return l10n return l10n
def load_languagefile(filename): def load_languagefile(filename):
return json.load(open(filename)) return json.load(open(filename), strict=False) # accept \t tabs
def write_languagefile(outputfilename, l10n_src, old_l10n_data): def write_languagefile(outputfilename, l10n_src, old_l10n_data):
outputfilename += '.po' outputfilename += '.po'
@ -110,7 +110,10 @@ if __name__ == '__main__':
'Content-Transfer-Encoding': '8bit', 'Content-Transfer-Encoding': '8bit',
} }
for (msg, ctxt), occurrences in l10n_src.items(): for (msg, ctxt), occurrences in l10n_src.items():
po.append(polib.POEntry(msgid=msg, msgstr="", occurrences=occurrences, msgctxt=ctxt)) commenttxt = ctxt
if(commenttxt):
commenttxt = 'Context: '+commenttxt
po.append(polib.POEntry(msgid=msg, msgstr="", occurrences=occurrences, msgctxt=ctxt, comment=commenttxt))
po.save('data/languages/base.pot') po.save('data/languages/base.pot')
for filename in os.listdir("data/languages"): for filename in os.listdir("data/languages"):

View file

@ -1,4 +1,5 @@
import shutil, optparse, os, re, sys, zipfile import shutil, optparse, os, re, sys, zipfile
from distutils.dir_util import copy_tree
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])) + "/..") os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])) + "/..")
import twlib import twlib
@ -88,6 +89,12 @@ def clean():
package = "%s-%s-%s" %(name, version, platform) package = "%s-%s-%s" %(name, version, platform)
package_dir = package package_dir = package
source_package_dir = "build/"
if platform == 'win32' or platform == 'linux_x86':
source_package_dir += "x86/release/"
else:
source_package_dir += "x86_64/release/"
print("cleaning target") print("cleaning target")
shutil.rmtree(package_dir, True) shutil.rmtree(package_dir, True)
os.mkdir(package_dir) os.mkdir(package_dir)
@ -118,18 +125,17 @@ shutil.copy("license.txt", package_dir)
shutil.copy("storage.cfg", package_dir) shutil.copy("storage.cfg", package_dir)
if include_data and not use_bundle: if include_data and not use_bundle:
os.mkdir(os.path.join(package_dir, "data")) copy_tree(source_package_dir+"data", package_dir+"/data")
copydir("data", package_dir) copy_tree(languages_dir, package_dir+"/data/languages")
copyfiles(languages_dir, package_dir+"/data/languages") copy_tree(maps_dir, package_dir+"/data/maps")
copyfiles(maps_dir, package_dir+"/data/maps")
if platform[:3] == "win": if platform[:3] == "win":
shutil.copy("other/config_directory.bat", package_dir) shutil.copy("other/config_directory.bat", package_dir)
shutil.copy("SDL.dll", package_dir) shutil.copy(source_package_dir+"SDL2.dll", package_dir)
shutil.copy("freetype.dll", package_dir) shutil.copy(source_package_dir+"freetype.dll", package_dir)
if include_exe and not use_bundle: if include_exe and not use_bundle:
shutil.copy(name+exe_ext, package_dir) shutil.copy(source_package_dir+name+exe_ext, package_dir)
shutil.copy(name+"_srv"+exe_ext, package_dir) shutil.copy(source_package_dir+name+"_srv"+exe_ext, package_dir)
if include_src: if include_src:
for p in ["src", "scripts", "datasrc", "other", "objs"]: for p in ["src", "scripts", "datasrc", "other", "objs"]:
@ -140,7 +146,7 @@ if include_src:
if use_bundle: if use_bundle:
bins = [name, name+'_srv', 'serverlaunch'] bins = [name, name+'_srv', 'serverlaunch']
platforms = ('x86', 'x86_64', 'ppc') platforms = ('x86_64')
for bin in bins: for bin in bins:
to_lipo = [] to_lipo = []
for p in platforms: for p in platforms:
@ -155,19 +161,24 @@ if use_bundle:
clientbundle_bin_dir = os.path.join(clientbundle_content_dir, "MacOS") clientbundle_bin_dir = os.path.join(clientbundle_content_dir, "MacOS")
clientbundle_resource_dir = os.path.join(clientbundle_content_dir, "Resources") clientbundle_resource_dir = os.path.join(clientbundle_content_dir, "Resources")
clientbundle_framework_dir = os.path.join(clientbundle_content_dir, "Frameworks") clientbundle_framework_dir = os.path.join(clientbundle_content_dir, "Frameworks")
binary_path = clientbundle_bin_dir + "/" + name+exe_ext
freetypelib_path = clientbundle_framework_dir + "/libfreetype.6.dylib"
os.mkdir(os.path.join(package_dir, "Teeworlds.app")) os.mkdir(os.path.join(package_dir, "Teeworlds.app"))
os.mkdir(clientbundle_content_dir) os.mkdir(clientbundle_content_dir)
os.mkdir(clientbundle_bin_dir) os.mkdir(clientbundle_bin_dir)
os.mkdir(clientbundle_resource_dir) os.mkdir(clientbundle_resource_dir)
os.mkdir(clientbundle_framework_dir) os.mkdir(clientbundle_framework_dir)
os.mkdir(os.path.join(clientbundle_resource_dir, "data")) copy_tree(source_package_dir+"data", clientbundle_resource_dir+"/data")
copydir("data", clientbundle_resource_dir) copy_tree(languages_dir, clientbundle_resource_dir+"/data/languages")
os.chdir(languages_dir) copy_tree(maps_dir, clientbundle_resource_dir+"/data/maps")
copydir("data", "../"+clientbundle_resource_dir)
os.chdir("..")
shutil.copy("other/icons/Teeworlds.icns", clientbundle_resource_dir) shutil.copy("other/icons/Teeworlds.icns", clientbundle_resource_dir)
shutil.copy(name+exe_ext, clientbundle_bin_dir) shutil.copy(source_package_dir+name+exe_ext, clientbundle_bin_dir)
os.system("cp -R /Library/Frameworks/SDL.framework " + clientbundle_framework_dir) os.system("install_name_tool -change /usr/local/opt/freetype/lib/libfreetype.6.dylib @executable_path/../Frameworks/libfreetype.6.dylib " + binary_path)
os.system("install_name_tool -change /usr/local/opt/sdl2/lib/libSDL2-2.0.0.dylib @executable_path/../Frameworks/libSDL2-2.0.0.dylib " + binary_path)
os.system("cp /usr/local/opt/freetype/lib/libfreetype.6.dylib " + clientbundle_framework_dir)
os.system("cp /usr/local/opt/libpng/lib/libpng16.16.dylib " + clientbundle_framework_dir)
os.system("cp /usr/local/opt/sdl2/lib/libSDL2-2.0.0.dylib " + clientbundle_framework_dir)
os.system("install_name_tool -change /usr/local/opt/libpng/lib/libpng16.16.dylib @executable_path/../Frameworks/libpng16.16.dylib " + freetypelib_path)
file(os.path.join(clientbundle_content_dir, "Info.plist"), "w").write(""" file(os.path.join(clientbundle_content_dir, "Info.plist"), "w").write("""
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@ -187,6 +198,10 @@ if use_bundle:
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>%s</string> <string>%s</string>
<key>CFBundleIdentifier</key>
<string>com.TeeworldsClient.app</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict> </dict>
</plist> </plist>
""" % (version)) """ % (version))
@ -203,10 +218,10 @@ if use_bundle:
os.mkdir(os.path.join(serverbundle_resource_dir, "data")) os.mkdir(os.path.join(serverbundle_resource_dir, "data"))
os.mkdir(os.path.join(serverbundle_resource_dir, "data/maps")) os.mkdir(os.path.join(serverbundle_resource_dir, "data/maps"))
os.mkdir(os.path.join(serverbundle_resource_dir, "data/mapres")) os.mkdir(os.path.join(serverbundle_resource_dir, "data/mapres"))
copydir("data/maps", serverbundle_resource_dir) copy_tree(maps_dir, serverbundle_resource_dir+"/data/maps")
shutil.copy("other/icons/Teeworlds_srv.icns", serverbundle_resource_dir) shutil.copy("other/icons/Teeworlds_srv.icns", serverbundle_resource_dir)
shutil.copy(name+"_srv"+exe_ext, serverbundle_bin_dir) shutil.copy(source_package_dir+name+"_srv"+exe_ext, serverbundle_bin_dir)
shutil.copy("serverlaunch"+exe_ext, serverbundle_bin_dir + "/"+name+"_server") shutil.copy(source_package_dir+"serverlaunch"+exe_ext, serverbundle_bin_dir + "/"+name+"_server")
file(os.path.join(serverbundle_content_dir, "Info.plist"), "w").write(""" file(os.path.join(serverbundle_content_dir, "Info.plist"), "w").write("""
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

View file

@ -1,162 +1,180 @@
#!/bin/env python3
# coding: utf-8 # coding: utf-8
from socket import * from socket import *
import struct
import sys import sys
import threading import threading
import time import time
import random
NUM_MASTERSERVERS = 4 NUM_MASTERSERVERS = 4
MASTERSERVER_PORT = 8300 MASTERSERVER_PORT = 8283
TIMEOUT = 2 TIMEOUT = 2
SERVERTYPE_NORMAL = 0 # src/mastersrv/mastersrv.h
SERVERTYPE_LEGACY = 1 PACKET_GETLIST = b"\xff\xff\xff\xffreq2"
PACKET_LIST = b"\xff\xff\xff\xfflis2"
PACKET_GETLIST = "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreqt" PACKET_GETINFO = b"\xff\xff\xff\xffgie3"
PACKET_GETLIST2 = "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreq2" PACKET_INFO = b"\xff\xff\xff\xffinf3"
PACKET_GETINFO = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgief"
PACKET_GETINFO2 = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgie2" + "\x00"
PACKET_GETINFO3 = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgie3" + "\x00"
# see CNetBase::SendControlMsgWithToken
def pack_control_msg_with_token(token_srv,token_cl):
NET_PACKETFLAG_CONTROL = 1
NET_CTRLMSG_TOKEN = 5
NET_TOKENREQUEST_DATASIZE = 512
b = [0]*(4 + 3 + NET_TOKENREQUEST_DATASIZE)
# Header
b[0] = (NET_PACKETFLAG_CONTROL<<2)&0xfc
b[3] = (token_srv >> 24) & 0xff
b[4] = (token_srv >> 16) & 0xff
b[5] = (token_srv >> 8) & 0xff
b[6] = (token_srv) & 0xff
# Data
b[7] = NET_CTRLMSG_TOKEN
b[8] = (token_cl >> 24) & 0xff
b[9] = (token_cl >> 16) & 0xff
b[10] = (token_cl >> 8) & 0xff
b[11] = (token_cl) & 0xff
return bytes(b)
def unpack_control_msg_with_token(msg):
b = list(msg)
token_cl = (b[3] << 24) + (b[4] << 16) + (b[5] << 8) + (b[6])
token_srv = (b[8] << 24) + (b[9] << 16) + (b[10] << 8) + (b[11])
return token_cl,token_srv
# CNetBase::SendPacketConnless
def header_connless(token_srv, token_cl):
NET_PACKETFLAG_CONNLESS = 8
NET_PACKETVERSION = 1
b = [0]*9
# Header
b[0] = ((NET_PACKETFLAG_CONNLESS<<2)&0xfc) | (NET_PACKETVERSION&0x03)
b[1] = (token_srv >> 24) & 0xff
b[2] = (token_srv >> 16) & 0xff
b[3] = (token_srv >> 8) & 0xff
b[4] = (token_srv) & 0xff
# ResponseToken
b[5] = (token_cl >> 24) & 0xff
b[6] = (token_cl >> 16) & 0xff
b[7] = (token_cl >> 8) & 0xff
b[8] = (token_cl) & 0xff
return bytes(b)
# CVariableInt::Unpack from src/engine/shared/compression.cpp
def unpack_int(b):
l = list(b[:5])
i = 0
Sign = (l[i]>>6)&1;
res = l[i] & 0x3F;
for _ in (0,):
if not (l[i]&0x80):
break
i+=1
res |= (l[i]&(0x7F))<<(6);
if not (l[i]&0x80):
break
i+=1
res |= (l[i]&(0x7F))<<(6+7);
if not (l[i]&0x80):
break
i+=1
res |= (l[i]&(0x7F))<<(6+7+7);
if not (l[i]&0x80):
break
i+=1
res |= (l[i]&(0x7F))<<(6+7+7+7);
i += 1;
res ^= -Sign
return res, b[i:]
class Server_Info(threading.Thread): class Server_Info(threading.Thread):
def __init__(self, address, type): def __init__(self, address):
self.address = address self.address = address
self.type = type
self.finished = False self.finished = False
threading.Thread.__init__(self, target = self.run) threading.Thread.__init__(self, target = self.run)
def run(self): def run(self):
self.info = None self.info = None
if self.type == SERVERTYPE_NORMAL:
self.info = get_server_info3(self.address)
elif self.type == SERVERTYPE_LEGACY:
self.info = get_server_info(self.address) self.info = get_server_info(self.address)
if self.info:
self.info = get_server_info2(self.address)
self.finished = True self.finished = True
def get_server_info(address): def get_server_info(address):
try: try:
sock = socket(AF_INET, SOCK_DGRAM) sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT); sock.settimeout(TIMEOUT)
sock.sendto(PACKET_GETINFO, address) token = random.randrange(0x100000000)
# Token request
sock.sendto(pack_control_msg_with_token(-1,token),address)
data, addr = sock.recvfrom(1024) data, addr = sock.recvfrom(1024)
token_cl, token_srv = unpack_control_msg_with_token(data)
assert token_cl == token, "Server %s send wrong token: %d (%d expected)" % (address, token_cl, token)
# Get info request
sock.sendto(header_connless(token_srv, token_cl) + PACKET_GETINFO + b'\x00', address)
data, addr = sock.recvfrom(4096)
head = header_connless(token_cl, token_srv) + PACKET_INFO + b'\x00'
assert data[:len(head)] == head, "Server %s info header mismatch: %r != %r (expected)" % (address, data[:len(head)], head)
sock.close() sock.close()
data = data[14:] # skip header data = data[len(head):] # skip header
slots = data.split("\x00")
slots = data.split(b"\x00", maxsplit=5)
server_info = {} server_info = {}
server_info["version"] = slots[0] server_info["address"] = address
server_info["name"] = slots[1] server_info["version"] = slots[0].decode()
server_info["map"] = slots[2] server_info["name"] = slots[1].decode()
server_info["gametype"] = slots[3] server_info["hostname"] = slots[2].decode()
server_info["flags"] = int(slots[4]) server_info["map"] = slots[3].decode()
server_info["progression"] = int(slots[5]) server_info["gametype"] = slots[4].decode()
server_info["num_players"] = int(slots[6]) data = slots[5]
server_info["max_players"] = int(slots[7])
# these integers should fit in one byte each
server_info["flags"], server_info["skill"] = tuple(data[:2])
data = data[2:]
server_info["num_players"], data = unpack_int(data)
server_info["max_players"], data = unpack_int(data)
server_info["num_clients"], data = unpack_int(data)
server_info["max_clients"], data = unpack_int(data)
server_info["players"] = [] server_info["players"] = []
for i in xrange(0, server_info["num_players"]): for i in range(server_info["num_clients"]):
player = {} player = {}
player["name"] = slots[8+i*2] slots = data.split(b"\x00", maxsplit=2)
player["score"] = int(slots[8+i*2+1]) player["name"] = slots[0].decode()
player["clan"] = slots[1].decode()
data = slots[2]
player["country"], data = unpack_int(data)
player["score"], data = unpack_int(data)
player["player"], data = unpack_int(data)
server_info["players"].append(player) server_info["players"].append(player)
return server_info return server_info
except AssertionError as e:
print(*e.args)
except OSError as e: # Timeout
print('> Server %s did not answer' % (address,))
except: except:
# print('> Server %s did something wrong here' % (address,))
# import traceback
# traceback.print_exc()
pass
finally:
sock.close() sock.close()
return None return None
def get_server_info2(address):
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT);
sock.sendto(PACKET_GETINFO2, address)
data, addr = sock.recvfrom(1024)
sock.close()
data = data[14:] # skip header
slots = data.split("\x00")
server_info = {}
server_info["token"] = slots[0]
server_info["version"] = slots[1]
server_info["name"] = slots[2]
server_info["map"] = slots[3]
server_info["gametype"] = slots[4]
server_info["flags"] = int(slots[5])
server_info["progression"] = int(slots[6])
server_info["num_players"] = int(slots[7])
server_info["max_players"] = int(slots[8])
server_info["players"] = []
for i in xrange(0, server_info["num_players"]):
player = {}
player["name"] = slots[9+i*2]
player["score"] = int(slots[9+i*2+1])
server_info["players"].append(player)
return server_info
except:
sock.close()
return None
def get_server_info3(address):
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT);
sock.sendto(PACKET_GETINFO3, address)
data, addr = sock.recvfrom(1400)
sock.close()
data = data[14:] # skip header
slots = data.split("\x00")
server_info = {}
server_info["token"] = slots[0]
server_info["version"] = slots[1]
server_info["name"] = slots[2]
server_info["map"] = slots[3]
server_info["gametype"] = slots[4]
server_info["flags"] = int(slots[5])
server_info["num_players"] = int(slots[6])
server_info["max_players"] = int(slots[7])
server_info["num_clients"] = int(slots[8])
server_info["max_clients"] = int(slots[9])
server_info["players"] = []
for i in xrange(0, server_info["num_clients"]):
player = {}
player["name"] = slots[10+i*5]
player["clan"] = slots[10+i*5+1]
player["country"] = int(slots[10+i*5+2])
player["score"] = int(slots[10+i*5+3])
if int(slots[10+i*5+4]):
player["player"] = True
else:
player["player"] = False
server_info["players"].append(player)
return server_info
except:
sock.close()
return None
class Master_Server_Info(threading.Thread): class Master_Server_Info(threading.Thread):
def __init__(self, address): def __init__(self, address):
@ -165,106 +183,126 @@ class Master_Server_Info(threading.Thread):
threading.Thread.__init__(self, target = self.run) threading.Thread.__init__(self, target = self.run)
def run(self): def run(self):
self.servers = get_list(self.address) + get_list2(self.address) self.servers = get_list(self.address)
self.finished = True self.finished = True
def get_list(address): def get_list(address):
servers = [] servers = []
answer = False
try: try:
sock = socket(AF_INET, SOCK_DGRAM) sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT) sock.settimeout(TIMEOUT)
sock.sendto(PACKET_GETLIST, address)
token = random.randrange(0x100000000)
# Token request
sock.sendto(pack_control_msg_with_token(-1,token),address)
data, addr = sock.recvfrom(1024)
token_cl, token_srv = unpack_control_msg_with_token(data)
assert token_cl == token, "Master %s send wrong token: %d (%d expected)" % (address, token_cl, token)
answer = True
# Get list request
sock.sendto(header_connless(token_srv, token_cl) + PACKET_GETLIST, addr)
head = header_connless(token_cl, token_srv) + PACKET_LIST
while 1: while 1:
data, addr = sock.recvfrom(1024) data, addr = sock.recvfrom(1024)
# Header should keep consistent
assert data[:len(head)] == head, "Master %s list header mismatch: %r != %r (expected)" % (address, data[:len(head)], head)
data = data[14:] data = data[len(head):]
num_servers = len(data) / 6 num_servers = len(data) // 18
for n in range(0, num_servers): for n in range(0, num_servers):
ip = ".".join(map(str, map(ord, data[n*6:n*6+4]))) # IPv4
port = ord(data[n*6+5]) * 256 + ord(data[n*6+4]) if data[n*18:n*18+12] == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff":
servers += [[(ip, port), SERVERTYPE_LEGACY]] ip = ".".join(map(str, data[n*18+12:n*18+16]))
# IPv6
except:
sock.close()
return servers
def get_list2(address):
servers = []
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT)
sock.sendto(PACKET_GETLIST2, address)
while 1:
data, addr = sock.recvfrom(1400)
data = data[14:]
num_servers = len(data) / 18
for n in range(0, num_servers):
if data[n*18:n*18+12] == "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff":
ip = ".".join(map(str, map(ord, data[n*18+12:n*18+16])))
else: else:
ip = ":".join(map(str, map(ord, data[n*18:n*18+16]))) ip = ":".join(map(str, data[n*18:n*18+16]))
port = (ord(data[n*18+16])<<8) + ord(data[n*18+17]) port = ((data[n*18+16])<<8) + data[n*18+17]
servers += [[(ip, port), SERVERTYPE_NORMAL]] servers += [(ip, port)]
except AssertionError as e:
print(*e.args)
except OSError as e: # Timeout
if not answer:
print('> Master %s did not answer' % (address,))
except: except:
# import traceback
# traceback.print_exc()
sock.close() sock.close()
return servers return servers
if __name__ == '__main__':
master_servers = []
for i in range(1, NUM_MASTERSERVERS+1):
master_servers = []
for i in range(1, NUM_MASTERSERVERS+1):
m = Master_Server_Info(("master%d.teeworlds.com"%i, MASTERSERVER_PORT)) m = Master_Server_Info(("master%d.teeworlds.com"%i, MASTERSERVER_PORT))
master_servers.append(m) master_servers.append(m)
m.start() m.start()
time.sleep(0.001) # avoid issues time.sleep(0.001) # avoid issues
servers = [] servers = set()
while len(master_servers) != 0: while len(master_servers) != 0:
if master_servers[0].finished == True: if master_servers[0].finished == True:
if master_servers[0].servers: if master_servers[0].servers:
servers += master_servers[0].servers servers.update(master_servers[0].servers)
del master_servers[0] del master_servers[0]
time.sleep(0.001) # be nice time.sleep(0.001) # be nice
servers_info = [] servers_info = []
print str(len(servers)) + " servers" print(str(len(servers)) + " servers")
for server in servers: for server in servers:
s = Server_Info(server[0], server[1]) s = Server_Info(server)
servers_info.append(s) servers_info.append(s)
s.start() s.start()
time.sleep(0.001) # avoid issues time.sleep(0.001) # avoid issues
num_players = 0 num_players = 0
num_clients = 0 num_clients = 0
num_botplayers = 0
num_botspectators = 0
while len(servers_info) != 0: while len(servers_info) != 0:
if servers_info[0].finished == True: if servers_info[0].finished == True:
if servers_info[0].info: if servers_info[0].info:
num_players += servers_info[0].info["num_players"] server_info = servers_info[0].info
if servers_info[0].type == SERVERTYPE_NORMAL: # check num/max validity
num_clients += servers_info[0].info["num_clients"] if server_info["num_players"] > server_info["max_players"] \
or server_info["num_clients"] > server_info["max_clients"] \
or server_info["max_players"] > server_info["max_clients"] \
or server_info["num_players"] < 0 \
or server_info["num_clients"] < 0 \
or server_info["max_clients"] < 0 \
or server_info["max_players"] < 0 \
or server_info["max_clients"] > 64:
server_info["bad"] = 'invalid num/max'
print('> Server %s has %s' % (server_info["address"], server_info["bad"]))
# check actual purity
elif server_info["gametype"] in ('DM', 'TDM', 'CTF', 'LMS', 'LTS') \
and server_info["max_players"] > 16:
server_info["bad"] = 'too many players for vanilla'
print('> Server %s has %s' % (server_info["address"], server_info["bad"]))
else: else:
num_clients += servers_info[0].info["num_players"] num_players += server_info["num_players"]
num_clients += server_info["num_clients"]
for p in servers_info[0].info["players"]:
if p["player"] == 2:
num_botplayers += 1
if p["player"] == 3:
num_botspectators += 1
del servers_info[0] del servers_info[0]
time.sleep(0.001) # be nice time.sleep(0.001) # be nice
print str(num_players) + " players and " + str(num_clients-num_players) + " spectators" print('%d players (%d bots) and %d spectators (%d bots)' % (num_players, num_botplayers, num_clients - num_players, num_botspectators))

View file

@ -56,4 +56,97 @@ inline vec4 HexToRgba(int hex)
return c; return c;
} }
/*
Function: HsvToRgb
Converts Hsv to Rgb
*/
inline vec3 HsvToRgb(vec3 hsv)
{
int h = int(hsv.x * 6.0f);
float f = hsv.x * 6.0f - h;
float p = hsv.z * (1.0f - hsv.y);
float q = hsv.z * (1.0f - hsv.y * f);
float t = hsv.z * (1.0f - hsv.y * (1.0f - f));
vec3 rgb = vec3(0.0f, 0.0f, 0.0f);
switch(h % 6)
{
case 0:
rgb.r = hsv.z;
rgb.g = t;
rgb.b = p;
break;
case 1:
rgb.r = q;
rgb.g = hsv.z;
rgb.b = p;
break;
case 2:
rgb.r = p;
rgb.g = hsv.z;
rgb.b = t;
break;
case 3:
rgb.r = p;
rgb.g = q;
rgb.b = hsv.z;
break;
case 4:
rgb.r = t;
rgb.g = p;
rgb.b = hsv.z;
break;
case 5:
rgb.r = hsv.z;
rgb.g = p;
rgb.b = q;
break;
}
return rgb;
}
/*
Function: RgbToHsv
Converts Rgb to Hsv
*/
inline vec3 RgbToHsv(vec3 rgb)
{
float h_min = min(min(rgb.r, rgb.g), rgb.b);
float h_max = max(max(rgb.r, rgb.g), rgb.b);
// hue
float hue = 0.0f;
if(h_max == h_min)
hue = 0.0f;
else if(h_max == rgb.r)
hue = (rgb.g-rgb.b) / (h_max-h_min);
else if(h_max == rgb.g)
hue = 2.0f + (rgb.b-rgb.r) / (h_max-h_min);
else
hue = 4.0f + (rgb.r-rgb.g) / (h_max-h_min);
hue /= 6.0f;
if(hue < 0.0f)
hue += 1.0f;
// saturation
float s = 0.0f;
if(h_max != 0.0f)
s = (h_max - h_min)/h_max;
// lightness
float l = h_max;
return vec3(hue, s, l);
}
#endif #endif

View file

@ -140,6 +140,14 @@
#endif #endif
#endif #endif
#if defined(__arm__)
#define CONF_ARCH_ARM 1
#define CONF_ARCH_STRING "arm"
#if !defined(CONF_ARCH_ENDIAN_LITTLE) && !defined(CONF_ARCH_ENDIAN_BIG)
#define CONF_ARCH_ENDIAN_LITTLE 1
#endif
#endif
#ifndef CONF_FAMILY_STRING #ifndef CONF_FAMILY_STRING
#define CONF_FAMILY_STRING "unknown" #define CONF_FAMILY_STRING "unknown"

View file

@ -47,6 +47,7 @@ inline T bezier(const T p0, const T p1, const T p2, const T p3, TB amount)
return mix(c20, c21, amount); // c30 return mix(c20, c21, amount); // c30
} }
inline int random_int() { return (((rand() & 0xffff) << 16) | (rand() & 0xffff)) & 0x7FFFFFFF; };
inline float frandom() { return rand()/(float)(RAND_MAX); } inline float frandom() { return rand()/(float)(RAND_MAX); }
// float to fixed // float to fixed

View file

@ -39,6 +39,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <direct.h> #include <direct.h>
#include <errno.h> #include <errno.h>
#include <wincrypt.h>
#else #else
#error NOT IMPLEMENTED #error NOT IMPLEMENTED
#endif #endif
@ -59,7 +60,6 @@ static DBG_LOGGER loggers[16];
static int num_loggers = 0; static int num_loggers = 0;
static NETSTATS network_stats = {0}; static NETSTATS network_stats = {0};
static MEMSTATS memory_stats = {0};
static NETSOCKET invalid_socket = {NETTYPE_INVALID, -1, -1}; static NETSOCKET invalid_socket = {NETTYPE_INVALID, -1, -1};
@ -105,6 +105,94 @@ void dbg_msg(const char *sys, const char *fmt, ...)
loggers[i](str); loggers[i](str);
} }
#if defined(CONF_FAMILY_WINDOWS)
static void logger_win_console(const char *line)
{
#define _MAX_LENGTH 1024
#define _MAX_LENGTH_ERROR (_MAX_LENGTH+32)
static const int UNICODE_REPLACEMENT_CHAR = 0xfffd;
static const char *STR_TOO_LONG = "(str too long)";
static const char *INVALID_UTF8 = "(invalid utf8)";
wchar_t wline[_MAX_LENGTH_ERROR];
size_t len = 0;
const char *read = line;
const char *error = STR_TOO_LONG;
while(len < _MAX_LENGTH)
{
// Read a character. This also advances the read pointer
int glyph = str_utf8_decode(&read);
if(glyph < 0)
{
// If there was an error decoding the UTF-8 sequence,
// emit a replacement character. Since the
// str_utf8_decode function will not work after such
// an error, end the string here.
glyph = UNICODE_REPLACEMENT_CHAR;
error = INVALID_UTF8;
wline[len] = glyph;
break;
}
else if(glyph == 0)
{
// A character code of 0 signals the end of the string.
error = 0;
break;
}
else if(glyph > 0xffff)
{
// Since the windows console does not really support
// UTF-16, don't mind doing actual UTF-16 encoding,
// but rather emit a replacement character.
glyph = UNICODE_REPLACEMENT_CHAR;
}
else if(glyph == 0x2022)
{
// The 'bullet' character might get converted to a 'beep',
// so it will be replaced by the 'bullet operator'.
glyph = 0x2219;
}
// Again, since the windows console does not really support
// UTF-16, but rather something along the lines of UCS-2,
// simply put the character into the output.
wline[len++] = glyph;
}
if(error)
{
read = error;
while(1)
{
// Errors are simple ascii, no need for UTF-8
// decoding
char character = *read;
if(character == 0)
break;
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for error");
wline[len++] = character;
read++;
}
}
// Terminate the line
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for \\r");
wline[len++] = '\r';
dbg_assert(len < _MAX_LENGTH_ERROR, "str too short for \\n");
wline[len++] = '\n';
// Ignore any error that might occur
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), wline, len, 0, 0);
#undef _MAX_LENGTH
#undef _MAX_LENGTH_ERROR
}
#endif
static void logger_stdout(const char *line) static void logger_stdout(const char *line)
{ {
printf("%s\n", line); printf("%s\n", line);
@ -128,7 +216,18 @@ static void logger_file(const char *line)
io_flush(logfile); io_flush(logfile);
} }
void dbg_logger_stdout() { dbg_logger(logger_stdout); } void dbg_logger_stdout()
{
#if defined(CONF_FAMILY_WINDOWS)
if(GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR)
{
dbg_logger(logger_win_console);
return;
}
#endif
dbg_logger(logger_stdout);
}
void dbg_logger_debugger() { dbg_logger(logger_debugger); } void dbg_logger_debugger() { dbg_logger(logger_debugger); }
void dbg_logger_file(const char *filename) void dbg_logger_file(const char *filename)
{ {
@ -160,80 +259,14 @@ static const int MEM_GUARD_VAL = 0xbaadc0de;
void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned alignment) void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned alignment)
{ {
/* TODO: fix alignment */ return malloc(size);
/* TODO: add debugging */
MEMTAIL *tail;
MEMHEADER *header = (struct MEMHEADER *)malloc(size+sizeof(MEMHEADER)+sizeof(MEMTAIL));
dbg_assert(header != 0, "mem_alloc failure");
if(!header)
return NULL;
tail = (struct MEMTAIL *)(((char*)(header+1))+size);
header->size = size;
header->filename = filename;
header->line = line;
memory_stats.allocated += header->size;
memory_stats.total_allocations++;
memory_stats.active_allocations++;
tail->guard = MEM_GUARD_VAL;
header->prev = (MEMHEADER *)0;
header->next = first;
if(first)
first->prev = header;
first = header;
/*dbg_msg("mem", "++ %p", header+1); */
return header+1;
} }
void mem_free(void *p) void mem_free(void *p)
{ {
if(p) free(p);
{
MEMHEADER *header = (MEMHEADER *)p - 1;
MEMTAIL *tail = (MEMTAIL *)(((char*)(header+1))+header->size);
if(tail->guard != MEM_GUARD_VAL)
dbg_msg("mem", "!! %p", p);
/* dbg_msg("mem", "-- %p", p); */
memory_stats.allocated -= header->size;
memory_stats.active_allocations--;
if(header->prev)
header->prev->next = header->next;
else
first = header->next;
if(header->next)
header->next->prev = header->prev;
free(header);
}
} }
void mem_debug_dump(IOHANDLE file)
{
char buf[1024];
MEMHEADER *header = first;
if(!file)
file = io_open("memory.txt", IOFLAG_WRITE);
if(file)
{
while(header)
{
str_format(buf, sizeof(buf), "%s(%d): %d", header->filename, header->line, header->size);
io_write(file, buf, strlen(buf));
io_write_newline(file);
header = header->next;
}
io_close(file);
}
}
void mem_copy(void *dest, const void *source, unsigned size) void mem_copy(void *dest, const void *source, unsigned size)
{ {
memcpy(dest, source, size); memcpy(dest, source, size);
@ -369,14 +402,44 @@ int io_flush(IOHANDLE io)
return 0; return 0;
} }
struct THREAD_RUN
{
void (*threadfunc)(void *);
void *u;
};
#if defined(CONF_FAMILY_UNIX)
static void *thread_run(void *user)
#elif defined(CONF_FAMILY_WINDOWS)
static unsigned long __stdcall thread_run(void *user)
#else
#error not implemented
#endif
{
struct THREAD_RUN *data = user;
void (*threadfunc)(void *) = data->threadfunc;
void *u = data->u;
free(data);
threadfunc(u);
return 0;
}
void *thread_init(void (*threadfunc)(void *), void *u) void *thread_init(void (*threadfunc)(void *), void *u)
{ {
struct THREAD_RUN *data = malloc(sizeof(*data));
data->threadfunc = threadfunc;
data->u = u;
#if defined(CONF_FAMILY_UNIX) #if defined(CONF_FAMILY_UNIX)
{
pthread_t id; pthread_t id;
pthread_create(&id, NULL, (void *(*)(void*))threadfunc, u); if(pthread_create(&id, NULL, thread_run, data) != 0)
{
return 0;
}
return (void*)id; return (void*)id;
}
#elif defined(CONF_FAMILY_WINDOWS) #elif defined(CONF_FAMILY_WINDOWS)
return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadfunc, u, 0, NULL); return CreateThread(NULL, 0, thread_run, data, 0, NULL);
#else #else
#error not implemented #error not implemented
#endif #endif
@ -853,7 +916,7 @@ static int priv_net_close_all_sockets(NETSOCKET sock)
return 0; return 0;
} }
static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, int sockaddrlen) static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, int sockaddrlen, int use_random_port)
{ {
int sock, e; int sock, e;
@ -883,27 +946,46 @@ static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, i
#endif #endif
/* bind the socket */ /* bind the socket */
while(1)
{
/* pick random port */
if(use_random_port)
{
int port = htons(rand()%16384+49152); /* 49152 to 65535 */
if(domain == AF_INET)
((struct sockaddr_in *)(addr))->sin_port = port;
else
((struct sockaddr_in6 *)(addr))->sin6_port = port;
}
e = bind(sock, addr, sockaddrlen); e = bind(sock, addr, sockaddrlen);
if(e != 0) if(e == 0)
break;
else
{ {
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
char buf[128]; char buf[128];
int error = WSAGetLastError(); int error = WSAGetLastError();
if(error == WSAEADDRINUSE && use_random_port)
continue;
if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, 0, buf, sizeof(buf), 0) == 0) if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, 0, buf, sizeof(buf), 0) == 0)
buf[0] = 0; buf[0] = 0;
dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, error, buf); dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, error, buf);
#else #else
if(errno == EADDRINUSE && use_random_port)
continue;
dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, errno, strerror(errno)); dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, errno, strerror(errno));
#endif #endif
priv_net_close_socket(sock); priv_net_close_socket(sock);
return -1; return -1;
} }
}
/* return the newly created socket */ /* return the newly created socket */
return sock; return sock;
} }
NETSOCKET net_udp_create(NETADDR bindaddr) NETSOCKET net_udp_create(NETADDR bindaddr, int use_random_port)
{ {
NETSOCKET sock = invalid_socket; NETSOCKET sock = invalid_socket;
NETADDR tmpbindaddr = bindaddr; NETADDR tmpbindaddr = bindaddr;
@ -918,7 +1000,7 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
/* bind, we should check for error */ /* bind, we should check for error */
tmpbindaddr.type = NETTYPE_IPV4; tmpbindaddr.type = NETTYPE_IPV4;
netaddr_to_sockaddr_in(&tmpbindaddr, &addr); netaddr_to_sockaddr_in(&tmpbindaddr, &addr);
socket = priv_net_create_socket(AF_INET, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr)); socket = priv_net_create_socket(AF_INET, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr), use_random_port);
if(socket >= 0) if(socket >= 0)
{ {
sock.type |= NETTYPE_IPV4; sock.type |= NETTYPE_IPV4;
@ -940,7 +1022,7 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
/* bind, we should check for error */ /* bind, we should check for error */
tmpbindaddr.type = NETTYPE_IPV6; tmpbindaddr.type = NETTYPE_IPV6;
netaddr_to_sockaddr_in6(&tmpbindaddr, &addr); netaddr_to_sockaddr_in6(&tmpbindaddr, &addr);
socket = priv_net_create_socket(AF_INET6, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr)); socket = priv_net_create_socket(AF_INET6, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr), use_random_port);
if(socket >= 0) if(socket >= 0)
{ {
sock.type |= NETTYPE_IPV6; sock.type |= NETTYPE_IPV6;
@ -1077,7 +1159,7 @@ NETSOCKET net_tcp_create(NETADDR bindaddr)
/* bind, we should check for error */ /* bind, we should check for error */
tmpbindaddr.type = NETTYPE_IPV4; tmpbindaddr.type = NETTYPE_IPV4;
netaddr_to_sockaddr_in(&tmpbindaddr, &addr); netaddr_to_sockaddr_in(&tmpbindaddr, &addr);
socket = priv_net_create_socket(AF_INET, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr)); socket = priv_net_create_socket(AF_INET, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), 0);
if(socket >= 0) if(socket >= 0)
{ {
sock.type |= NETTYPE_IPV4; sock.type |= NETTYPE_IPV4;
@ -1093,7 +1175,7 @@ NETSOCKET net_tcp_create(NETADDR bindaddr)
/* bind, we should check for error */ /* bind, we should check for error */
tmpbindaddr.type = NETTYPE_IPV6; tmpbindaddr.type = NETTYPE_IPV6;
netaddr_to_sockaddr_in6(&tmpbindaddr, &addr); netaddr_to_sockaddr_in6(&tmpbindaddr, &addr);
socket = priv_net_create_socket(AF_INET6, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr)); socket = priv_net_create_socket(AF_INET6, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), 0);
if(socket >= 0) if(socket >= 0)
{ {
sock.type |= NETTYPE_IPV6; sock.type |= NETTYPE_IPV6;
@ -1357,19 +1439,46 @@ int fs_storage_path(const char *appname, char *path, int max)
return 0; return 0;
#else #else
char *home = getenv("HOME"); char *home = getenv("HOME");
#if !defined(CONF_PLATFORM_MACOSX)
int i;
#endif
if(!home) if(!home)
return -1; return -1;
#if defined(CONF_PLATFORM_MACOSX) #if defined(CONF_PLATFORM_MACOSX)
snprintf(path, max, "%s/Library/Application Support/%s", home, appname); snprintf(path, max, "%s/Library/Application Support/%s", home, appname);
#else return 0;
#endif
int i;
char *xdgdatahome = getenv("XDG_DATA_HOME");
char xdgpath[max];
/* old folder location */
snprintf(path, max, "%s/.%s", home, appname); snprintf(path, max, "%s/.%s", home, appname);
for(i = strlen(home)+2; path[i]; i++) for(i = strlen(home)+2; path[i]; i++)
path[i] = tolower(path[i]); path[i] = tolower(path[i]);
#endif
if(!xdgdatahome)
{
/* use default location */
snprintf(xdgpath, max, "%s/.local/share/%s", home, appname);
for(i = strlen(home)+14; xdgpath[i]; i++)
xdgpath[i] = tolower(xdgpath[i]);
}
else
{
snprintf(xdgpath, max, "%s/%s", xdgdatahome, appname);
for(i = strlen(xdgdatahome)+1; xdgpath[i]; i++)
xdgpath[i] = tolower(xdgpath[i]);
}
/* check for old location / backward compatibility */
if(fs_is_dir(path))
{
/* use old folder path */
/* for backward compatibility */
return 0;
}
snprintf(path, max, "%s", xdgpath);
return 0; return 0;
#endif #endif
@ -1549,6 +1658,18 @@ int time_houroftheday()
return time_info->tm_hour; return time_info->tm_hour;
} }
int time_isxmasday()
{
time_t time_data;
struct tm *time_info;
time(&time_data);
time_info = localtime(&time_data);
if(time_info->tm_mon == 11 && time_info->tm_mday >= 24 && time_info->tm_mday <= 26)
return 1;
return 0;
}
void str_append(char *dst, const char *src, int dst_size) void str_append(char *dst, const char *src, int dst_size)
{ {
int s = strlen(dst); int s = strlen(dst);
@ -1847,58 +1968,11 @@ int mem_comp(const void *a, const void *b, int size)
return memcmp(a,b,size); return memcmp(a,b,size);
} }
const MEMSTATS *mem_stats()
{
return &memory_stats;
}
void net_stats(NETSTATS *stats_inout) void net_stats(NETSTATS *stats_inout)
{ {
*stats_inout = network_stats; *stats_inout = network_stats;
} }
void gui_messagebox(const char *title, const char *message)
{
#if defined(CONF_PLATFORM_MACOSX)
DialogRef theItem;
DialogItemIndex itemIndex;
/* FIXME: really needed? can we rely on glfw? */
/* HACK - get events without a bundle */
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
TransformProcessType(&psn,kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
/* END HACK */
CreateStandardAlert(kAlertStopAlert,
CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII),
CFStringCreateWithCString(NULL, message, kCFStringEncodingASCII),
NULL,
&theItem);
RunStandardAlert(theItem, NULL, &itemIndex);
#elif defined(CONF_FAMILY_UNIX)
static char cmd[1024];
int err;
/* use xmessage which is available on nearly every X11 system */
snprintf(cmd, sizeof(cmd), "xmessage -center -title '%s' '%s'",
title,
message);
err = system(cmd);
dbg_msg("gui/msgbox", "result = %i", err);
#elif defined(CONF_FAMILY_WINDOWS)
MessageBox(NULL,
message,
title,
MB_ICONEXCLAMATION | MB_OK);
#else
/* this is not critical */
#warning not implemented
#endif
}
int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; } int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; }
char str_uppercase(char c) char str_uppercase(char c)
@ -2030,24 +2104,24 @@ int str_utf8_decode(const char **ptr)
} }
else if((*buf&0xE0) == 0xC0) /* 110xxxxx */ else if((*buf&0xE0) == 0xC0) /* 110xxxxx */
{ {
ch = (*buf++ & 0x3F) << 6; if(!(*buf)) break; ch = (*buf++ & 0x3F) << 6; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F); ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1; if(ch < 0x80 || ch > 0x7FF) ch = -1;
} }
else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */ else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */
{ {
ch = (*buf++ & 0x1F) << 12; if(!(*buf)) break; ch = (*buf++ & 0x1F) << 12; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break; ch += (*buf++ & 0x3F) << 6; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F); ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1; if(ch < 0x800 || ch > 0xFFFF) ch = -1;
} }
else if((*buf & 0xF8) == 0xF0) /* 11110xxx */ else if((*buf & 0xF8) == 0xF0) /* 11110xxx */
{ {
ch = (*buf++ & 0x0F) << 18; if(!(*buf)) break; ch = (*buf++ & 0x0F) << 18; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F) << 12; if(!(*buf)) break; ch += (*buf++ & 0x3F) << 12; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break; ch += (*buf++ & 0x3F) << 6; if(!(*buf) || (*buf&0xC0) != 0x80) break;
ch += (*buf++ & 0x3F); ch += (*buf++ & 0x3F);
if(ch == 0) ch = -1; if(ch < 0x10000 || ch > 0x10FFFF) ch = -1;
} }
else else
{ {
@ -2093,6 +2167,69 @@ unsigned str_quickhash(const char *str)
return hash; return hash;
} }
struct SECURE_RANDOM_DATA
{
int initialized;
#if defined(CONF_FAMILY_WINDOWS)
HCRYPTPROV provider;
#else
IOHANDLE urandom;
#endif
};
static struct SECURE_RANDOM_DATA secure_random_data = { 0 };
int secure_random_init()
{
if(secure_random_data.initialized)
{
return 0;
}
#if defined(CONF_FAMILY_WINDOWS)
if(CryptAcquireContext(&secure_random_data.provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
secure_random_data.initialized = 1;
return 0;
}
else
{
return 1;
}
#else
secure_random_data.urandom = io_open("/dev/urandom", IOFLAG_READ);
if(secure_random_data.urandom)
{
secure_random_data.initialized = 1;
return 0;
}
else
{
return 1;
}
#endif
}
void secure_random_fill(void *bytes, unsigned length)
{
if(!secure_random_data.initialized)
{
dbg_msg("secure", "called secure_random_fill before secure_random_init");
dbg_break();
}
#if defined(CONF_FAMILY_WINDOWS)
if(!CryptGenRandom(secure_random_data.provider, length, bytes))
{
dbg_msg("secure", "CryptGenRandom failed, last_error=%d", GetLastError());
dbg_break();
}
#else
if(length != io_read(secure_random_data.urandom, bytes, length))
{
dbg_msg("secure", "io_read returned with a short read");
dbg_break();
}
#endif
}
#if defined(__cplusplus) #if defined(__cplusplus)
} }

View file

@ -170,14 +170,6 @@ void mem_zero(void *block, unsigned size);
*/ */
int mem_comp(const void *a, const void *b, int size); int mem_comp(const void *a, const void *b, int size);
/*
Function: mem_check
Validates the heap
Will trigger a assert if memory has failed.
*/
int mem_check_imp();
#define mem_check() dbg_assert_imp(__FILE__, __LINE__, mem_check_imp(), "Memory check failed")
/* Group: File IO */ /* Group: File IO */
enum { enum {
IOFLAG_READ = 1, IOFLAG_READ = 1,
@ -475,6 +467,16 @@ int time_timestamp();
*/ */
int time_houroftheday(); int time_houroftheday();
/*
Function: time_isxmasday
Checks if it's xmas
Returns:
1 - if it's a xmas day
0 - if not
*/
int time_isxmasday();
/* Group: Network General */ /* Group: Network General */
typedef struct typedef struct
{ {
@ -576,12 +578,13 @@ int net_addr_from_str(NETADDR *addr, const char *string);
Parameters: Parameters:
bindaddr - Address to bind the socket to. bindaddr - Address to bind the socket to.
use_random_port - use a random port
Returns: Returns:
On success it returns an handle to the socket. On failure it On success it returns an handle to the socket. On failure it
returns NETSOCKET_INVALID. returns NETSOCKET_INVALID.
*/ */
NETSOCKET net_udp_create(NETADDR bindaddr); NETSOCKET net_udp_create(NETADDR bindaddr, int use_random_port);
/* /*
Function: net_udp_send Function: net_udp_send
@ -1202,8 +1205,6 @@ int net_would_block();
int net_socket_read_wait(NETSOCKET sock, int time); int net_socket_read_wait(NETSOCKET sock, int time);
void mem_debug_dump(IOHANDLE file);
void swap_endian(void *data, unsigned elem_size, unsigned num); void swap_endian(void *data, unsigned elem_size, unsigned num);
@ -1214,15 +1215,6 @@ void dbg_logger_stdout();
void dbg_logger_debugger(); void dbg_logger_debugger();
void dbg_logger_file(const char *filename); void dbg_logger_file(const char *filename);
typedef struct
{
int allocated;
int active_allocations;
int total_allocations;
} MEMSTATS;
const MEMSTATS *mem_stats();
typedef struct typedef struct
{ {
int sent_packets; int sent_packets;
@ -1240,16 +1232,6 @@ int str_isspace(char c);
char str_uppercase(char c); char str_uppercase(char c);
unsigned str_quickhash(const char *str); unsigned str_quickhash(const char *str);
/*
Function: gui_messagebox
Display plain OS-dependent message box
Parameters:
title - title of the message box
message - text to display
*/
void gui_messagebox(const char *title, const char *message);
char *str_utf8_skip_whitespaces(char *str); char *str_utf8_skip_whitespaces(char *str);
/* /*
@ -1330,6 +1312,27 @@ int str_utf8_encode(char *ptr, int chr);
*/ */
int str_utf8_check(const char *str); int str_utf8_check(const char *str);
/*
Function: secure_random_init
Initializes the secure random module.
You *MUST* check the return value of this function.
Returns:
0 - Initialization succeeded.
1 - Initialization failed.
*/
int secure_random_init();
/*
Function: secure_random_fill
Fills the buffer with the specified amount of random bytes.
Parameters:
bytes - Pointer to the start of the buffer.
length - Length of the buffer.
*/
void secure_random_fill(void *bytes, unsigned length);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -35,7 +35,9 @@
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h> #include <windows.h>
inline unsigned atomic_inc(volatile unsigned *pValue) inline unsigned atomic_inc(volatile unsigned *pValue)

View file

@ -17,7 +17,7 @@ public:
union { T y,v; }; union { T y,v; };
vector2_base() {} vector2_base() {}
vector2_base(float nx, float ny) vector2_base(T nx, T ny)
{ {
x = nx; x = nx;
y = ny; y = ny;
@ -119,7 +119,7 @@ public:
union { T z,b,v,l; }; union { T z,b,v,l; };
vector3_base() {} vector3_base() {}
vector3_base(float nx, float ny, float nz) vector3_base(T nx, T ny, T nz)
{ {
x = nx; x = nx;
y = ny; y = ny;
@ -198,7 +198,7 @@ public:
union { T w,a; }; union { T w,a; };
vector4_base() {} vector4_base() {}
vector4_base(float nx, float ny, float nz, float nw) vector4_base(T nx, T ny, T nz, T nw)
{ {
x = nx; x = nx;
y = ny; y = ny;

View file

@ -88,10 +88,17 @@ public:
virtual void AutoScreenshot_Start() = 0; virtual void AutoScreenshot_Start() = 0;
virtual void ServerBrowserUpdate() = 0; virtual void ServerBrowserUpdate() = 0;
// gfx
virtual void SwitchWindowScreen(int Index) = 0;
virtual void ToggleFullscreen() = 0;
virtual void ToggleWindowBordered() = 0;
virtual void ToggleWindowVSync() = 0;
// networking // networking
virtual void EnterGame() = 0; virtual void EnterGame() = 0;
// //
virtual const char *MapDownloadName() const = 0;
virtual int MapDownloadAmount() const = 0; virtual int MapDownloadAmount() const = 0;
virtual int MapDownloadTotalsize() const = 0; virtual int MapDownloadTotalsize() const = 0;
@ -160,6 +167,7 @@ public:
virtual void OnEnterGame() = 0; virtual void OnEnterGame() = 0;
virtual void OnShutdown() = 0; virtual void OnShutdown() = 0;
virtual void OnRender() = 0; virtual void OnRender() = 0;
virtual void OnUpdate() = 0;
virtual void OnStateChange(int NewState, int OldState) = 0; virtual void OnStateChange(int NewState, int OldState) = 0;
virtual void OnConnected() = 0; virtual void OnConnected() = 0;
virtual void OnMessage(int MsgID, CUnpacker *pUnpacker) = 0; virtual void OnMessage(int MsgID, CUnpacker *pUnpacker) = 0;
@ -171,6 +179,7 @@ public:
virtual const char *GetItemName(int Type) const = 0; virtual const char *GetItemName(int Type) const = 0;
virtual const char *Version() const = 0; virtual const char *Version() const = 0;
virtual const char *NetVersion() const = 0; virtual const char *NetVersion() const = 0;
virtual int ClientVersion() const = 0;
}; };

View file

@ -12,9 +12,13 @@
#include "graphics_threaded.h" #include "graphics_threaded.h"
#include "backend_sdl.h" #include "backend_sdl.h"
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
PFNGLTEXIMAGE3DPROC glTexImage3D; PFNGLTEXIMAGE3DPROC glTexImage3DInternal;
GLAPI void APIENTRY glTexImage3D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
{
glTexImage3DInternal(target, level, internalFormat, width, height, depth, border, format, type, pixels);
}
#endif #endif
// ------------ CGraphicsBackend_Threaded // ------------ CGraphicsBackend_Threaded
@ -171,7 +175,7 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
else if(State.m_Dimension == 3 && (m_aTextures[State.m_Texture].m_State&CTexture::STATE_TEX3D)) else if(State.m_Dimension == 3 && (m_aTextures[State.m_Texture].m_State&CTexture::STATE_TEX3D))
{ {
glEnable(GL_TEXTURE_3D); glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex3D); glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex3D[State.m_TextureArrayIndex]);
} }
else else
dbg_msg("render", "invalid texture %d %d %d\n", State.m_Texture, State.m_Dimension, m_aTextures[State.m_Texture].m_State); dbg_msg("render", "invalid texture %d %d %d\n", State.m_Texture, State.m_Dimension, m_aTextures[State.m_Texture].m_State);
@ -244,6 +248,13 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St
void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand) void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand)
{ {
m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage; m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize);
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &m_Max3DTexSize);
dbg_msg("render", "opengl max texture sizes: %d, %d(3D)", m_MaxTexSize, m_Max3DTexSize);
if(m_Max3DTexSize < IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION)
dbg_msg("render", "*** warning *** max 3D texture size is too low - using the fallback system");
m_TextureArraySize = IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION / min(m_Max3DTexSize, IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION);
*pCommand->m_pTextureArraySize = m_TextureArraySize;
} }
void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
@ -262,7 +273,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer:
if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX2D) if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX2D)
glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex2D); glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex2D);
if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX3D) if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX3D)
glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D); glDeleteTextures(m_TextureArraySize, m_aTextures[pCommand->m_Slot].m_Tex3D);
*m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize; *m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize;
m_aTextures[pCommand->m_Slot].m_State = CTexture::STATE_EMPTY; m_aTextures[pCommand->m_Slot].m_State = CTexture::STATE_EMPTY;
m_aTextures[pCommand->m_Slot].m_MemSize = 0; m_aTextures[pCommand->m_Slot].m_MemSize = 0;
@ -278,16 +289,13 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
// resample if needed // resample if needed
if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB) if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB)
{ {
int MaxTexSize; int MaxTexSize = m_MaxTexSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTexSize); if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE)
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D)
{ {
int Max3DTexSize;
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &Max3DTexSize);
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE2D) if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE2D)
MaxTexSize = min(MaxTexSize, Max3DTexSize*16); MaxTexSize = min(MaxTexSize, m_Max3DTexSize * IGraphics::NUMTILES_DIMENSION);
else else
MaxTexSize = Max3DTexSize*16; MaxTexSize = m_Max3DTexSize * IGraphics::NUMTILES_DIMENSION;
} }
if(Width > MaxTexSize || Height > MaxTexSize) if(Width > MaxTexSize || Height > MaxTexSize)
{ {
@ -302,7 +310,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
mem_free(pTexData); mem_free(pTexData);
pTexData = pTmpData; pTexData = pTmpData;
} }
else if(Width > 16 && Height > 16 && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0) else if(Width > IGraphics::NUMTILES_DIMENSION && Height > IGraphics::NUMTILES_DIMENSION && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0)
{ {
Width>>=1; Width>>=1;
Height>>=1; Height>>=1;
@ -357,6 +365,9 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
else else
{ {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if(pCommand->m_Flags&CCommandBuffer::TEXTFLAG_LINEARMIPMAPS)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData); gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData);
} }
@ -374,43 +385,46 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
} }
// 3D texture // 3D texture
if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE)
{ {
Width /= 16; Width /= IGraphics::NUMTILES_DIMENSION;
Height /= 16; Height /= IGraphics::NUMTILES_DIMENSION;
Depth = 256; Depth = min(m_Max3DTexSize, IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION);
// copy and reorder texture data // copy and reorder texture data
int MemSize = Width*Height*Depth*pCommand->m_PixelSize; int MemSize = Width*Height*IGraphics::NUMTILES_DIMENSION*IGraphics::NUMTILES_DIMENSION*pCommand->m_PixelSize;
char *pTmpData = (char *)mem_alloc(MemSize, sizeof(void*)); char *pTmpData = (char *)mem_alloc(MemSize, sizeof(void*));
const int TileSize = (Height * Width) * pCommand->m_PixelSize; const int TileSize = (Height * Width) * pCommand->m_PixelSize;
const int TileRowSize = Width * pCommand->m_PixelSize; const int TileRowSize = Width * pCommand->m_PixelSize;
const int ImagePitch = Width*16 * pCommand->m_PixelSize; const int ImagePitch = Width * IGraphics::NUMTILES_DIMENSION * pCommand->m_PixelSize;
mem_zero(pTmpData, MemSize); mem_zero(pTmpData, MemSize);
for(int i = 0; i < 256; i++) for(int i = 0; i < IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION; i++)
{ {
const int px = (i%16) * Width; const int px = (i%IGraphics::NUMTILES_DIMENSION) * Width;
const int py = (i/16) * Height; const int py = (i/IGraphics::NUMTILES_DIMENSION) * Height;
const char *pTileData = (const char *)pTexData + (py * Width*16 + px) * pCommand->m_PixelSize; const char *pTileData = (const char *)pTexData + (py * Width * IGraphics::NUMTILES_DIMENSION + px) * pCommand->m_PixelSize;
for(int y = 0; y < Height; y++) for(int y = 0; y < Height; y++)
mem_copy(pTmpData + i*TileSize + y*TileRowSize, pTileData + y * ImagePitch, TileRowSize); mem_copy(pTmpData + i*TileSize + y*TileRowSize, pTileData + y * ImagePitch, TileRowSize);
} }
mem_free(pTexData); mem_free(pTexData);
pTexData = pTmpData;
// //
glGenTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D); glGenTextures(m_TextureArraySize, m_aTextures[pCommand->m_Slot].m_Tex3D);
m_aTextures[pCommand->m_Slot].m_State |= CTexture::STATE_TEX3D; m_aTextures[pCommand->m_Slot].m_State |= CTexture::STATE_TEX3D;
glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D); for(int i = 0; i < m_TextureArraySize; ++i)
{
glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D[i]);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
pTexData = pTmpData+i*(Width*Height*Depth*pCommand->m_PixelSize);
glTexImage3D(GL_TEXTURE_3D, 0, StoreOglformat, Width, Height, Depth, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); glTexImage3D(GL_TEXTURE_3D, 0, StoreOglformat, Width, Height, Depth, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize; m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize;
} }
pTexData = pTmpData;
}
*m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize; *m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize;
@ -453,8 +467,10 @@ void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCom
GLint aViewport[4] = {0,0,0,0}; GLint aViewport[4] = {0,0,0,0};
glGetIntegerv(GL_VIEWPORT, aViewport); glGetIntegerv(GL_VIEWPORT, aViewport);
int w = aViewport[2]; int w = pCommand->m_W == -1 ? aViewport[2] : pCommand->m_W;
int h = aViewport[3]; int h = pCommand->m_H == -1 ? aViewport[3] : pCommand->m_H;
int x = pCommand->m_X;
int y = aViewport[3] - pCommand->m_Y - 1 - (h - 1);
// we allocate one more row to use when we are flipping the texture // we allocate one more row to use when we are flipping the texture
unsigned char *pPixelData = (unsigned char *)mem_alloc(w*(h+1)*3, 1); unsigned char *pPixelData = (unsigned char *)mem_alloc(w*(h+1)*3, 1);
@ -464,15 +480,15 @@ void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCom
GLint Alignment; GLint Alignment;
glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment);
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData);
glPixelStorei(GL_PACK_ALIGNMENT, Alignment); glPixelStorei(GL_PACK_ALIGNMENT, Alignment);
// flip the pixel because opengl works from bottom left corner // flip the pixel because opengl works from bottom left corner
for(int y = 0; y < h/2; y++) for(int ty = 0; ty < h/2; ty++)
{ {
mem_copy(pTempRow, pPixelData+y*w*3, w*3); mem_copy(pTempRow, pPixelData+ty*w*3, w*3);
mem_copy(pPixelData+y*w*3, pPixelData+(h-y-1)*w*3, w*3); mem_copy(pPixelData+ty*w*3, pPixelData+(h-ty-1)*w*3, w*3);
mem_copy(pPixelData+(h-y-1)*w*3, pTempRow,w*3); mem_copy(pPixelData+(h-ty-1)*w*3, pTempRow,w*3);
} }
// fill in the information // fill in the information
@ -539,6 +555,11 @@ void CCommandProcessorFragment_SDL::Cmd_Swap(const CCommandBuffer::SCommand_Swap
glFinish(); glFinish();
} }
void CCommandProcessorFragment_SDL::Cmd_VSync(const CCommandBuffer::SCommand_VSync *pCommand)
{
*pCommand->m_pRetOk = SDL_GL_SetSwapInterval(pCommand->m_VSync) == 0;
}
void CCommandProcessorFragment_SDL::Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand) void CCommandProcessorFragment_SDL::Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand)
{ {
SDL_DisplayMode mode; SDL_DisplayMode mode;
@ -584,6 +605,7 @@ bool CCommandProcessorFragment_SDL::RunCommand(const CCommandBuffer::SCommand *p
switch(pBaseCommand->m_Cmd) switch(pBaseCommand->m_Cmd)
{ {
case CCommandBuffer::CMD_SWAP: Cmd_Swap(static_cast<const CCommandBuffer::SCommand_Swap *>(pBaseCommand)); break; case CCommandBuffer::CMD_SWAP: Cmd_Swap(static_cast<const CCommandBuffer::SCommand_Swap *>(pBaseCommand)); break;
case CCommandBuffer::CMD_VSYNC: Cmd_VSync(static_cast<const CCommandBuffer::SCommand_VSync *>(pBaseCommand)); break;
case CCommandBuffer::CMD_VIDEOMODES: Cmd_VideoModes(static_cast<const CCommandBuffer::SCommand_VideoModes *>(pBaseCommand)); break; case CCommandBuffer::CMD_VIDEOMODES: Cmd_VideoModes(static_cast<const CCommandBuffer::SCommand_VideoModes *>(pBaseCommand)); break;
case CMD_INIT: Cmd_Init(static_cast<const SCommand_Init *>(pBaseCommand)); break; case CMD_INIT: Cmd_Init(static_cast<const SCommand_Init *>(pBaseCommand)); break;
case CMD_SHUTDOWN: Cmd_Shutdown(static_cast<const SCommand_Shutdown *>(pBaseCommand)); break; case CMD_SHUTDOWN: Cmd_Shutdown(static_cast<const SCommand_Shutdown *>(pBaseCommand)); break;
@ -619,7 +641,7 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer)
// ------------ CGraphicsBackend_SDL_OpenGL // ------------ CGraphicsBackend_SDL_OpenGL
int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight) int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight)
{ {
if(!SDL_WasInit(SDL_INIT_VIDEO)) if(!SDL_WasInit(SDL_INIT_VIDEO))
{ {
@ -628,34 +650,43 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
dbg_msg("gfx", "unable to init SDL video: %s", SDL_GetError()); dbg_msg("gfx", "unable to init SDL video: %s", SDL_GetError());
return -1; return -1;
} }
#ifdef CONF_FAMILY_WINDOWS
if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention
putenv("SDL_VIDEO_WINDOW_POS=center"); // ignore_convention
#endif
} }
SDL_Rect ScreenBounds; // set screen
if(SDL_GetDisplayBounds(Screen, &ScreenBounds) < 0) SDL_Rect ScreenPos;
m_NumScreens = SDL_GetNumVideoDisplays();
if(m_NumScreens > 0)
{ {
dbg_msg("gfx", "unable to get current screen bounds: %s", SDL_GetError()); clamp(*Screen, 0, m_NumScreens-1);
if(SDL_GetDisplayBounds(*Screen, &ScreenPos) != 0)
{
dbg_msg("gfx", "unable to retrieve screen information: %s", SDL_GetError());
return -1; return -1;
} }
// use current resolution as default }
if(*pWidth == 0 || *pHeight == 0) else
{ {
*pWidth = ScreenBounds.w; dbg_msg("gfx", "unable to retrieve number of screens: %s", SDL_GetError());
*pHeight = ScreenBounds.h; return -1;
} }
// store desktop resolution for settings reset button // store desktop resolution for settings reset button
*pDesktopWidth = ScreenBounds.w; SDL_DisplayMode DisplayMode;
*pDesktopHeight = ScreenBounds.h; if(SDL_GetDesktopDisplayMode(*Screen, &DisplayMode))
{
dbg_msg("gfx", "unable to get desktop resolution: %s", SDL_GetError());
return -1;
}
*pDesktopWidth = DisplayMode.w;
*pDesktopHeight = DisplayMode.h;
dbg_assert(!(Flags&IGraphicsBackend::INITFLAG_BORDERLESS) // use desktop resolution as default resolution
|| !(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN), if (*pWidth == 0 || *pWidth == 0)
"only one of borderless and fullscreen may be activated at the same time"); {
*pWidth = *pDesktopWidth;
*pHeight = *pDesktopHeight;
}
// set flags // set flags
int SdlFlags = SDL_WINDOW_OPENGL; int SdlFlags = SDL_WINDOW_OPENGL;
@ -664,11 +695,13 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
if(Flags&IGraphicsBackend::INITFLAG_BORDERLESS) if(Flags&IGraphicsBackend::INITFLAG_BORDERLESS)
SdlFlags |= SDL_WINDOW_BORDERLESS; SdlFlags |= SDL_WINDOW_BORDERLESS;
if(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN) if(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN)
#if defined(CONF_FAMILY_WINDOWS) || defined(CONF_PLATFORM_MACOSX) #if defined(CONF_PLATFORM_MACOSX) // Todo SDL: remove this when fixed (game freezes when losing focus in fullscreen)
SdlFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; // always use "fake" fullscreen
*pWidth = *pDesktopWidth;
*pHeight = *pDesktopHeight;
#else
SdlFlags |= SDL_WINDOW_FULLSCREEN; SdlFlags |= SDL_WINDOW_FULLSCREEN;
#else #endif
SdlFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
#endif
// set gl attributes // set gl attributes
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
@ -683,14 +716,17 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
} }
m_pWindow = SDL_CreateWindow( // calculate centered position in windowed mode
pName, int OffsetX = 0;
SDL_WINDOWPOS_UNDEFINED_DISPLAY(0), int OffsetY = 0;
SDL_WINDOWPOS_UNDEFINED_DISPLAY(0), if(!(Flags&IGraphicsBackend::INITFLAG_FULLSCREEN) && *pDesktopWidth > *pWidth && *pDesktopHeight > *pHeight)
*pWidth, {
*pHeight, OffsetX = (*pDesktopWidth - *pWidth) / 2;
SdlFlags); OffsetY = (*pDesktopHeight - *pHeight) / 2;
}
// create window
m_pWindow = SDL_CreateWindow(pName, ScreenPos.x+OffsetX, ScreenPos.y+OffsetY, *pWidth, *pHeight, SdlFlags);
if(m_pWindow == NULL) if(m_pWindow == NULL)
{ {
dbg_msg("gfx", "unable to create window: %s", SDL_GetError()); dbg_msg("gfx", "unable to create window: %s", SDL_GetError());
@ -699,8 +735,8 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
SDL_GetWindowSize(m_pWindow, pWidth, pHeight); SDL_GetWindowSize(m_pWindow, pWidth, pHeight);
// create gl context
m_GLContext = SDL_GL_CreateContext(m_pWindow); m_GLContext = SDL_GL_CreateContext(m_pWindow);
if(m_GLContext == NULL) if(m_GLContext == NULL)
{ {
dbg_msg("gfx", "unable to create OpenGL context: %s", SDL_GetError()); dbg_msg("gfx", "unable to create OpenGL context: %s", SDL_GetError());
@ -708,8 +744,8 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
} }
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
glTexImage3D = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D"); glTexImage3DInternal = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D");
if(glTexImage3D == 0) if(glTexImage3DInternal == 0)
{ {
dbg_msg("gfx", "glTexImage3D not supported"); dbg_msg("gfx", "glTexImage3D not supported");
return -1; return -1;
@ -726,13 +762,14 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int Screen, int *pWidth
// issue init commands for OpenGL and SDL // issue init commands for OpenGL and SDL
CCommandBuffer CmdBuffer(1024, 512); CCommandBuffer CmdBuffer(1024, 512);
CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL;
CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage;
CmdBuffer.AddCommand(CmdOpenGL);
CCommandProcessorFragment_SDL::SCommand_Init CmdSDL; CCommandProcessorFragment_SDL::SCommand_Init CmdSDL;
CmdSDL.m_pWindow = m_pWindow; CmdSDL.m_pWindow = m_pWindow;
CmdSDL.m_GLContext = m_GLContext; CmdSDL.m_GLContext = m_GLContext;
CmdBuffer.AddCommand(CmdSDL); CmdBuffer.AddCommand(CmdSDL);
CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL;
CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage;
CmdOpenGL.m_pTextureArraySize = &m_TextureArraySize;
CmdBuffer.AddCommand(CmdOpenGL);
RunBuffer(&CmdBuffer); RunBuffer(&CmdBuffer);
WaitForIdle(); WaitForIdle();
@ -772,7 +809,41 @@ void CGraphicsBackend_SDL_OpenGL::Minimize()
void CGraphicsBackend_SDL_OpenGL::Maximize() void CGraphicsBackend_SDL_OpenGL::Maximize()
{ {
// TODO: SDL SDL_MaximizeWindow(m_pWindow);
}
bool CGraphicsBackend_SDL_OpenGL::Fullscreen(bool State)
{
#if defined(CONF_PLATFORM_MACOSX) // Todo SDL: remove this when fixed (game freezes when losing focus in fullscreen)
return SDL_SetWindowFullscreen(m_pWindow, State ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0) == 0;
#else
return SDL_SetWindowFullscreen(m_pWindow, State ? SDL_WINDOW_FULLSCREEN : 0) == 0;
#endif
}
void CGraphicsBackend_SDL_OpenGL::SetWindowBordered(bool State)
{
SDL_SetWindowBordered(m_pWindow, SDL_bool(State));
}
bool CGraphicsBackend_SDL_OpenGL::SetWindowScreen(int Index)
{
if(Index >= 0 && Index < m_NumScreens)
{
SDL_Rect ScreenPos;
if(SDL_GetDisplayBounds(Index, &ScreenPos) == 0)
{
SDL_SetWindowPosition(m_pWindow, ScreenPos.x, ScreenPos.y);
return true;
}
}
return false;
}
int CGraphicsBackend_SDL_OpenGL::GetWindowScreen()
{
return SDL_GetWindowDisplayIndex(m_pWindow);
} }
int CGraphicsBackend_SDL_OpenGL::WindowActive() int CGraphicsBackend_SDL_OpenGL::WindowActive()

View file

@ -91,15 +91,21 @@ class CCommandProcessorFragment_OpenGL
STATE_EMPTY = 0, STATE_EMPTY = 0,
STATE_TEX2D = 1, STATE_TEX2D = 1,
STATE_TEX3D = 2, STATE_TEX3D = 2,
MIN_GL_MAX_3D_TEXTURE_SIZE = 64, // GL_MAX_3D_TEXTURE_SIZE must be at least 64 according to the standard
MAX_ARRAYSIZE_TEX3D = IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION / MIN_GL_MAX_3D_TEXTURE_SIZE, // = 4
}; };
GLuint m_Tex2D; GLuint m_Tex2D;
GLuint m_Tex3D; GLuint m_Tex3D[MAX_ARRAYSIZE_TEX3D];
int m_State; int m_State;
int m_Format; int m_Format;
int m_MemSize; int m_MemSize;
}; };
CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES]; CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES];
volatile int *m_pTextureMemoryUsage; volatile int *m_pTextureMemoryUsage;
int m_MaxTexSize;
int m_Max3DTexSize;
int m_TextureArraySize;
public: public:
enum enum
@ -111,6 +117,7 @@ public:
{ {
SCommand_Init() : SCommand(CMD_INIT) {} SCommand_Init() : SCommand(CMD_INIT) {}
volatile int *m_pTextureMemoryUsage; volatile int *m_pTextureMemoryUsage;
int *m_pTextureArraySize;
}; };
private: private:
@ -163,6 +170,7 @@ private:
void Cmd_Init(const SCommand_Init *pCommand); void Cmd_Init(const SCommand_Init *pCommand);
void Cmd_Shutdown(const SCommand_Shutdown *pCommand); void Cmd_Shutdown(const SCommand_Shutdown *pCommand);
void Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand); void Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand);
void Cmd_VSync(const CCommandBuffer::SCommand_VSync *pCommand);
void Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand); void Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand);
public: public:
CCommandProcessorFragment_SDL(); CCommandProcessorFragment_SDL();
@ -187,14 +195,23 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
SDL_GLContext m_GLContext; SDL_GLContext m_GLContext;
ICommandProcessor *m_pProcessor; ICommandProcessor *m_pProcessor;
volatile int m_TextureMemoryUsage; volatile int m_TextureMemoryUsage;
int m_NumScreens;
int m_TextureArraySize;
public: public:
virtual int Init(const char *pName, int Screen, int *Width, int *Height, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight); virtual int Init(const char *pName, int *Screen, int *Width, int *Height, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight);
virtual int Shutdown(); virtual int Shutdown();
virtual int MemoryUsage() const; virtual int MemoryUsage() const;
virtual int GetTextureArraySize() const { return m_TextureArraySize; }
virtual int GetNumScreens() const { return m_NumScreens; }
virtual void Minimize(); virtual void Minimize();
virtual void Maximize(); virtual void Maximize();
virtual bool Fullscreen(bool State); // on=true/off=false
virtual void SetWindowBordered(bool State); // on=true/off=false
virtual bool SetWindowScreen(int Index);
virtual int GetWindowScreen();
virtual int WindowActive(); virtual int WindowActive();
virtual int WindowOpen(); virtual int WindowOpen();
}; };

View file

@ -2,6 +2,7 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <new> #include <new>
#include <immintrin.h> //_mm_pause
#include <stdlib.h> // qsort #include <stdlib.h> // qsort
#include <stdarg.h> #include <stdarg.h>
@ -56,15 +57,15 @@
void CGraph::Init(float Min, float Max) void CGraph::Init(float Min, float Max)
{ {
m_Min = Min; m_MinRange = m_Min = Min;
m_Max = Max; m_MaxRange = m_Max = Max;
m_Index = 0; m_Index = 0;
} }
void CGraph::ScaleMax() void CGraph::ScaleMax()
{ {
int i = 0; int i = 0;
m_Max = 0; m_Max = m_MaxRange;
for(i = 0; i < MAX_VALUES; i++) for(i = 0; i < MAX_VALUES; i++)
{ {
if(m_aValues[i] > m_Max) if(m_aValues[i] > m_Max)
@ -75,7 +76,7 @@ void CGraph::ScaleMax()
void CGraph::ScaleMin() void CGraph::ScaleMin()
{ {
int i = 0; int i = 0;
m_Min = m_Max; m_Min = m_MinRange;
for(i = 0; i < MAX_VALUES; i++) for(i = 0; i < MAX_VALUES; i++)
{ {
if(m_aValues[i] < m_Min) if(m_aValues[i] < m_Min)
@ -239,8 +240,7 @@ void CSmoothTime::Update(CGraph *pGraph, int64 Target, int TimeLeft, int AdjustD
UpdateInt(Target); UpdateInt(Target);
} }
CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotDelta), m_pConLinkIdentifier("teeworlds:")
CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotDelta)
{ {
m_pEditor = 0; m_pEditor = 0;
m_pInput = 0; m_pInput = 0;
@ -255,6 +255,8 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD
m_RenderFrameTimeHigh = 0.0f; m_RenderFrameTimeHigh = 0.0f;
m_RenderFrames = 0; m_RenderFrames = 0;
m_LastRenderTime = time_get(); m_LastRenderTime = time_get();
m_LastCpuTime = time_get();
m_LastAvgCpuFrameTime = 0;
m_GameTickSpeed = SERVER_TICK_SPEED; m_GameTickSpeed = SERVER_TICK_SPEED;
@ -290,8 +292,6 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD
m_MapdownloadAmount = -1; m_MapdownloadAmount = -1;
m_MapdownloadTotalsize = -1; m_MapdownloadTotalsize = -1;
m_CurrentServerInfoRequestTime = -1;
m_CurrentInput = 0; m_CurrentInput = 0;
m_State = IClient::STATE_OFFLINE; m_State = IClient::STATE_OFFLINE;
@ -338,6 +338,7 @@ void CClient::SendInfo()
CMsgPacker Msg(NETMSG_INFO, true); CMsgPacker Msg(NETMSG_INFO, true);
Msg.AddString(GameClient()->NetVersion(), 128); Msg.AddString(GameClient()->NetVersion(), 128);
Msg.AddString(g_Config.m_Password, 128); Msg.AddString(g_Config.m_Password, 128);
Msg.AddInt(GameClient()->ClientVersion());
SendMsg(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH); SendMsg(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);
} }
@ -376,20 +377,6 @@ bool CClient::ConnectionProblems() const
return m_NetClient.GotProblems() != 0; return m_NetClient.GotProblems() != 0;
} }
void CClient::DirectInput(int *pInput, int Size)
{
CMsgPacker Msg(NETMSG_INPUT, true);
Msg.AddInt(m_AckGameTick);
Msg.AddInt(m_PredTick);
Msg.AddInt(Size);
for(int i = 0; i < Size/4; i++)
Msg.AddInt(pInput[i]);
SendMsg(&Msg, 0);
}
void CClient::SendInput() void CClient::SendInput()
{ {
int64 Now = time_get(); int64 Now = time_get();
@ -417,6 +404,12 @@ void CClient::SendInput()
for(int i = 0; i < Size/4; i++) for(int i = 0; i < Size/4; i++)
Msg.AddInt(m_aInputs[m_CurrentInput].m_aData[i]); Msg.AddInt(m_aInputs[m_CurrentInput].m_aData[i]);
int PingCorrection = 0;
int64 TagTime;
if(m_SnapshotStorage.Get(m_AckGameTick, &TagTime, 0, 0) >= 0)
PingCorrection = (int)(((Now-TagTime)*1000)/time_freq());
Msg.AddInt(PingCorrection);
m_CurrentInput++; m_CurrentInput++;
m_CurrentInput%=200; m_CurrentInput%=200;
@ -506,7 +499,7 @@ void CClient::Connect(const char *pAddress)
str_format(aBuf, sizeof(aBuf), "connecting to '%s'", m_aServerAddressStr); str_format(aBuf, sizeof(aBuf), "connecting to '%s'", m_aServerAddressStr);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf);
ServerInfoRequest(); mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
if(net_addr_from_str(&m_ServerAddress, m_aServerAddressStr) != 0 && net_host_lookup(m_aServerAddressStr, &m_ServerAddress, m_NetClient.NetType()) != 0) if(net_addr_from_str(&m_ServerAddress, m_aServerAddressStr) != 0 && net_host_lookup(m_aServerAddressStr, &m_ServerAddress, m_NetClient.NetType()) != 0)
{ {
@ -577,12 +570,6 @@ void CClient::GetServerInfo(CServerInfo *pServerInfo) const
mem_copy(pServerInfo, &m_CurrentServerInfo, sizeof(m_CurrentServerInfo)); mem_copy(pServerInfo, &m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
} }
void CClient::ServerInfoRequest()
{
mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo));
m_CurrentServerInfoRequestTime = 0;
}
int CClient::LoadData() int CClient::LoadData()
{ {
m_DebugFont = Graphics()->LoadTexture("ui/debug_font.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, IGraphics::TEXLOAD_NORESAMPLE); m_DebugFont = Graphics()->LoadTexture("ui/debug_font.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, IGraphics::TEXLOAD_NORESAMPLE);
@ -685,10 +672,8 @@ void CClient::DebugRender()
total = 42 total = 42
*/ */
FrameTimeAvg = FrameTimeAvg*0.9f + m_RenderFrameTime*0.1f; FrameTimeAvg = FrameTimeAvg*0.9f + m_RenderFrameTime*0.1f;
str_format(aBuffer, sizeof(aBuffer), "ticks: %8d %8d mem %dk %d gfxmem: %dk fps: %3d", str_format(aBuffer, sizeof(aBuffer), "ticks: %8d %8d gfxmem: %dk fps: %3d",
m_CurGameTick, m_PredTick, m_CurGameTick, m_PredTick,
mem_stats()->allocated/1024,
mem_stats()->total_allocations,
Graphics()->MemoryUsage()/1024, Graphics()->MemoryUsage()/1024,
(int)(1.0f/FrameTimeAvg + 0.5f)); (int)(1.0f/FrameTimeAvg + 0.5f));
Graphics()->QuadsText(2, 2, 16, aBuffer); Graphics()->QuadsText(2, 2, 16, aBuffer);
@ -743,7 +728,11 @@ void CClient::DebugRender()
m_FpsGraph.ScaleMax(); m_FpsGraph.ScaleMax();
m_FpsGraph.ScaleMin(); m_FpsGraph.ScaleMin();
m_FpsGraph.Render(Graphics(), m_DebugFont, x, sp*5, w, h, "FPS"); m_FpsGraph.Render(Graphics(), m_DebugFont, x, sp*5, w, h, "FPS");
m_InputtimeMarginGraph.ScaleMin();
m_InputtimeMarginGraph.ScaleMax();
m_InputtimeMarginGraph.Render(Graphics(), m_DebugFont, x, sp*5+h+sp, w, h, "Prediction Margin"); m_InputtimeMarginGraph.Render(Graphics(), m_DebugFont, x, sp*5+h+sp, w, h, "Prediction Margin");
m_GametimeMarginGraph.ScaleMin();
m_GametimeMarginGraph.ScaleMax();
m_GametimeMarginGraph.Render(Graphics(), m_DebugFont, x, sp*5+h+sp+h+sp, w, h, "Gametime Margin"); m_GametimeMarginGraph.Render(Graphics(), m_DebugFont, x, sp*5+h+sp+h+sp, w, h, "Gametime Margin");
} }
} }
@ -837,9 +826,9 @@ int CClient::PlayerScoreComp(const void *a, const void *b)
{ {
CServerInfo::CClient *p0 = (CServerInfo::CClient *)a; CServerInfo::CClient *p0 = (CServerInfo::CClient *)a;
CServerInfo::CClient *p1 = (CServerInfo::CClient *)b; CServerInfo::CClient *p1 = (CServerInfo::CClient *)b;
if(p0->m_Player && !p1->m_Player) if(!(p0->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC) && (p1->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC))
return -1; return -1;
if(!p0->m_Player && p1->m_Player) if((p0->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC) && !(p1->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC))
return 1; return 1;
if(p0->m_Score == p1->m_Score) if(p0->m_Score == p1->m_Score)
return 0; return 0;
@ -848,6 +837,68 @@ int CClient::PlayerScoreComp(const void *a, const void *b)
return -1; return -1;
} }
int CClient::UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pToken)
{
if(pToken)
*pToken = pUnpacker->GetInt();
str_copy(pInfo->m_aVersion, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aVersion));
str_copy(pInfo->m_aName, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aName));
str_clean_whitespaces(pInfo->m_aName);
str_copy(pInfo->m_aHostname, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aHostname));
if(pInfo->m_aHostname[0] == 0)
str_copy(pInfo->m_aHostname, pInfo->m_aAddress, sizeof(pInfo->m_aHostname));
str_copy(pInfo->m_aMap, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aMap));
str_copy(pInfo->m_aGameType, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aGameType));
pInfo->m_Flags = (pUnpacker->GetInt()&SERVERINFO_FLAG_PASSWORD) ? IServerBrowser::FLAG_PASSWORD : 0;
pInfo->m_ServerLevel = clamp<int>(pUnpacker->GetInt(), SERVERINFO_LEVEL_MIN, SERVERINFO_LEVEL_MAX);
pInfo->m_NumPlayers = pUnpacker->GetInt();
pInfo->m_MaxPlayers = pUnpacker->GetInt();
pInfo->m_NumClients = pUnpacker->GetInt();
pInfo->m_MaxClients = pUnpacker->GetInt();
pInfo->m_NumBotPlayers = 0;
pInfo->m_NumBotSpectators = 0;
// don't add invalid info to the server browser list
if(pInfo->m_NumClients < 0 || pInfo->m_NumClients > pInfo->m_MaxClients || pInfo->m_MaxClients < 0 || pInfo->m_MaxClients > MAX_CLIENTS ||
pInfo->m_NumPlayers < 0 || pInfo->m_NumPlayers > pInfo->m_NumClients || pInfo->m_MaxPlayers < 0 || pInfo->m_MaxPlayers > pInfo->m_MaxClients)
return -1;
// drop standard gametype with more than MAX_PLAYERS
if(pInfo->m_MaxPlayers > MAX_PLAYERS && (str_comp(pInfo->m_aGameType, "DM") == 0 || str_comp(pInfo->m_aGameType, "TDM") == 0 || str_comp(pInfo->m_aGameType, "CTF") == 0 ||
str_comp(pInfo->m_aGameType, "LTS") == 0 || str_comp(pInfo->m_aGameType, "LMS") == 0))
return -1;
// use short version
if(!pToken)
return 0;
int NumPlayers = 0;
int NumClients = 0;
for(int i = 0; i < pInfo->m_NumClients; i++)
{
str_copy(pInfo->m_aClients[i].m_aName, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aClients[i].m_aName));
str_copy(pInfo->m_aClients[i].m_aClan, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aClients[i].m_aClan));
pInfo->m_aClients[i].m_Country = pUnpacker->GetInt();
pInfo->m_aClients[i].m_Score = pUnpacker->GetInt();
pInfo->m_aClients[i].m_PlayerType = pUnpacker->GetInt()&CServerInfo::CClient::PLAYERFLAG_MASK;
if(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_BOT)
{
if(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC)
pInfo->m_NumBotSpectators++;
else
pInfo->m_NumBotPlayers++;
}
NumClients++;
if(!(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC))
NumPlayers++;
}
pInfo->m_NumPlayers = NumPlayers;
pInfo->m_NumClients = NumClients;
return 0;
}
void CClient::ProcessConnlessPacket(CNetChunk *pPacket) void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
{ {
// version server // version server
@ -884,7 +935,7 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
Packet.m_pData = VERSIONSRV_GETMAPLIST; Packet.m_pData = VERSIONSRV_GETMAPLIST;
Packet.m_DataSize = sizeof(VERSIONSRV_GETMAPLIST); Packet.m_DataSize = sizeof(VERSIONSRV_GETMAPLIST);
Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_NetClient.Send(&Packet); m_ContactClient.Send(&Packet);
} }
// map version list // map version list
@ -951,56 +1002,14 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
// server info // server info
if(pPacket->m_DataSize >= (int)sizeof(SERVERBROWSE_INFO) && mem_comp(pPacket->m_pData, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0) if(pPacket->m_DataSize >= (int)sizeof(SERVERBROWSE_INFO) && mem_comp(pPacket->m_pData, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
{ {
// we got ze info
CUnpacker Up; CUnpacker Up;
CServerInfo Info = {0}; CServerInfo Info = {0};
Up.Reset((unsigned char*)pPacket->m_pData+sizeof(SERVERBROWSE_INFO), pPacket->m_DataSize-sizeof(SERVERBROWSE_INFO)); Up.Reset((unsigned char*)pPacket->m_pData+sizeof(SERVERBROWSE_INFO), pPacket->m_DataSize-sizeof(SERVERBROWSE_INFO));
int Token = Up.GetInt();
str_copy(Info.m_aVersion, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aVersion));
str_copy(Info.m_aName, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aName));
str_copy(Info.m_aHostname, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aHostname));
str_copy(Info.m_aMap, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aMap));
str_copy(Info.m_aGameType, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aGameType));
Info.m_Flags = (Up.GetInt()&SERVERINFO_FLAG_PASSWORD) ? IServerBrowser::FLAG_PASSWORD : 0;
Info.m_ServerLevel = clamp<int>(Up.GetInt(), SERVERINFO_LEVEL_MIN, SERVERINFO_LEVEL_MAX);
Info.m_NumPlayers = Up.GetInt();
Info.m_MaxPlayers = Up.GetInt();
Info.m_NumClients = Up.GetInt();
Info.m_MaxClients = Up.GetInt();
// don't add invalid info to the server browser list
if(Info.m_NumClients < 0 || Info.m_NumClients > MAX_CLIENTS || Info.m_MaxClients < 0 || Info.m_MaxClients > MAX_CLIENTS ||
Info.m_NumPlayers < 0 || Info.m_NumPlayers > Info.m_NumClients || Info.m_MaxPlayers < 0 || Info.m_MaxPlayers > Info.m_MaxClients)
return;
net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress), true); net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress), true);
if(Info.m_aHostname[0] == 0) int Token;
str_copy(Info.m_aHostname, Info.m_aAddress, sizeof(Info.m_aHostname)); if(!UnpackServerInfo(&Up, &Info, &Token) && !Up.Error())
for(int i = 0; i < Info.m_NumClients; i++)
{ {
str_copy(Info.m_aClients[i].m_aName, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aClients[i].m_aName));
str_copy(Info.m_aClients[i].m_aClan, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(Info.m_aClients[i].m_aClan));
Info.m_aClients[i].m_Country = Up.GetInt();
Info.m_aClients[i].m_Score = Up.GetInt();
Info.m_aClients[i].m_Player = Up.GetInt() != 0 ? true : false;
}
str_clean_whitespaces(Info.m_aName);
if(!Up.Error())
{
// sort players
qsort(Info.m_aClients, Info.m_NumClients, sizeof(*Info.m_aClients), PlayerScoreComp); qsort(Info.m_aClients, Info.m_NumClients, sizeof(*Info.m_aClients), PlayerScoreComp);
if(net_addr_comp(&m_ServerAddress, &pPacket->m_Address) == 0)
{
mem_copy(&m_CurrentServerInfo, &Info, sizeof(m_CurrentServerInfo));
m_CurrentServerInfo.m_NetAddr = m_ServerAddress;
m_CurrentServerInfoRequestTime = -1;
}
else
m_ServerBrowser.Set(pPacket->m_Address, CServerBrowser::SET_TOKEN, Token, &Info); m_ServerBrowser.Set(pPacket->m_Address, CServerBrowser::SET_TOKEN, Token, &Info);
} }
} }
@ -1022,7 +1031,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(Sys) if(Sys)
{ {
// system message // system message
if(Msg == NETMSG_MAP_CHANGE) if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_CHANGE)
{ {
const char *pMap = Unpacker.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES); const char *pMap = Unpacker.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES);
int MapCrc = Unpacker.GetInt(); int MapCrc = Unpacker.GetInt();
@ -1088,7 +1097,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
} }
} }
} }
else if(Msg == NETMSG_MAP_DATA) else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_MAP_DATA)
{ {
if(!m_MapdownloadFile) if(!m_MapdownloadFile)
return; return;
@ -1133,7 +1142,18 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", "requested next chunk package"); m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client/network", "requested next chunk package");
} }
} }
else if(Msg == NETMSG_CON_READY) else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_SERVERINFO)
{
CServerInfo Info = {0};
net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress), true);
if(!UnpackServerInfo(&Unpacker, &Info, 0) && !Unpacker.Error())
{
qsort(Info.m_aClients, Info.m_NumClients, sizeof(*Info.m_aClients), PlayerScoreComp);
mem_copy(&m_CurrentServerInfo, &Info, sizeof(m_CurrentServerInfo));
m_CurrentServerInfo.m_NetAddr = m_ServerAddress;
}
}
else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_CON_READY)
{ {
GameClient()->OnConnected(); GameClient()->OnConnected();
} }
@ -1142,7 +1162,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
CMsgPacker Msg(NETMSG_PING_REPLY, true); CMsgPacker Msg(NETMSG_PING_REPLY, true);
SendMsg(&Msg, 0); SendMsg(&Msg, 0);
} }
else if(Msg == NETMSG_RCON_CMD_ADD) else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_ADD)
{ {
const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
const char *pHelp = Unpacker.GetString(CUnpacker::SANITIZE_CC); const char *pHelp = Unpacker.GetString(CUnpacker::SANITIZE_CC);
@ -1150,25 +1170,25 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(Unpacker.Error() == 0) if(Unpacker.Error() == 0)
m_pConsole->RegisterTemp(pName, pParams, CFGFLAG_SERVER, pHelp); m_pConsole->RegisterTemp(pName, pParams, CFGFLAG_SERVER, pHelp);
} }
else if(Msg == NETMSG_RCON_CMD_REM) else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_CMD_REM)
{ {
const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
if(Unpacker.Error() == 0) if(Unpacker.Error() == 0)
m_pConsole->DeregisterTemp(pName); m_pConsole->DeregisterTemp(pName);
} }
else if(Msg == NETMSG_RCON_AUTH_ON) else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_AUTH_ON)
{ {
m_RconAuthed = 1; m_RconAuthed = 1;
m_UseTempRconCommands = 1; m_UseTempRconCommands = 1;
} }
else if(Msg == NETMSG_RCON_AUTH_OFF) else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_AUTH_OFF)
{ {
m_RconAuthed = 0; m_RconAuthed = 0;
if(m_UseTempRconCommands) if(m_UseTempRconCommands)
m_pConsole->DeregisterTempAll(); m_pConsole->DeregisterTempAll();
m_UseTempRconCommands = 0; m_UseTempRconCommands = 0;
} }
else if(Msg == NETMSG_RCON_LINE) else if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Msg == NETMSG_RCON_LINE)
{ {
const char *pLine = Unpacker.GetString(); const char *pLine = Unpacker.GetString();
if(Unpacker.Error() == 0) if(Unpacker.Error() == 0)
@ -1229,7 +1249,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
pData = (const char *)Unpacker.GetRaw(PartSize); pData = (const char *)Unpacker.GetRaw(PartSize);
if(Unpacker.Error()) if(Unpacker.Error() || NumParts < 1 || NumParts > CSnapshot::MAX_PARTS || Part < 0 || Part >= NumParts || PartSize < 0 || PartSize > MAX_SNAPSHOT_PACKSIZE)
return; return;
if(GameTick >= m_CurrentRecvTick) if(GameTick >= m_CurrentRecvTick)
@ -1293,7 +1313,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(CompleteSize) if(CompleteSize)
{ {
int IntSize = CVariableInt::Decompress(m_aSnapshotIncommingData, CompleteSize, aTmpBuffer2); int IntSize = CVariableInt::Decompress(m_aSnapshotIncommingData, CompleteSize, aTmpBuffer2, sizeof(aTmpBuffer2));
if(IntSize < 0) // failure during decompression, bail if(IntSize < 0) // failure during decompression, bail
return; return;
@ -1373,7 +1393,6 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
m_GameTime.Init((GameTick-1)*time_freq()/50); m_GameTime.Init((GameTick-1)*time_freq()/50);
m_aSnapshots[SNAP_PREV] = m_SnapshotStorage.m_pFirst; m_aSnapshots[SNAP_PREV] = m_SnapshotStorage.m_pFirst;
m_aSnapshots[SNAP_CURRENT] = m_SnapshotStorage.m_pLast; m_aSnapshots[SNAP_CURRENT] = m_SnapshotStorage.m_pLast;
m_LocalStartTime = time_get();
SetState(IClient::STATE_ONLINE); SetState(IClient::STATE_ONLINE);
DemoRecorder_HandleAutoStart(); DemoRecorder_HandleAutoStart();
} }
@ -1394,6 +1413,8 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
} }
} }
else else
{
if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0)
{ {
// game message // game message
GameClient()->OnMessage(Msg, &Unpacker); GameClient()->OnMessage(Msg, &Unpacker);
@ -1401,6 +1422,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(m_RecordGameMessage && m_DemoRecorder.IsRecording()) if(m_RecordGameMessage && m_DemoRecorder.IsRecording())
m_DemoRecorder.RecordMessage(pPacket->m_pData, pPacket->m_DataSize); m_DemoRecorder.RecordMessage(pPacket->m_pData, pPacket->m_DataSize);
} }
}
} }
void CClient::PumpNetwork() void CClient::PumpNetwork()
@ -1429,15 +1451,21 @@ void CClient::PumpNetwork()
} }
} }
// process packets // process non-connless packets
CNetChunk Packet; CNetChunk Packet;
while(m_NetClient.Recv(&Packet)) while(m_NetClient.Recv(&Packet))
{ {
if(Packet.m_ClientID == -1) if(!(Packet.m_Flags&NETSENDFLAG_CONNLESS))
ProcessConnlessPacket(&Packet);
else
ProcessServerPacket(&Packet); ProcessServerPacket(&Packet);
} }
// process connless packets data
m_ContactClient.Update();
while(m_ContactClient.Recv(&Packet))
{
if(Packet.m_Flags&NETSENDFLAG_CONNLESS)
ProcessConnlessPacket(&Packet);
}
} }
void CClient::OnDemoPlayerSnapshot(void *pData, int Size) void CClient::OnDemoPlayerSnapshot(void *pData, int Size)
@ -1601,15 +1629,6 @@ void CClient::Update()
if(m_PredTick > m_CurGameTick && m_PredTick < m_CurGameTick+50) if(m_PredTick > m_CurGameTick && m_PredTick < m_CurGameTick+50)
GameClient()->OnPredict(); GameClient()->OnPredict();
} }
// fetch server info if we don't have it
if(State() >= IClient::STATE_LOADING &&
m_CurrentServerInfoRequestTime >= 0 &&
time_get() > m_CurrentServerInfoRequestTime)
{
m_ServerBrowser.Request(m_ServerAddress);
m_CurrentServerInfoRequestTime = time_get()+time_freq()*2;
}
} }
// STRESS TEST: join the server again // STRESS TEST: join the server again
@ -1646,18 +1665,24 @@ void CClient::Update()
// update the server browser // update the server browser
m_ServerBrowser.Update(m_ResortServerBrowser); m_ServerBrowser.Update(m_ResortServerBrowser);
m_ResortServerBrowser = false; m_ResortServerBrowser = false;
// update gameclient
if(!m_EditorActive)
GameClient()->OnUpdate();
} }
void CClient::VersionUpdate() void CClient::VersionUpdate()
{ {
if(m_VersionInfo.m_State == CVersionInfo::STATE_INIT) if(m_VersionInfo.m_State == CVersionInfo::STATE_INIT)
{ {
Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, g_Config.m_ClVersionServer, m_NetClient.NetType()); Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, g_Config.m_ClVersionServer, m_ContactClient.NetType());
m_VersionInfo.m_State = CVersionInfo::STATE_START; m_VersionInfo.m_State = CVersionInfo::STATE_START;
} }
else if(m_VersionInfo.m_State == CVersionInfo::STATE_START) else if(m_VersionInfo.m_State == CVersionInfo::STATE_START)
{ {
if(m_VersionInfo.m_VersionServeraddr.m_Job.Status() == CJob::STATE_DONE) if(m_VersionInfo.m_VersionServeraddr.m_Job.Status() == CJob::STATE_DONE)
{
if(m_VersionInfo.m_VersionServeraddr.m_Job.Result() == 0)
{ {
CNetChunk Packet; CNetChunk Packet;
@ -1671,9 +1696,12 @@ void CClient::VersionUpdate()
Packet.m_DataSize = sizeof(VERSIONSRV_GETVERSION); Packet.m_DataSize = sizeof(VERSIONSRV_GETVERSION);
Packet.m_Flags = NETSENDFLAG_CONNLESS; Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_NetClient.Send(&Packet); m_ContactClient.Send(&Packet);
m_VersionInfo.m_State = CVersionInfo::STATE_READY; m_VersionInfo.m_State = CVersionInfo::STATE_READY;
} }
else
m_VersionInfo.m_State = CVersionInfo::STATE_ERROR;
}
} }
} }
@ -1699,10 +1727,90 @@ void CClient::InitInterfaces()
m_pStorage = Kernel()->RequestInterface<IStorage>(); m_pStorage = Kernel()->RequestInterface<IStorage>();
// //
m_ServerBrowser.SetBaseInfo(&m_NetClient, m_pGameClient->NetVersion()); m_ServerBrowser.Init(&m_ContactClient, m_pGameClient->NetVersion());
m_Friends.Init(); m_Friends.Init();
} }
bool CClient::LimitFps()
{
if(g_Config.m_GfxVsync || !g_Config.m_GfxLimitFps) return false;
/**
If desired frame time is not reached:
Skip rendering the frame
Do another game loop
If we don't have the time to do another game loop:
Wait until desired frametime
Returns true if frame should be skipped
**/
#ifdef CONF_DEBUG
static double DbgTimeWaited = 0.0;
static int64 DbgFramesSkippedCount = 0;
static int64 DbgLastSkippedDbgMsg = time_get();
#endif
int64 Now = time_get();
const double LastCpuFrameTime = (Now - m_LastCpuTime) / (double)time_freq();
m_LastAvgCpuFrameTime = (m_LastAvgCpuFrameTime + LastCpuFrameTime * 4.0) / 5.0;
m_LastCpuTime = Now;
bool SkipFrame = true;
double RenderDeltaTime = (Now - m_LastRenderTime) / (double)time_freq();
const double DesiredTime = 1.0/g_Config.m_GfxMaxFps;
// we can't skip another frame, so wait instead
if(SkipFrame && RenderDeltaTime < DesiredTime &&
m_LastAvgCpuFrameTime * 1.20 > (DesiredTime - RenderDeltaTime))
{
#ifdef CONF_DEBUG
DbgTimeWaited += DesiredTime - RenderDeltaTime;
#endif
const double Freq = (double)time_freq();
const int64 LastT = m_LastRenderTime;
double d = DesiredTime - RenderDeltaTime;
while(d > 0.00001)
{
Now = time_get();
RenderDeltaTime = (Now - LastT) / Freq;
d = DesiredTime - RenderDeltaTime;
_mm_pause();
}
SkipFrame = false;
m_LastCpuTime = Now;
}
// RenderDeltaTime exceeds DesiredTime, render
if(SkipFrame && RenderDeltaTime > DesiredTime)
{
SkipFrame = false;
}
#ifdef CONF_DEBUG
DbgFramesSkippedCount += SkipFrame? 1:0;
Now = time_get();
if(g_Config.m_GfxLimitFps &&
g_Config.m_Debug &&
(Now - DbgLastSkippedDbgMsg) / (double)time_freq() > 5.0)
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "LimitFps: FramesSkippedCount=%d TimeWaited=%.3f (per sec)",
DbgFramesSkippedCount/5,
DbgTimeWaited/5.0);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client", aBuf);
DbgFramesSkippedCount = 0;
DbgTimeWaited = 0;
DbgLastSkippedDbgMsg = Now;
}
#endif
return SkipFrame;
}
void CClient::Run() void CClient::Run()
{ {
m_LocalStartTime = time_get(); m_LocalStartTime = time_get();
@ -1753,9 +1861,15 @@ void CClient::Run()
mem_zero(&BindAddr, sizeof(BindAddr)); mem_zero(&BindAddr, sizeof(BindAddr));
BindAddr.type = NETTYPE_ALL; BindAddr.type = NETTYPE_ALL;
} }
if(!m_NetClient.Open(BindAddr, 0)) if(!m_NetClient.Open(BindAddr, BindAddr.port ? 0 : NETCREATE_FLAG_RANDOMPORT))
{ {
dbg_msg("client", "couldn't open socket"); dbg_msg("client", "couldn't open socket(net)");
return;
}
BindAddr.port = 0;
if(!m_ContactClient.Open(BindAddr, 0))
{
dbg_msg("client", "couldn't open socket(contact)");
return; return;
} }
} }
@ -1767,7 +1881,7 @@ void CClient::Run()
Input()->Init(); Input()->Init();
// start refreshing addresses while we load // start refreshing addresses while we load
MasterServer()->RefreshAddresses(m_NetClient.NetType()); MasterServer()->RefreshAddresses(m_ContactClient.NetType());
// init the editor // init the editor
m_pEditor->Init(); m_pEditor->Init();
@ -1783,21 +1897,12 @@ void CClient::Run()
str_format(aBuf, sizeof(aBuf), "version %s", GameClient()->NetVersion()); str_format(aBuf, sizeof(aBuf), "version %s", GameClient()->NetVersion());
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf);
// connect to the server if wanted
/*
if(config.cl_connect[0] != 0)
Connect(config.cl_connect);
config.cl_connect[0] = 0;
*/
// //
m_FpsGraph.Init(0.0f, 200.0f); m_FpsGraph.Init(0.0f, 120.0f);
// never start with the editor // never start with the editor
g_Config.m_ClEditor = 0; g_Config.m_ClEditor = 0;
Input()->MouseModeRelative();
// process pending commands // process pending commands
m_pConsole->StoreCommands(false); m_pConsole->StoreCommands(false);
@ -1828,7 +1933,7 @@ void CClient::Run()
Input()->MouseModeAbsolute(); Input()->MouseModeAbsolute();
m_WindowMustRefocus = 1; m_WindowMustRefocus = 1;
} }
else if (g_Config.m_DbgFocus && Input()->KeyPressed(KEY_ESCAPE)) else if (g_Config.m_DbgFocus && Input()->KeyPress(KEY_ESCAPE, true))
{ {
Input()->MouseModeAbsolute(); Input()->MouseModeAbsolute();
m_WindowMustRefocus = 1; m_WindowMustRefocus = 1;
@ -1843,37 +1948,37 @@ void CClient::Run()
m_WindowMustRefocus++; m_WindowMustRefocus++;
} }
if(m_WindowMustRefocus >= 3 || Input()->KeyPressed(KEY_MOUSE_1)) if(m_WindowMustRefocus >= 3 || Input()->KeyPress(KEY_MOUSE_1, true))
{ {
Input()->MouseModeRelative(); Input()->MouseModeRelative();
m_WindowMustRefocus = 0; m_WindowMustRefocus = 0;
// update screen in case it got moved
int ActScreen = Graphics()->GetWindowScreen();
if(ActScreen >= 0 && ActScreen != g_Config.m_GfxScreen)
g_Config.m_GfxScreen = ActScreen;
} }
} }
// panic quit button // panic quit button
if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyPressed(KEY_Q)) if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_Q, true))
{ {
Quit(); Quit();
break; break;
} }
if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_D)) if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_D, true))
g_Config.m_Debug ^= 1; g_Config.m_Debug ^= 1;
if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_G)) if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_G, true))
g_Config.m_DbgGraphs ^= 1; g_Config.m_DbgGraphs ^= 1;
if(Input()->KeyPressed(KEY_LCTRL) && Input()->KeyPressed(KEY_LSHIFT) && Input()->KeyDown(KEY_E)) if(Input()->KeyIsPressed(KEY_LCTRL) && Input()->KeyIsPressed(KEY_LSHIFT) && Input()->KeyPress(KEY_E, true))
{ {
g_Config.m_ClEditor = g_Config.m_ClEditor^1; g_Config.m_ClEditor = g_Config.m_ClEditor^1;
Input()->MouseModeRelative(); Input()->MouseModeRelative();
} }
/*
if(!gfx_window_open())
break;
*/
// render // render
{ {
if(g_Config.m_ClEditor) if(g_Config.m_ClEditor)
@ -1889,13 +1994,16 @@ void CClient::Run()
Update(); Update();
if(!g_Config.m_GfxAsyncRender || m_pGraphics->IsIdle()) const bool SkipFrame = LimitFps();
if(!SkipFrame && (!g_Config.m_GfxAsyncRender || m_pGraphics->IsIdle()))
{ {
m_RenderFrames++; m_RenderFrames++;
// update frametime // update frametime
int64 Now = time_get(); int64 Now = time_get();
m_RenderFrameTime = (Now - m_LastRenderTime) / (float)time_freq(); m_RenderFrameTime = (Now - m_LastRenderTime) / (float)time_freq();
if(m_RenderFrameTime < m_RenderFrameTimeLow) if(m_RenderFrameTime < m_RenderFrameTimeLow)
m_RenderFrameTimeLow = m_RenderFrameTime; m_RenderFrameTimeLow = m_RenderFrameTime;
if(m_RenderFrameTime > m_RenderFrameTimeHigh) if(m_RenderFrameTime > m_RenderFrameTimeHigh)
@ -1972,6 +2080,8 @@ void CClient::Run()
m_pGraphics->Shutdown(); m_pGraphics->Shutdown();
m_pSound->Shutdown(); m_pSound->Shutdown();
m_ServerBrowser.SaveServerlist();
// shutdown SDL // shutdown SDL
{ {
SDL_Quit(); SDL_Quit();
@ -2193,6 +2303,89 @@ void CClient::ConchainServerBrowserUpdate(IConsole::IResult *pResult, void *pUse
((CClient *)pUserData)->ServerBrowserUpdate(); ((CClient *)pUserData)->ServerBrowserUpdate();
} }
void CClient::SwitchWindowScreen(int Index)
{
// Todo SDL: remove this when fixed (changing screen when in fullscreen is bugged)
if(g_Config.m_GfxFullscreen)
{
ToggleFullscreen();
if(Graphics()->SetWindowScreen(Index))
g_Config.m_GfxScreen = Index;
ToggleFullscreen();
}
else
{
if(Graphics()->SetWindowScreen(Index))
g_Config.m_GfxScreen = Index;
}
}
void CClient::ConchainWindowScreen(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CClient *pSelf = (CClient *)pUserData;
if(pSelf->Graphics() && pResult->NumArguments())
{
if(g_Config.m_GfxScreen != pResult->GetInteger(0))
pSelf->SwitchWindowScreen(pResult->GetInteger(0));
}
else
pfnCallback(pResult, pCallbackUserData);
}
void CClient::ToggleFullscreen()
{
if(Graphics()->Fullscreen(g_Config.m_GfxFullscreen^1))
g_Config.m_GfxFullscreen ^= 1;
}
void CClient::ConchainFullscreen(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CClient *pSelf = (CClient *)pUserData;
if(pSelf->Graphics() && pResult->NumArguments())
{
if(g_Config.m_GfxFullscreen != pResult->GetInteger(0))
pSelf->ToggleFullscreen();
}
else
pfnCallback(pResult, pCallbackUserData);
}
void CClient::ToggleWindowBordered()
{
g_Config.m_GfxBorderless ^= 1;
Graphics()->SetWindowBordered(!g_Config.m_GfxBorderless);
}
void CClient::ConchainWindowBordered(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CClient *pSelf = (CClient *)pUserData;
if(pSelf->Graphics() && pResult->NumArguments())
{
if(!g_Config.m_GfxFullscreen && (g_Config.m_GfxBorderless != pResult->GetInteger(0)))
pSelf->ToggleWindowBordered();
}
else
pfnCallback(pResult, pCallbackUserData);
}
void CClient::ToggleWindowVSync()
{
if(Graphics()->SetVSync(g_Config.m_GfxVsync^1))
g_Config.m_GfxVsync ^= 1;
}
void CClient::ConchainWindowVSync(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CClient *pSelf = (CClient *)pUserData;
if(pSelf->Graphics() && pResult->NumArguments())
{
if(g_Config.m_GfxVsync != pResult->GetInteger(0))
pSelf->ToggleWindowVSync();
}
else
pfnCallback(pResult, pCallbackUserData);
}
void CClient::RegisterCommands() void CClient::RegisterCommands()
{ {
m_pConsole = Kernel()->RequestInterface<IConsole>(); m_pConsole = Kernel()->RequestInterface<IConsole>();
@ -2213,8 +2406,11 @@ void CClient::RegisterCommands()
// used for server browser update // used for server browser update
m_pConsole->Chain("br_filter_string", ConchainServerBrowserUpdate, this); m_pConsole->Chain("br_filter_string", ConchainServerBrowserUpdate, this);
m_pConsole->Chain("br_filter_gametype", ConchainServerBrowserUpdate, this);
m_pConsole->Chain("br_filter_serveraddress", ConchainServerBrowserUpdate, this); m_pConsole->Chain("gfx_screen", ConchainWindowScreen, this);
m_pConsole->Chain("gfx_fullscreen", ConchainFullscreen, this);
m_pConsole->Chain("gfx_borderless", ConchainWindowBordered, this);
m_pConsole->Chain("gfx_vsync", ConchainWindowVSync, this);
} }
static CClient *CreateClient() static CClient *CreateClient()
@ -2224,6 +2420,11 @@ static CClient *CreateClient()
return new(pClient) CClient; return new(pClient) CClient;
} }
void CClient::HandleTeeworldsConnectLink(const char *pConLink)
{
str_copy(m_aCmdConnect, pConLink, sizeof(m_aCmdConnect));
}
/* /*
Server Time Server Time
Client Mirror Time Client Mirror Time
@ -2235,7 +2436,6 @@ static CClient *CreateClient()
Prediction Latency Prediction Latency
Upstream latency Upstream latency
*/ */
#if defined(CONF_PLATFORM_MACOSX) #if defined(CONF_PLATFORM_MACOSX)
extern "C" int SDL_main(int argc, char **argv_) // ignore_convention extern "C" int SDL_main(int argc, char **argv_) // ignore_convention
{ {
@ -2245,14 +2445,27 @@ int main(int argc, const char **argv) // ignore_convention
{ {
#endif #endif
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
#ifdef CONF_RELEASE
bool HideConsole = true;
#else
bool HideConsole = false;
#endif
for(int i = 1; i < argc; i++) // ignore_convention for(int i = 1; i < argc; i++) // ignore_convention
{ {
if(str_comp("-c", argv[i]) == 0 || str_comp("--console", argv[i]) == 0) // ignore_convention
{
HideConsole = false;
break;
}
if(str_comp("-s", argv[i]) == 0 || str_comp("--silent", argv[i]) == 0) // ignore_convention if(str_comp("-s", argv[i]) == 0 || str_comp("--silent", argv[i]) == 0) // ignore_convention
{ {
FreeConsole(); HideConsole = true;
break; break;
} }
} }
if(HideConsole)
FreeConsole();
#endif #endif
bool UseDefaultConfig = false; bool UseDefaultConfig = false;
@ -2335,7 +2548,24 @@ int main(int argc, const char **argv) // ignore_convention
// parse the command line arguments // parse the command line arguments
if(argc > 1) // ignore_convention if(argc > 1) // ignore_convention
pConsole->ParseArguments(argc-1, &argv[1]); // ignore_convention {
switch(argc) // ignore_convention
{
case 2:
{
// handle Teeworlds connect link
const int Length = str_length(pClient->m_pConLinkIdentifier);
if(str_comp_num(pClient->m_pConLinkIdentifier, argv[1], Length) == 0) // ignore_convention
{
pClient->HandleTeeworldsConnectLink(argv[1] + Length); // ignore_convention
break;
}
}
default:
pConsole->ParseArguments(argc - 1, &argv[1]); // ignore_convention
}
}
} }
// restore empty config strings to their defaults // restore empty config strings to their defaults

View file

@ -13,6 +13,7 @@ public:
}; };
float m_Min, m_Max; float m_Min, m_Max;
float m_MinRange, m_MaxRange;
float m_aValues[MAX_VALUES]; float m_aValues[MAX_VALUES];
float m_aColors[MAX_VALUES][3]; float m_aColors[MAX_VALUES][3];
int m_Index; int m_Index;
@ -70,6 +71,7 @@ class CClient : public IClient, public CDemoPlayer::IListner
}; };
class CNetClient m_NetClient; class CNetClient m_NetClient;
class CNetClient m_ContactClient;
class CDemoPlayer m_DemoPlayer; class CDemoPlayer m_DemoPlayer;
class CDemoRecorder m_DemoRecorder; class CDemoRecorder m_DemoRecorder;
class CServerBrowser m_ServerBrowser; class CServerBrowser m_ServerBrowser;
@ -84,6 +86,8 @@ class CClient : public IClient, public CDemoPlayer::IListner
IGraphics::CTextureHandle m_DebugFont; IGraphics::CTextureHandle m_DebugFont;
int64 m_LastRenderTime; int64 m_LastRenderTime;
int64 m_LastCpuTime;
float m_LastAvgCpuFrameTime;
float m_RenderFrameTimeLow; float m_RenderFrameTimeLow;
float m_RenderFrameTimeHigh; float m_RenderFrameTimeHigh;
int m_RenderFrames; int m_RenderFrames;
@ -161,7 +165,6 @@ class CClient : public IClient, public CDemoPlayer::IListner
// //
class CServerInfo m_CurrentServerInfo; class CServerInfo m_CurrentServerInfo;
int64 m_CurrentServerInfoRequestTime; // >= 0 should request, == -1 got info
// version info // version info
struct CVersionInfo struct CVersionInfo
@ -171,6 +174,7 @@ class CClient : public IClient, public CDemoPlayer::IListner
STATE_INIT=0, STATE_INIT=0,
STATE_START, STATE_START,
STATE_READY, STATE_READY,
STATE_ERROR,
}; };
int m_State; int m_State;
@ -208,7 +212,6 @@ public:
virtual IGraphics::CTextureHandle GetDebugFont() const { return m_DebugFont; } virtual IGraphics::CTextureHandle GetDebugFont() const { return m_DebugFont; }
void DirectInput(int *pInput, int Size);
void SendInput(); void SendInput();
// TODO: OPT: do this alot smarter! // TODO: OPT: do this alot smarter!
@ -230,7 +233,6 @@ public:
virtual void GetServerInfo(CServerInfo *pServerInfo) const; virtual void GetServerInfo(CServerInfo *pServerInfo) const;
void ServerInfoRequest();
int LoadData(); int LoadData();
@ -255,9 +257,11 @@ public:
static int PlayerScoreComp(const void *a, const void *b); static int PlayerScoreComp(const void *a, const void *b);
int UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pToken);
void ProcessConnlessPacket(CNetChunk *pPacket); void ProcessConnlessPacket(CNetChunk *pPacket);
void ProcessServerPacket(CNetChunk *pPacket); void ProcessServerPacket(CNetChunk *pPacket);
virtual const char *MapDownloadName() const { return m_aMapdownloadName; }
virtual int MapDownloadAmount() const { return m_MapdownloadAmount; } virtual int MapDownloadAmount() const { return m_MapdownloadAmount; }
virtual int MapDownloadTotalsize() const { return m_MapdownloadTotalsize; } virtual int MapDownloadTotalsize() const { return m_MapdownloadTotalsize; }
@ -271,6 +275,7 @@ public:
void RegisterInterfaces(); void RegisterInterfaces();
void InitInterfaces(); void InitInterfaces();
bool LimitFps();
void Run(); void Run();
@ -289,6 +294,10 @@ public:
static void Con_StopRecord(IConsole::IResult *pResult, void *pUserData); static void Con_StopRecord(IConsole::IResult *pResult, void *pUserData);
static void Con_AddDemoMarker(IConsole::IResult *pResult, void *pUserData); static void Con_AddDemoMarker(IConsole::IResult *pResult, void *pUserData);
static void ConchainServerBrowserUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainServerBrowserUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainFullscreen(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainWindowBordered(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainWindowScreen(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainWindowVSync(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
void RegisterCommands(); void RegisterCommands();
@ -303,5 +312,15 @@ public:
void AutoScreenshot_Cleanup(); void AutoScreenshot_Cleanup();
void ServerBrowserUpdate(); void ServerBrowserUpdate();
// gfx
void SwitchWindowScreen(int Index);
void ToggleFullscreen();
void ToggleWindowBordered();
void ToggleWindowVSync();
// Teeworlds connect link
const char * const m_pConLinkIdentifier;
void HandleTeeworldsConnectLink(const char *pConLink);
}; };
#endif #endif

View file

@ -264,20 +264,22 @@ void CGraphics_Threaded::LinesDraw(const CLineItem *pArray, int Num)
AddVertices(2*Num); AddVertices(2*Num);
} }
int CGraphics_Threaded::UnloadTexture(CTextureHandle Index) int CGraphics_Threaded::UnloadTexture(CTextureHandle *Index)
{ {
if(Index.Id() == m_InvalidTexture.Id()) if(Index->Id() == m_InvalidTexture.Id())
return 0; return 0;
if(!Index.IsValid()) if(!Index->IsValid())
return 0; return 0;
CCommandBuffer::SCommand_Texture_Destroy Cmd; CCommandBuffer::SCommand_Texture_Destroy Cmd;
Cmd.m_Slot = Index.Id(); Cmd.m_Slot = Index->Id();
m_pCommandBuffer->AddCommand(Cmd); m_pCommandBuffer->AddCommand(Cmd);
m_aTextureIndices[Index.Id()] = m_FirstFreeTexture; m_aTextureIndices[Index->Id()] = m_FirstFreeTexture;
m_FirstFreeTexture = Index.Id(); m_FirstFreeTexture = Index->Id();
Index->Invalidate();
return 0; return 0;
} }
@ -358,6 +360,8 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig
} }
if(Flags&IGraphics::TEXLOAD_MULTI_DIMENSION) if(Flags&IGraphics::TEXLOAD_MULTI_DIMENSION)
Cmd.m_Flags |= CCommandBuffer::TEXFLAG_TEXTURE3D; Cmd.m_Flags |= CCommandBuffer::TEXFLAG_TEXTURE3D;
if(Flags&IGraphics::TEXLOAD_LINEARMIPMAPS)
Cmd.m_Flags |= CCommandBuffer::TEXTFLAG_LINEARMIPMAPS;
// copy texture data // copy texture data
@ -424,7 +428,7 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto
return 0; return 0;
} }
if(Png.depth != 8 || (Png.color_type != PNG_TRUECOLOR && Png.color_type != PNG_TRUECOLOR_ALPHA)) // ignore_convention if(Png.depth != 8 || (Png.color_type != PNG_TRUECOLOR && Png.color_type != PNG_TRUECOLOR_ALPHA) || Png.width > (2<<12) || Png.height > (2<<12)) // ignore_convention
{ {
dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename); dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename);
png_close_file(&Png); // ignore_convention png_close_file(&Png); // ignore_convention
@ -463,6 +467,8 @@ void CGraphics_Threaded::ScreenshotDirect(const char *pFilename)
CCommandBuffer::SCommand_Screenshot Cmd; CCommandBuffer::SCommand_Screenshot Cmd;
Cmd.m_pImage = &Image; Cmd.m_pImage = &Image;
Cmd.m_X = 0; Cmd.m_Y = 0;
Cmd.m_W = -1; Cmd.m_H = -1;
m_pCommandBuffer->AddCommand(Cmd); m_pCommandBuffer->AddCommand(Cmd);
// kick the buffer and wait for the result // kick the buffer and wait for the result
@ -516,6 +522,7 @@ void CGraphics_Threaded::QuadsBegin()
QuadsSetSubset(0,0,1,1,-1); QuadsSetSubset(0,0,1,1,-1);
QuadsSetRotation(0); QuadsSetRotation(0);
SetColor(1,1,1,1); SetColor(1,1,1,1);
m_TextureArrayIndex = m_pBackend->GetTextureArraySize() > 1 ? -1 : 0;
} }
void CGraphics_Threaded::QuadsEnd() void CGraphics_Threaded::QuadsEnd()
@ -566,17 +573,36 @@ void CGraphics_Threaded::SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft,
SetColorVertex(Array, 4); SetColorVertex(Array, 4);
} }
void CGraphics_Threaded::TilesetFallbackSystem(int TextureIndex)
{
int NewTextureArrayIndex = TextureIndex / (256 / m_pBackend->GetTextureArraySize());
if(m_TextureArrayIndex == -1)
m_TextureArrayIndex = NewTextureArrayIndex;
else if(m_TextureArrayIndex != NewTextureArrayIndex)
{
// have to switch the texture index
FlushVertices();
m_TextureArrayIndex = NewTextureArrayIndex;
}
}
void CGraphics_Threaded::QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex) void CGraphics_Threaded::QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex)
{ {
dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetSubset without begin"); dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetSubset without begin");
// tileset fallback system
if(m_pBackend->GetTextureArraySize() > 1 && TextureIndex >= 0)
TilesetFallbackSystem(TextureIndex);
m_State.m_TextureArrayIndex = m_TextureArrayIndex;
m_aTexture[0].u = TlU; m_aTexture[1].u = BrU; m_aTexture[0].u = TlU; m_aTexture[1].u = BrU;
m_aTexture[0].v = TlV; m_aTexture[1].v = TlV; m_aTexture[0].v = TlV; m_aTexture[1].v = TlV;
m_aTexture[3].u = TlU; m_aTexture[2].u = BrU; m_aTexture[3].u = TlU; m_aTexture[2].u = BrU;
m_aTexture[3].v = BrV; m_aTexture[2].v = BrV; m_aTexture[3].v = BrV; m_aTexture[2].v = BrV;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / 256.0f; m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / (256.0f/m_pBackend->GetTextureArraySize());
m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3; m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3;
} }
@ -584,12 +610,18 @@ void CGraphics_Threaded::QuadsSetSubsetFree(
float x0, float y0, float x1, float y1, float x0, float y0, float x1, float y1,
float x2, float y2, float x3, float y3, int TextureIndex) float x2, float y2, float x3, float y3, int TextureIndex)
{ {
// tileset fallback system
if(m_pBackend->GetTextureArraySize() > 1 && TextureIndex >= 0)
TilesetFallbackSystem(TextureIndex);
m_State.m_TextureArrayIndex = m_TextureArrayIndex;
m_aTexture[0].u = x0; m_aTexture[0].v = y0; m_aTexture[0].u = x0; m_aTexture[0].v = y0;
m_aTexture[1].u = x1; m_aTexture[1].v = y1; m_aTexture[1].u = x1; m_aTexture[1].v = y1;
m_aTexture[2].u = x2; m_aTexture[2].v = y2; m_aTexture[2].u = x2; m_aTexture[2].v = y2;
m_aTexture[3].u = x3; m_aTexture[3].v = y3; m_aTexture[3].u = x3; m_aTexture[3].v = y3;
m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / 256.0f; m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / (256.0f/m_pBackend->GetTextureArraySize());
m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3; m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3;
} }
@ -707,18 +739,12 @@ void CGraphics_Threaded::QuadsText(float x, float y, float Size, const char *pTe
int CGraphics_Threaded::IssueInit() int CGraphics_Threaded::IssueInit()
{ {
int Flags = 0; int Flags = 0;
if(g_Config.m_GfxBorderless && g_Config.m_GfxFullscreen)
{
dbg_msg("gfx", "both borderless and fullscreen activated, disabling borderless");
g_Config.m_GfxBorderless = 0;
}
if(g_Config.m_GfxBorderless) Flags |= IGraphicsBackend::INITFLAG_BORDERLESS; if(g_Config.m_GfxBorderless) Flags |= IGraphicsBackend::INITFLAG_BORDERLESS;
else if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN; if(g_Config.m_GfxFullscreen) Flags |= IGraphicsBackend::INITFLAG_FULLSCREEN;
if(g_Config.m_GfxVsync) Flags |= IGraphicsBackend::INITFLAG_VSYNC; if(g_Config.m_GfxVsync) Flags |= IGraphicsBackend::INITFLAG_VSYNC;
if(g_Config.m_DbgResizable) Flags |= IGraphicsBackend::INITFLAG_RESIZABLE; if(g_Config.m_DbgResizable) Flags |= IGraphicsBackend::INITFLAG_RESIZABLE;
return m_pBackend->Init("Teeworlds", g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags, &m_DesktopScreenWidth, &m_DesktopScreenHeight); return m_pBackend->Init("Teeworlds", &g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags, &m_DesktopScreenWidth, &m_DesktopScreenHeight);
} }
int CGraphics_Threaded::InitWindow() int CGraphics_Threaded::InitWindow()
@ -839,6 +865,11 @@ void CGraphics_Threaded::Shutdown()
delete m_apCommandBuffers[i]; delete m_apCommandBuffers[i];
} }
int CGraphics_Threaded::GetNumScreens() const
{
return m_pBackend->GetNumScreens();
}
void CGraphics_Threaded::Minimize() void CGraphics_Threaded::Minimize()
{ {
m_pBackend->Minimize(); m_pBackend->Minimize();
@ -846,10 +877,29 @@ void CGraphics_Threaded::Minimize()
void CGraphics_Threaded::Maximize() void CGraphics_Threaded::Maximize()
{ {
// TODO: SDL
m_pBackend->Maximize(); m_pBackend->Maximize();
} }
bool CGraphics_Threaded::Fullscreen(bool State)
{
return m_pBackend->Fullscreen(State);
}
void CGraphics_Threaded::SetWindowBordered(bool State)
{
m_pBackend->SetWindowBordered(State);
}
bool CGraphics_Threaded::SetWindowScreen(int Index)
{
return m_pBackend->SetWindowScreen(Index);
}
int CGraphics_Threaded::GetWindowScreen()
{
return m_pBackend->GetWindowScreen();
}
int CGraphics_Threaded::WindowActive() int CGraphics_Threaded::WindowActive()
{ {
return m_pBackend->WindowActive(); return m_pBackend->WindowActive();
@ -861,6 +911,28 @@ int CGraphics_Threaded::WindowOpen()
} }
void CGraphics_Threaded::ReadBackbuffer(unsigned char **ppPixels, int x, int y, int w, int h)
{
if(!ppPixels)
return;
// add swap command
CImageInfo Image;
mem_zero(&Image, sizeof(Image));
CCommandBuffer::SCommand_Screenshot Cmd;
Cmd.m_pImage = &Image;
Cmd.m_X = x; Cmd.m_Y = y;
Cmd.m_W = w; Cmd.m_H = h;
m_pCommandBuffer->AddCommand(Cmd);
// kick the buffer and wait for the result
KickCommandBuffer();
WaitForIdle();
*ppPixels = (unsigned char *)Image.m_pData; // take ownership!
}
void CGraphics_Threaded::TakeScreenshot(const char *pFilename) void CGraphics_Threaded::TakeScreenshot(const char *pFilename)
{ {
// TODO: screenshot support // TODO: screenshot support
@ -889,6 +961,21 @@ void CGraphics_Threaded::Swap()
KickCommandBuffer(); KickCommandBuffer();
} }
bool CGraphics_Threaded::SetVSync(bool State)
{
// add vsnc command
bool RetOk = 0;
CCommandBuffer::SCommand_VSync Cmd;
Cmd.m_VSync = State ? 1 : 0;
Cmd.m_pRetOk = &RetOk;
m_pCommandBuffer->AddCommand(Cmd);
// kick the command buffer
KickCommandBuffer();
WaitForIdle();
return RetOk;
}
// syncronization // syncronization
void CGraphics_Threaded::InsertSignal(semaphore *pSemaphore) void CGraphics_Threaded::InsertSignal(semaphore *pSemaphore)
{ {
@ -923,10 +1010,11 @@ int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes, int Scre
mem_zero(&Image, sizeof(Image)); mem_zero(&Image, sizeof(Image));
int NumModes = 0; int NumModes = 0;
CCommandBuffer::SCommand_VideoModes Cmd(Screen); CCommandBuffer::SCommand_VideoModes Cmd;
Cmd.m_pModes = pModes; Cmd.m_pModes = pModes;
Cmd.m_MaxModes = MaxModes; Cmd.m_MaxModes = MaxModes;
Cmd.m_pNumModes = &NumModes; Cmd.m_pNumModes = &NumModes;
Cmd.m_Screen = Screen;
m_pCommandBuffer->AddCommand(Cmd); m_pCommandBuffer->AddCommand(Cmd);
// kick the buffer and wait for the result and return it // kick the buffer and wait for the result and return it

View file

@ -82,6 +82,7 @@ public:
CMD_SWAP, CMD_SWAP,
// misc // misc
CMD_VSYNC,
CMD_SCREENSHOT, CMD_SCREENSHOT,
CMD_VIDEOMODES, CMD_VIDEOMODES,
@ -99,6 +100,7 @@ public:
TEXFLAG_QUALITY = 4, TEXFLAG_QUALITY = 4,
TEXFLAG_TEXTURE3D = 8, TEXFLAG_TEXTURE3D = 8,
TEXFLAG_TEXTURE2D = 16, TEXFLAG_TEXTURE2D = 16,
TEXTFLAG_LINEARMIPMAPS = 32,
}; };
enum enum
@ -141,6 +143,7 @@ public:
int m_WrapModeU; int m_WrapModeU;
int m_WrapModeV; int m_WrapModeV;
int m_Texture; int m_Texture;
int m_TextureArrayIndex;
int m_Dimension; int m_Dimension;
SPoint m_ScreenTL; SPoint m_ScreenTL;
SPoint m_ScreenBR; SPoint m_ScreenBR;
@ -183,13 +186,13 @@ public:
struct SCommand_Screenshot : public SCommand struct SCommand_Screenshot : public SCommand
{ {
SCommand_Screenshot() : SCommand(CMD_SCREENSHOT) {} SCommand_Screenshot() : SCommand(CMD_SCREENSHOT) {}
int m_X, m_Y, m_W, m_H; // specify rectangle size, -1 if fullscreen (width/height)
CImageInfo *m_pImage; // processor will fill this out, the one who adds this command must free the data as well CImageInfo *m_pImage; // processor will fill this out, the one who adds this command must free the data as well
}; };
struct SCommand_VideoModes : public SCommand struct SCommand_VideoModes : public SCommand
{ {
SCommand_VideoModes(int screen) : SCommand(CMD_VIDEOMODES), SCommand_VideoModes() : SCommand(CMD_VIDEOMODES) {}
m_Screen(screen) {}
CVideoMode *m_pModes; // processor will fill this in CVideoMode *m_pModes; // processor will fill this in
int m_MaxModes; // maximum of modes the processor can write to the m_pModes int m_MaxModes; // maximum of modes the processor can write to the m_pModes
@ -204,6 +207,14 @@ public:
int m_Finish; int m_Finish;
}; };
struct SCommand_VSync : public SCommand
{
SCommand_VSync() : SCommand(CMD_VSYNC) {}
int m_VSync;
bool *m_pRetOk;
};
struct SCommand_Texture_Create : public SCommand struct SCommand_Texture_Create : public SCommand
{ {
SCommand_Texture_Create() : SCommand(CMD_TEXTURE_CREATE) {} SCommand_Texture_Create() : SCommand(CMD_TEXTURE_CREATE) {}
@ -302,13 +313,20 @@ public:
virtual ~IGraphicsBackend() {} virtual ~IGraphicsBackend() {}
virtual int Init(const char *pName, int Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight) = 0; virtual int Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight) = 0;
virtual int Shutdown() = 0; virtual int Shutdown() = 0;
virtual int MemoryUsage() const = 0; virtual int MemoryUsage() const = 0;
virtual int GetTextureArraySize() const = 0;
virtual int GetNumScreens() const = 0;
virtual void Minimize() = 0; virtual void Minimize() = 0;
virtual void Maximize() = 0; virtual void Maximize() = 0;
virtual bool Fullscreen(bool State) = 0;
virtual void SetWindowBordered(bool State) = 0;
virtual bool SetWindowScreen(int Index) = 0;
virtual int GetWindowScreen() = 0;
virtual int WindowActive() = 0; virtual int WindowActive() = 0;
virtual int WindowOpen() = 0; virtual int WindowOpen() = 0;
@ -356,6 +374,7 @@ class CGraphics_Threaded : public IEngineGraphics
CTextureHandle m_InvalidTexture; CTextureHandle m_InvalidTexture;
int m_TextureArrayIndex;
int m_aTextureIndices[MAX_TEXTURES]; int m_aTextureIndices[MAX_TEXTURES];
int m_FirstFreeTexture; int m_FirstFreeTexture;
int m_TextureMemoryUsage; int m_TextureMemoryUsage;
@ -391,7 +410,7 @@ public:
virtual void LinesEnd(); virtual void LinesEnd();
virtual void LinesDraw(const CLineItem *pArray, int Num); virtual void LinesDraw(const CLineItem *pArray, int Num);
virtual int UnloadTexture(IGraphics::CTextureHandle Index); virtual int UnloadTexture(IGraphics::CTextureHandle *Index);
virtual IGraphics::CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags); virtual IGraphics::CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags);
virtual int LoadTextureRawSub(IGraphics::CTextureHandle TextureID, int x, int y, int Width, int Height, int Format, const void *pData); virtual int LoadTextureRawSub(IGraphics::CTextureHandle TextureID, int x, int y, int Width, int Height, int Format, const void *pData);
@ -413,6 +432,7 @@ public:
virtual void SetColor(float r, float g, float b, float a); virtual void SetColor(float r, float g, float b, float a);
virtual void SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft, vec4 BottomRight); virtual void SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft, vec4 BottomRight);
void TilesetFallbackSystem(int TextureIndex);
virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex = -1); virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex = -1);
virtual void QuadsSetSubsetFree( virtual void QuadsSetSubsetFree(
float x0, float y0, float x1, float y1, float x0, float y0, float x1, float y1,
@ -423,8 +443,13 @@ public:
virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num); virtual void QuadsDrawFreeform(const CFreeformItem *pArray, int Num);
virtual void QuadsText(float x, float y, float Size, const char *pText); virtual void QuadsText(float x, float y, float Size, const char *pText);
virtual int GetNumScreens() const;
virtual void Minimize(); virtual void Minimize();
virtual void Maximize(); virtual void Maximize();
virtual bool Fullscreen(bool State);
virtual void SetWindowBordered(bool State);
virtual bool SetWindowScreen(int Index);
virtual int GetWindowScreen();
virtual int WindowActive(); virtual int WindowActive();
virtual int WindowOpen(); virtual int WindowOpen();
@ -432,8 +457,10 @@ public:
virtual int Init(); virtual int Init();
virtual void Shutdown(); virtual void Shutdown();
virtual void ReadBackbuffer(unsigned char **ppPixels, int x, int y, int w, int h);
virtual void TakeScreenshot(const char *pFilename); virtual void TakeScreenshot(const char *pFilename);
virtual void Swap(); virtual void Swap();
virtual bool SetVSync(bool State);
virtual int GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen); virtual int GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen);

View file

@ -4,26 +4,30 @@
#include <base/system.h> #include <base/system.h>
#include <engine/shared/config.h> #include <engine/shared/config.h>
#include <engine/console.h>
#include <engine/graphics.h> #include <engine/graphics.h>
#include <engine/input.h> #include <engine/input.h>
#include <engine/keys.h> #include <engine/keys.h>
#include "input.h" #include "input.h"
//print >>f, "int inp_key_code(const char *key_name) { int i; if (!strcmp(key_name, \"-?-\")) return -1; else for (i = 0; i < 512; i++) if (!strcmp(key_strings[i], key_name)) return i; return -1; }"
// this header is protected so you don't include it from anywere // this header is protected so you don't include it from anywere
#define KEYS_INCLUDE #define KEYS_INCLUDE
#include "keynames.h" #include "keynames.h"
#undef KEYS_INCLUDE #undef KEYS_INCLUDE
void CInput::AddEvent(int Unicode, int Key, int Flags) void CInput::AddEvent(char *pText, int Key, int Flags)
{ {
if(m_NumEvents != INPUT_BUFFER_SIZE) if(m_NumEvents != INPUT_BUFFER_SIZE)
{ {
m_aInputEvents[m_NumEvents].m_Unicode = Unicode;
m_aInputEvents[m_NumEvents].m_Key = Key; m_aInputEvents[m_NumEvents].m_Key = Key;
m_aInputEvents[m_NumEvents].m_Flags = Flags; m_aInputEvents[m_NumEvents].m_Flags = Flags;
if(!pText)
m_aInputEvents[m_NumEvents].m_aText[0] = 0;
else
str_copy(m_aInputEvents[m_NumEvents].m_aText, pText, sizeof(m_aInputEvents[m_NumEvents].m_aText));
m_aInputEvents[m_NumEvents].m_InputCount = m_InputCounter;
m_NumEvents++; m_NumEvents++;
} }
} }
@ -33,9 +37,8 @@ CInput::CInput()
mem_zero(m_aInputCount, sizeof(m_aInputCount)); mem_zero(m_aInputCount, sizeof(m_aInputCount));
mem_zero(m_aInputState, sizeof(m_aInputState)); mem_zero(m_aInputState, sizeof(m_aInputState));
m_InputCurrent = 0; m_InputCounter = 1;
m_InputGrabbed = 0; m_InputGrabbed = 0;
m_InputDispatched = false;
m_LastRelease = 0; m_LastRelease = 0;
m_ReleaseDelta = -1; m_ReleaseDelta = -1;
@ -46,21 +49,21 @@ CInput::CInput()
void CInput::Init() void CInput::Init()
{ {
m_pGraphics = Kernel()->RequestInterface<IEngineGraphics>(); m_pGraphics = Kernel()->RequestInterface<IEngineGraphics>();
m_pConsole = Kernel()->RequestInterface<IConsole>();
// FIXME: unicode handling: use SDL_StartTextInput/SDL_StopTextInput on inputs // FIXME: unicode handling: use SDL_StartTextInput/SDL_StopTextInput on inputs
// FIXME: key repeat: not a global setting anymore; need to do manually
SDL_SetRelativeMouseMode(SDL_TRUE); MouseModeRelative();
} }
void CInput::MouseRelative(float *x, float *y) void CInput::MouseRelative(float *x, float *y)
{ {
if(!m_InputGrabbed)
return;
int nx = 0, ny = 0; int nx = 0, ny = 0;
float Sens = g_Config.m_InpMousesens/100.0f; float Sens = g_Config.m_InpMousesens/100.0f;
if(m_InputGrabbed)
{
SDL_GetRelativeMouseState(&nx,&ny); SDL_GetRelativeMouseState(&nx,&ny);
}
*x = nx*Sens; *x = nx*Sens;
*y = ny*Sens; *y = ny*Sens;
@ -68,14 +71,27 @@ void CInput::MouseRelative(float *x, float *y)
void CInput::MouseModeAbsolute() void CInput::MouseModeAbsolute()
{ {
if(m_InputGrabbed)
{
m_InputGrabbed = 0; m_InputGrabbed = 0;
SDL_ShowCursor(SDL_ENABLE);
SDL_SetRelativeMouseMode(SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE);
}
} }
void CInput::MouseModeRelative() void CInput::MouseModeRelative()
{ {
if(!m_InputGrabbed)
{
m_InputGrabbed = 1; m_InputGrabbed = 1;
SDL_ShowCursor(SDL_DISABLE);
if(SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, g_Config.m_InpGrab ? "0" : "1", SDL_HINT_OVERRIDE) == SDL_FALSE)
{
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "input", "unable to switch relative mouse mode");
}
SDL_SetRelativeMouseMode(SDL_TRUE); SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_GetRelativeMouseState(NULL, NULL);
}
} }
int CInput::MouseDoubleClick() int CInput::MouseDoubleClick()
@ -89,47 +105,42 @@ int CInput::MouseDoubleClick()
return 0; return 0;
} }
void CInput::ClearKeyStates() void CInput::Clear()
{ {
mem_zero(m_aInputState, sizeof(m_aInputState)); mem_zero(m_aInputState, sizeof(m_aInputState));
mem_zero(m_aInputCount, sizeof(m_aInputCount)); mem_zero(m_aInputCount, sizeof(m_aInputCount));
m_NumEvents = 0;
} }
int CInput::KeyState(int Key) bool CInput::KeyState(int Key) const
{ {
return m_aInputState[m_InputCurrent][Key]; return m_aInputState[Key>=KEY_MOUSE_1 ? Key : SDL_GetScancodeFromKey(KeyToKeycode(Key))];
} }
int CInput::Update() int CInput::Update()
{ {
if(m_InputDispatched) // keep the counter between 1..0xFFFF, 0 means not pressed
{ m_InputCounter = (m_InputCounter%0xFFFF)+1;
// clear and begin count on the other one
m_InputCurrent^=1;
mem_zero(&m_aInputCount[m_InputCurrent], sizeof(m_aInputCount[m_InputCurrent]));
mem_zero(&m_aInputState[m_InputCurrent], sizeof(m_aInputState[m_InputCurrent]));
m_InputDispatched = false;
}
{ {
int i; int i;
const Uint8 *pState = SDL_GetKeyboardState(&i); const Uint8 *pState = SDL_GetKeyboardState(&i);
if(i >= KEY_LAST) if(i >= KEY_LAST)
i = KEY_LAST-1; i = KEY_LAST-1;
mem_copy(m_aInputState[m_InputCurrent], pState, i); mem_copy(m_aInputState, pState, i);
} }
// these states must always be updated manually because they are not in the GetKeyState from SDL // these states must always be updated manually because they are not in the GetKeyState from SDL
int i = SDL_GetMouseState(NULL, NULL); int i = SDL_GetMouseState(NULL, NULL);
if(i&SDL_BUTTON(1)) m_aInputState[m_InputCurrent][KEY_MOUSE_1] = 1; // 1 is left if(i&SDL_BUTTON(1)) m_aInputState[KEY_MOUSE_1] = 1; // 1 is left
if(i&SDL_BUTTON(3)) m_aInputState[m_InputCurrent][KEY_MOUSE_2] = 1; // 3 is right if(i&SDL_BUTTON(3)) m_aInputState[KEY_MOUSE_2] = 1; // 3 is right
if(i&SDL_BUTTON(2)) m_aInputState[m_InputCurrent][KEY_MOUSE_3] = 1; // 2 is middle if(i&SDL_BUTTON(2)) m_aInputState[KEY_MOUSE_3] = 1; // 2 is middle
if(i&SDL_BUTTON(4)) m_aInputState[m_InputCurrent][KEY_MOUSE_4] = 1; if(i&SDL_BUTTON(4)) m_aInputState[KEY_MOUSE_4] = 1;
if(i&SDL_BUTTON(5)) m_aInputState[m_InputCurrent][KEY_MOUSE_5] = 1; if(i&SDL_BUTTON(5)) m_aInputState[KEY_MOUSE_5] = 1;
if(i&SDL_BUTTON(6)) m_aInputState[m_InputCurrent][KEY_MOUSE_6] = 1; if(i&SDL_BUTTON(6)) m_aInputState[KEY_MOUSE_6] = 1;
if(i&SDL_BUTTON(7)) m_aInputState[m_InputCurrent][KEY_MOUSE_7] = 1; if(i&SDL_BUTTON(7)) m_aInputState[KEY_MOUSE_7] = 1;
if(i&SDL_BUTTON(8)) m_aInputState[m_InputCurrent][KEY_MOUSE_8] = 1; if(i&SDL_BUTTON(8)) m_aInputState[KEY_MOUSE_8] = 1;
if(i&SDL_BUTTON(9)) m_aInputState[m_InputCurrent][KEY_MOUSE_9] = 1; if(i&SDL_BUTTON(9)) m_aInputState[KEY_MOUSE_9] = 1;
{ {
SDL_Event Event; SDL_Event Event;
@ -137,26 +148,23 @@ int CInput::Update()
while(SDL_PollEvent(&Event)) while(SDL_PollEvent(&Event))
{ {
int Key = -1; int Key = -1;
int Scancode = 0;
int Action = IInput::FLAG_PRESS; int Action = IInput::FLAG_PRESS;
switch (Event.type) switch (Event.type)
{ {
case SDL_TEXTINPUT: case SDL_TEXTINPUT:
{ AddEvent(Event.text.text, 0, IInput::FLAG_TEXT);
int TextLength, i; break;
TextLength = strlen(Event.text.text);
for(i = 0; i < TextLength; i++)
{
AddEvent(Event.text.text[i], 0, 0);
}
}
// handle keys // handle keys
case SDL_KEYDOWN: case SDL_KEYDOWN:
Key = SDL_GetScancodeFromName(SDL_GetKeyName(Event.key.keysym.sym)); Key = KeycodeToKey(Event.key.keysym.sym);
Scancode = Event.key.keysym.scancode;
break; break;
case SDL_KEYUP: case SDL_KEYUP:
Action = IInput::FLAG_RELEASE; Action = IInput::FLAG_RELEASE;
Key = SDL_GetScancodeFromName(SDL_GetKeyName(Event.key.keysym.sym)); Key = KeycodeToKey(Event.key.keysym.sym);
Scancode = Event.key.keysym.scancode;
break; break;
// handle mouse buttons // handle mouse buttons
@ -174,19 +182,31 @@ int CInput::Update()
if(Event.button.button == SDL_BUTTON_LEFT) Key = KEY_MOUSE_1; // ignore_convention if(Event.button.button == SDL_BUTTON_LEFT) Key = KEY_MOUSE_1; // ignore_convention
if(Event.button.button == SDL_BUTTON_RIGHT) Key = KEY_MOUSE_2; // ignore_convention if(Event.button.button == SDL_BUTTON_RIGHT) Key = KEY_MOUSE_2; // ignore_convention
if(Event.button.button == SDL_BUTTON_MIDDLE) Key = KEY_MOUSE_3; // ignore_convention if(Event.button.button == SDL_BUTTON_MIDDLE) Key = KEY_MOUSE_3; // ignore_convention
if(Event.button.button == 4) Key = KEY_MOUSE_4; // ignore_convention
if(Event.button.button == 5) Key = KEY_MOUSE_5; // ignore_convention
if(Event.button.button == 6) Key = KEY_MOUSE_6; // ignore_convention if(Event.button.button == 6) Key = KEY_MOUSE_6; // ignore_convention
if(Event.button.button == 7) Key = KEY_MOUSE_7; // ignore_convention if(Event.button.button == 7) Key = KEY_MOUSE_7; // ignore_convention
if(Event.button.button == 8) Key = KEY_MOUSE_8; // ignore_convention if(Event.button.button == 8) Key = KEY_MOUSE_8; // ignore_convention
if(Event.button.button == 9) Key = KEY_MOUSE_9; // ignore_convention if(Event.button.button == 9) Key = KEY_MOUSE_9; // ignore_convention
Scancode = Key;
break; break;
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
if(Event.wheel.y > 0) Key = KEY_MOUSE_WHEEL_UP; // ignore_convention if(Event.wheel.y > 0) Key = KEY_MOUSE_WHEEL_UP; // ignore_convention
if(Event.wheel.y < 0) Key = KEY_MOUSE_WHEEL_DOWN; // ignore_convention if(Event.wheel.y < 0) Key = KEY_MOUSE_WHEEL_DOWN; // ignore_convention
AddEvent(0, Key, Action); Action |= IInput::FLAG_RELEASE;
Action = IInput::FLAG_RELEASE;
break; break;
#if defined(CONF_PLATFORM_MACOSX) // Todo SDL: remove this when fixed (mouse state is faulty on start)
case SDL_WINDOWEVENT:
if(Event.window.event == SDL_WINDOWEVENT_MAXIMIZED)
{
MouseModeAbsolute();
MouseModeRelative();
}
break;
#endif
// other messages // other messages
case SDL_QUIT: case SDL_QUIT:
return 1; return 1;
@ -195,9 +215,11 @@ int CInput::Update()
// //
if(Key != -1) if(Key != -1)
{ {
m_aInputCount[m_InputCurrent][Key].m_Presses++; if(Action&IInput::FLAG_PRESS)
if(Action == IInput::FLAG_PRESS) {
m_aInputState[m_InputCurrent][Key] = 1; m_aInputState[Scancode] = 1;
m_aInputCount[Key] = m_InputCounter;
}
AddEvent(0, Key, Action); AddEvent(0, Key, Action);
} }

View file

@ -6,13 +6,24 @@
class CInput : public IEngineInput class CInput : public IEngineInput
{ {
IEngineGraphics *m_pGraphics; IEngineGraphics *m_pGraphics;
IConsole *m_pConsole;
int m_InputGrabbed; int m_InputGrabbed;
int64 m_LastRelease; int64 m_LastRelease;
int64 m_ReleaseDelta; int64 m_ReleaseDelta;
void AddEvent(int Unicode, int Key, int Flags); void AddEvent(char *pText, int Key, int Flags);
void Clear();
bool IsEventValid(CEvent *pEvent) const { return pEvent->m_InputCount == m_InputCounter; };
//quick access to input
unsigned short m_aInputCount[g_MaxKeys]; // tw-KEY
unsigned char m_aInputState[g_MaxKeys]; // SDL_SCANCODE
int m_InputCounter;
void ClearKeyStates();
bool KeyState(int Key) const;
IEngineGraphics *Graphics() { return m_pGraphics; } IEngineGraphics *Graphics() { return m_pGraphics; }
@ -21,16 +32,14 @@ public:
virtual void Init(); virtual void Init();
bool KeyIsPressed(int Key) const { return KeyState(Key); }
bool KeyPress(int Key, bool CheckCounter) const { return CheckCounter ? (m_aInputCount[Key] == m_InputCounter) : m_aInputCount[Key]; }
virtual void MouseRelative(float *x, float *y); virtual void MouseRelative(float *x, float *y);
virtual void MouseModeAbsolute(); virtual void MouseModeAbsolute();
virtual void MouseModeRelative(); virtual void MouseModeRelative();
virtual int MouseDoubleClick(); virtual int MouseDoubleClick();
void ClearKeyStates();
int KeyState(int Key);
int ButtonPressed(int Button) { return m_aInputState[m_InputCurrent][Button]; }
virtual int Update(); virtual int Update();
}; };

View file

@ -4,14 +4,105 @@
#error do not include this header! #error do not include this header!
#endif #endif
#include <string.h>
const char g_aaKeyStrings[512][20] = const char g_aaKeyStrings[512][20] =
{ {
"unknown", "unknown",
"&1", "&1",
"&2", "&2",
"&3", "&3",
"&4",
"&5",
"&6",
"&7",
"backspace",
"tab",
"&10",
"&11",
"&12",
"return",
"&14",
"&15",
"&16",
"&17",
"&18",
"&19",
"&20",
"&21",
"&22",
"&23",
"&24",
"&25",
"&26",
"escape",
"&28",
"&29",
"&30",
"&31",
"space",
"exclaim",
"quotedbl",
"hash",
"dollar",
"percent",
"ampersand",
"quote",
"leftparen",
"rightparen",
"asterix",
"plus",
"comma",
"minus",
"period",
"slash",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"colon",
"semicolon",
"less",
"equals",
"greater",
"question",
"at",
"&65",
"&66",
"&67",
"&68",
"&69",
"&70",
"&71",
"&72",
"&73",
"&74",
"&75",
"&76",
"&77",
"&78",
"&79",
"&80",
"&81",
"&82",
"&83",
"&84",
"&85",
"&86",
"&87",
"&88",
"&89",
"&90",
"leftbracket",
"backslash",
"rightbracket",
"caret",
"underscore",
"backquote",
"a", "a",
"b", "b",
"c", "c",
@ -38,33 +129,68 @@ const char g_aaKeyStrings[512][20] =
"x", "x",
"y", "y",
"z", "z",
"1", "&123",
"2", "&124",
"3", "&125",
"4", "&126",
"5", "delete",
"6", "&128",
"7", "&129",
"8", "&130",
"9", "&131",
"0", "&132",
"return", "&133",
"escape", "&134",
"backspace", "&135",
"tab", "&136",
"space", "&137",
"minus", "&138",
"equals", "&139",
"leftbracket", "&140",
"rightbracket", "&141",
"backslash", "&142",
"nonushash", "&143",
"semicolon", "&144",
"apostrophe", "&145",
"grave", "&146",
"comma", "&147",
"period", "&148",
"slash", "&149",
"&150",
"&151",
"&152",
"&153",
"&154",
"&155",
"&156",
"&157",
"&158",
"&159",
"&160",
"&161",
"&162",
"&163",
"&164",
"&165",
"&166",
"&167",
"&168",
"&169",
"&170",
"&171",
"&172",
"&173",
"&174",
"&175",
"&176",
"&177",
"&178",
"&179",
"&180",
"&181",
"&182",
"&183",
"&184",
"capslock", "capslock",
"f1", "f1",
"f2", "f2",
@ -84,7 +210,7 @@ const char g_aaKeyStrings[512][20] =
"insert", "insert",
"home", "home",
"pageup", "pageup",
"delete", "&204",
"end", "end",
"pagedown", "pagedown",
"right", "right",
@ -108,7 +234,7 @@ const char g_aaKeyStrings[512][20] =
"kp_9", "kp_9",
"kp_0", "kp_0",
"kp_period", "kp_period",
"nonusbackslash", "&228",
"application", "application",
"power", "power",
"kp_equals", "kp_equals",
@ -138,29 +264,29 @@ const char g_aaKeyStrings[512][20] =
"mute", "mute",
"volumeup", "volumeup",
"volumedown", "volumedown",
"&130", "&258",
"&131", "&259",
"&132", "&260",
"kp_comma", "kp_comma",
"kp_equalsas400", "kp_equalsas400",
"international1", "&263",
"international2", "&264",
"international3", "&265",
"international4", "&266",
"international5", "&267",
"international6", "&268",
"international7", "&269",
"international8", "&270",
"international9", "&271",
"lang1", "&272",
"lang2", "&273",
"lang3", "&274",
"lang4", "&275",
"lang5", "&276",
"lang6", "&277",
"lang7", "&278",
"lang8", "&279",
"lang9", "&280",
"alterase", "alterase",
"sysreq", "sysreq",
"cancel", "cancel",
@ -173,17 +299,17 @@ const char g_aaKeyStrings[512][20] =
"clearagain", "clearagain",
"crsel", "crsel",
"exsel", "exsel",
"&165", "&293",
"&166", "&294",
"&167", "&295",
"&168", "&296",
"&169", "&297",
"&170", "&298",
"&171", "&299",
"&172", "&300",
"&173", "&301",
"&174", "&302",
"&175", "&303",
"kp_00", "kp_00",
"kp_000", "kp_000",
"thousandsseparator", "thousandsseparator",
@ -230,8 +356,8 @@ const char g_aaKeyStrings[512][20] =
"kp_octal", "kp_octal",
"kp_decimal", "kp_decimal",
"kp_hexadecimal", "kp_hexadecimal",
"&222", "&350",
"&223", "&351",
"lctrl", "lctrl",
"lshift", "lshift",
"lalt", "lalt",
@ -240,134 +366,6 @@ const char g_aaKeyStrings[512][20] =
"rshift", "rshift",
"ralt", "ralt",
"rgui", "rgui",
"&232",
"&233",
"&234",
"&235",
"&236",
"&237",
"&238",
"&239",
"&240",
"&241",
"&242",
"&243",
"&244",
"&245",
"&246",
"&247",
"&248",
"&249",
"&250",
"&251",
"&252",
"&253",
"&254",
"&255",
"&256",
"mode",
"audionext",
"audioprev",
"audiostop",
"audioplay",
"audiomute",
"mediaselect",
"www",
"mail",
"calculator",
"computer",
"ac_search",
"ac_home",
"ac_back",
"ac_forward",
"ac_stop",
"ac_refresh",
"ac_bookmarks",
"brightnessdown",
"brightnessup",
"displayswitch",
"kbdillumtoggle",
"kbdillumdown",
"kbdillumup",
"eject",
"sleep",
"app1",
"app2",
"mouse1",
"mouse2",
"mouse3",
"mouse4",
"mouse5",
"mouse6",
"mouse7",
"mouse8",
"mousewheelup",
"mousewheeldown",
"&295",
"&296",
"&297",
"&298",
"&299",
"&300",
"&301",
"&302",
"&303",
"&304",
"&305",
"&306",
"&307",
"&308",
"&309",
"&310",
"&311",
"&312",
"&313",
"&314",
"&315",
"&316",
"&317",
"&318",
"&319",
"&320",
"&321",
"&322",
"&323",
"&324",
"&325",
"&326",
"&327",
"&328",
"&329",
"&330",
"&331",
"&332",
"&333",
"&334",
"&335",
"&336",
"&337",
"&338",
"&339",
"&340",
"&341",
"&342",
"&343",
"&344",
"&345",
"&346",
"&347",
"&348",
"&349",
"&350",
"&351",
"&352",
"&353",
"&354",
"&355",
"&356",
"&357",
"&358",
"&359",
"&360", "&360",
"&361", "&361",
"&362", "&362",
@ -393,43 +391,43 @@ const char g_aaKeyStrings[512][20] =
"&382", "&382",
"&383", "&383",
"&384", "&384",
"&385", "mode",
"&386", "audionext",
"&387", "audioprev",
"&388", "audiostop",
"&389", "audioplay",
"&390", "audiomute",
"&391", "mediaselect",
"&392", "www",
"&393", "mail",
"&394", "calculator",
"&395", "computer",
"&396", "ac_search",
"&397", "ac_home",
"&398", "ac_back",
"&399", "ac_forward",
"&400", "ac_stop",
"&401", "ac_refresh",
"&402", "ac_bookmarks",
"&403", "brightnessdown",
"&404", "brightnessup",
"&405", "displayswitch",
"&406", "kbdillumtoggle",
"&407", "kbdillumdown",
"&408", "kpdillumup",
"&409", "eject",
"&410", "sleep",
"&411", "mouse1",
"&412", "mouse2",
"&413", "mouse3",
"&414", "mouse4",
"&415", "mouse5",
"&416", "mouse6",
"&417", "mouse7",
"&418", "mouse8",
"&419", "mouse9",
"&420", "mousewheelup",
"&421", "mousewheeldown",
"&422", "&422",
"&423", "&423",
"&424", "&424",

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more