Merge branch 'master' of https://github.com/teeworlds/teeworlds into feature-complexbinds

This commit is contained in:
Jordy Ruiz 2018-11-26 11:50:07 +01:00
commit 9e67d32fa5
123 changed files with 6794 additions and 3852 deletions

3
.gitignore vendored
View file

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

2
.gitmodules vendored
View file

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

View file

@ -17,10 +17,11 @@ class SoundSet(Struct):
self.sounds.Add(Sound(name))
class Image(Struct):
def __init__(self, name="", filename=""):
def __init__(self, name="", filename="", linear_mapping=0):
Struct.__init__(self, "CDataImage")
self.name = String(name)
self.filename = String(filename)
self.flag = Int(linear_mapping)
self.id = TextureHandle()
class SpriteSet(Struct):
@ -233,16 +234,20 @@ container.sounds.Add(SoundSet("menu", ["audio/music_menu.wv"]))
image_null = Image("null", "")
image_particles = Image("particles", "particles.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_demobuttons = Image("demobuttons", "ui/demo_buttons.png")
image_fileicons = Image("fileicons", "ui/file_icons.png")
image_guibuttons = Image("guibuttons", "ui/gui_buttons.png")
image_guiicons = Image("guiicons", "ui/gui_icons.png")
image_menuicons = Image("menuicons", "ui/icons/menu.png")
image_toolicons = Image("toolicons", "ui/icons/tools.png")
image_friendicons = Image("friendicons", "ui/icons/friend.png")
image_infoicons = Image("infoicons", "ui/icons/info.png")
image_demobuttons = Image("demobuttons", "ui/demo_buttons.png", 1)
image_fileicons = Image("fileicons", "ui/file_icons.png", 1)
image_guibuttons = Image("guibuttons", "ui/gui_buttons.png", 1)
image_guiicons = Image("guiicons", "ui/gui_icons.png", 1)
image_menuicons = Image("menuicons", "ui/icons/menu.png", 1)
image_toolicons = Image("toolicons", "ui/icons/tools.png", 1)
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_game)
@ -261,8 +266,12 @@ container.images.Add(image_guiicons)
container.images.Add(Image("no_skinpart", "ui/no_skinpart.png"))
container.images.Add(image_menuicons)
container.images.Add(image_toolicons)
container.images.Add(image_arrowicons)
container.images.Add(image_friendicons)
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("armor"))
@ -287,8 +296,11 @@ set_guibuttons = SpriteSet("guibuttons", image_guibuttons, 12, 4)
set_guiicons = SpriteSet("guiicons", image_guiicons, 8, 2)
set_menuicons = SpriteSet("menuicons", image_menuicons, 2, 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_levelicons = SpriteSet("levelicons", image_levelicons, 4, 4)
set_sidebaricons = SpriteSet("sidebaricons", image_sidebaricons, 4, 2)
container.spritesets.Add(set_particles)
container.spritesets.Add(set_game)
@ -306,8 +318,12 @@ container.spritesets.Add(set_guibuttons)
container.spritesets.Add(set_guiicons)
container.spritesets.Add(set_menuicons)
container.spritesets.Add(set_toolicons)
container.spritesets.Add(set_arrowicons)
container.spritesets.Add(set_friendicons)
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_ball", set_particles, 1,0,1,1))
@ -387,6 +403,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_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", set_tee_body, 1,0,1,1))
container.sprites.Add(Sprite("tee_body_shadow", set_tee_body, 0,1,1,1))
@ -472,6 +493,19 @@ 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_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))
@ -480,6 +514,24 @@ 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_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.body.frames.Add(AnimKeyframe(0, 0, -4, 0))
@ -552,7 +604,7 @@ weapon.damage.Set(1)
weapon.ammoregentime.Set(500)
weapon.visual_size.Set(64)
weapon.offsetx.Set(32)
weapon.offsety.Set(4)
weapon.offsety.Set(-4)
weapon.muzzleoffsetx.Set(50)
weapon.muzzleoffsety.Set(6)
container.weapons.gun.base.Set(weapon)

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 ad1818b3f3fd16edf1388976d697ff03b66d8c58
Subproject commit 5111dfa5ef0639045606bcda485dc32f7d24df49

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 133 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: 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

@ -1 +1 @@
Subproject commit 250e1e5d5cb2bf2ba4661b924a9bd79a352aa391
Subproject commit 31b9e3cd594396fdb482d228ed61bc454baee622

View file

@ -6,7 +6,7 @@ Emoticons = Enum("EMOTICON", ["OOP", "EXCLAMATION", "HEARTS", "DROP", "DOTDOT",
Votes = Enum("VOTE", ["UNKNOWN", "START_OP", "START_KICK", "START_SPEC", "END_ABORT", "END_PASS", "END_FAIL"])
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"])
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"])
@ -246,6 +246,7 @@ Messages = [
NetMessage("Sv_Chat", [
NetIntRange("m_Mode", 0, 'NUM_CHATS-1'),
NetIntRange("m_ClientID", -1, 'MAX_CLIENTS-1'),
NetIntRange("m_TargetID", -1, 'MAX_CLIENTS-1'),
NetStringStrict("m_pMessage"),
]),
@ -322,6 +323,7 @@ Messages = [
NetArray(NetStringStrict("m_apSkinPartNames"), 6),
NetArray(NetBool("m_aUseCustomColors"), 6),
NetArray(NetIntAny("m_aSkinPartColors"), 6),
NetBool("m_Silent"),
]),
NetMessage("Sv_GameInfo", [
@ -337,6 +339,7 @@ Messages = [
NetMessage("Sv_ClientDrop", [
NetIntRange("m_ClientID", 0, 'MAX_CLIENTS-1'),
NetStringStrict("m_pReason"),
NetBool("m_Silent"),
]),
NetMessage("Sv_GameMsg", []),

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

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/level.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 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-2016 Magnus Auvinen
Copyright (C) 2007-2018 Magnus Auvinen
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -21,6 +21,11 @@ freely, subject to the following restrictions:
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/).
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

View file

@ -88,6 +88,12 @@ def clean():
package = "%s-%s-%s" %(name, version, platform)
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")
shutil.rmtree(package_dir, True)
os.mkdir(package_dir)
@ -118,18 +124,17 @@ shutil.copy("license.txt", package_dir)
shutil.copy("storage.cfg", package_dir)
if include_data and not use_bundle:
os.mkdir(os.path.join(package_dir, "data"))
copydir("data", package_dir)
shutil.copytree(source_package_dir+"data", package_dir+"/data")
copyfiles(languages_dir, package_dir+"/data/languages")
copyfiles(maps_dir, package_dir+"/data/maps")
if platform[:3] == "win":
shutil.copy("other/config_directory.bat", package_dir)
shutil.copy("SDL.dll", package_dir)
shutil.copy("freetype.dll", package_dir)
shutil.copy(source_package_dir+"SDL2.dll", package_dir)
shutil.copy(source_package_dir+"freetype.dll", package_dir)
if include_exe and not use_bundle:
shutil.copy(name+exe_ext, package_dir)
shutil.copy(name+"_srv"+exe_ext, package_dir)
shutil.copy(source_package_dir+name+exe_ext, package_dir)
shutil.copy(source_package_dir+name+"_srv"+exe_ext, package_dir)
if include_src:
for p in ["src", "scripts", "datasrc", "other", "objs"]:

View file

@ -1,160 +1,172 @@
#!/bin/env python3
# coding: utf-8
from socket import *
import struct
import sys
import threading
import time
import random
NUM_MASTERSERVERS = 4
MASTERSERVER_PORT = 8300
MASTERSERVER_PORT = 8283
TIMEOUT = 2
SERVERTYPE_NORMAL = 0
SERVERTYPE_LEGACY = 1
# src/mastersrv/mastersrv.h
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_GETLIST2 = "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreq2"
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"
PACKET_GETINFO = b"\xff\xff\xff\xffgie3"
PACKET_INFO = b"\xff\xff\xff\xffinf3"
# 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] = (token_srv >> 24) & 0xff
b[1] = (token_srv >> 16) & 0xff
b[2] = (token_srv >> 8) & 0xff
b[3] = (token_srv) & 0xff
b[4] = (NET_PACKETFLAG_CONTROL<<2)&0xfc
# 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[0] << 24) + (b[1] << 16) + (b[2] << 8) + (b[3])
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
b[0] = (token_srv >> 24) & 0xff
b[1] = (token_srv >> 16) & 0xff
b[2] = (token_srv >> 8) & 0xff
b[3] = (token_srv) & 0xff
b[4] = ((NET_PACKETFLAG_CONNLESS<<2)&0xfc) | (NET_PACKETVERSION&0x03)
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):
def __init__(self, address, type):
def __init__(self, address):
self.address = address
self.type = type
self.finished = False
threading.Thread.__init__(self, target = self.run)
def run(self):
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)
if self.info:
self.info = get_server_info2(self.address)
self.info = get_server_info(self.address)
self.finished = True
def get_server_info(address):
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT);
sock.sendto(PACKET_GETINFO, address)
sock.settimeout(TIMEOUT)
token = random.randrange(0x100000000)
# Token request
sock.sendto(pack_control_msg_with_token(-1,token),address)
data, addr = sock.recvfrom(1024)
sock.close()
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)
data = data[14:] # skip header
slots = data.split("\x00")
server_info = {}
server_info["version"] = slots[0]
server_info["name"] = slots[1]
server_info["map"] = slots[2]
server_info["gametype"] = slots[3]
server_info["flags"] = int(slots[4])
server_info["progression"] = int(slots[5])
server_info["num_players"] = int(slots[6])
server_info["max_players"] = int(slots[7])
server_info["players"] = []
for i in xrange(0, server_info["num_players"]):
player = {}
player["name"] = slots[8+i*2]
player["score"] = int(slots[8+i*2+1])
server_info["players"].append(player)
return server_info
except:
sock.close()
return None
def get_server_info2(address):
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT);
sock.sendto(PACKET_GETINFO2, address)
# Get info request
sock.sendto(header_connless(token_srv, token_cl) + PACKET_GETINFO + b'\x00', address)
data, addr = sock.recvfrom(1024)
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()
data = data[14:] # skip header
slots = data.split("\x00")
data = data[len(head):] # skip header
slots = data.split(b"\x00", maxsplit=5)
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["version"] = slots[0].decode()
server_info["name"] = slots[1].decode()
server_info["hostname"] = slots[2].decode()
server_info["map"] = slots[3].decode()
server_info["gametype"] = slots[4].decode()
data = slots[5]
# these integers should fit in one byte each
server_info["flags"], server_info["skill"], server_info["num_players"], server_info["max_players"], server_info["num_clients"], server_info["max_clients"] = tuple(data[:6])
data = data[6:]
server_info["players"] = []
for i in xrange(0, server_info["num_players"]):
for i in range(server_info["num_clients"]):
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]):
slots = data.split(b"\x00", maxsplit=2)
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)
is_player, data = unpack_int(data)
if is_player:
player["player"] = True
else:
player["player"] = False
server_info["players"].append(player)
return server_info
except AssertionError as e:
print(*e.args)
except OSError as e: # Timeout
print('> Server %s did not answer' % (address,))
except:
# import traceback
# traceback.print_exc()
pass
finally:
sock.close()
return None
return None
class Master_Server_Info(threading.Thread):
@ -165,7 +177,7 @@ class Master_Server_Info(threading.Thread):
threading.Thread.__init__(self, target = self.run)
def run(self):
self.servers = get_list(self.address) + get_list2(self.address)
self.servers = get_list(self.address)
self.finished = True
@ -175,96 +187,88 @@ def get_list(address):
try:
sock = socket(AF_INET, SOCK_DGRAM)
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)
# 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:
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:]
num_servers = len(data) / 6
data = data[len(head):]
num_servers = len(data) // 18
for n in range(0, num_servers):
ip = ".".join(map(str, map(ord, data[n*6:n*6+4])))
port = ord(data[n*6+5]) * 256 + ord(data[n*6+4])
servers += [[(ip, port), SERVERTYPE_LEGACY]]
# IPv4
if data[n*18:n*18+12] == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff":
ip = ".".join(map(str, data[n*18+12:n*18+16]))
# IPv6
else:
ip = ":".join(map(str, data[n*18:n*18+16]))
port = ((data[n*18+16])<<8) + data[n*18+17]
servers += [(ip, port)]
except AssertionError as e:
print(*e.args)
except OSError as e: # Timeout
if not servers:
print('> Master %s did not answer' % (address,))
except:
# import traceback
# traceback.print_exc()
sock.close()
return servers
if __name__ == '__main__':
master_servers = []
for i in range(1, NUM_MASTERSERVERS+1):
m = Master_Server_Info(("master%d.teeworlds.com"%i, MASTERSERVER_PORT))
master_servers.append(m)
m.start()
time.sleep(0.001) # avoid issues
def get_list2(address):
servers = []
try:
sock = socket(AF_INET, SOCK_DGRAM)
sock.settimeout(TIMEOUT)
sock.sendto(PACKET_GETLIST2, address)
while len(master_servers) != 0:
if master_servers[0].finished == True:
if master_servers[0].servers:
servers += master_servers[0].servers
del master_servers[0]
time.sleep(0.001) # be nice
while 1:
data, addr = sock.recvfrom(1400)
data = data[14:]
num_servers = len(data) / 18
servers_info = []
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:
ip = ":".join(map(str, map(ord, data[n*18:n*18+16])))
port = (ord(data[n*18+16])<<8) + ord(data[n*18+17])
servers += [[(ip, port), SERVERTYPE_NORMAL]]
print(str(len(servers)) + " servers")
except:
sock.close()
for server in servers:
s = Server_Info(server)
servers_info.append(s)
s.start()
time.sleep(0.001) # avoid issues
return servers
num_players = 0
num_clients = 0
master_servers = []
for i in range(1, NUM_MASTERSERVERS+1):
m = Master_Server_Info(("master%d.teeworlds.com"%i, MASTERSERVER_PORT))
master_servers.append(m)
m.start()
time.sleep(0.001) # avoid issues
servers = []
while len(master_servers) != 0:
if master_servers[0].finished == True:
if master_servers[0].servers:
servers += master_servers[0].servers
del master_servers[0]
time.sleep(0.001) # be nice
servers_info = []
print str(len(servers)) + " servers"
for server in servers:
s = Server_Info(server[0], server[1])
servers_info.append(s)
s.start()
time.sleep(0.001) # avoid issues
num_players = 0
num_clients = 0
while len(servers_info) != 0:
if servers_info[0].finished == True:
if servers_info[0].info:
num_players += servers_info[0].info["num_players"]
if servers_info[0].type == SERVERTYPE_NORMAL:
while len(servers_info) != 0:
if servers_info[0].finished == True:
if servers_info[0].info:
num_players += servers_info[0].info["num_players"]
num_clients += servers_info[0].info["num_clients"]
else:
num_clients += servers_info[0].info["num_players"]
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(str(num_players) + " players and " + str(num_clients-num_players) + " spectators")

View file

@ -362,7 +362,10 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
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);
gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData);
}

View file

@ -377,20 +377,6 @@ bool CClient::ConnectionProblems() const
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()
{
int64 Now = time_get();
@ -418,6 +404,12 @@ void CClient::SendInput()
for(int i = 0; i < Size/4; 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%=200;
@ -836,9 +828,9 @@ int CClient::PlayerScoreComp(const void *a, const void *b)
{
CServerInfo::CClient *p0 = (CServerInfo::CClient *)a;
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;
if(!p0->m_Player && p1->m_Player)
if((p0->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC) && !(p1->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC))
return 1;
if(p0->m_Score == p1->m_Score)
return 0;
@ -865,6 +857,8 @@ int CClient::UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pTo
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 > MAX_CLIENTS || pInfo->m_MaxClients < 0 || pInfo->m_MaxClients > MAX_CLIENTS ||
@ -875,14 +869,30 @@ int CClient::UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pTo
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_Player = pUnpacker->GetInt() != 0 ? true : false;
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;
}
@ -1381,7 +1391,6 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
m_GameTime.Init((GameTick-1)*time_freq()/50);
m_aSnapshots[SNAP_PREV] = m_SnapshotStorage.m_pFirst;
m_aSnapshots[SNAP_CURRENT] = m_SnapshotStorage.m_pLast;
m_LocalStartTime = time_get();
SetState(IClient::STATE_ONLINE);
DemoRecorder_HandleAutoStart();
}
@ -1671,20 +1680,25 @@ void CClient::VersionUpdate()
{
if(m_VersionInfo.m_VersionServeraddr.m_Job.Status() == CJob::STATE_DONE)
{
CNetChunk Packet;
if(m_VersionInfo.m_VersionServeraddr.m_Job.Result() == 0)
{
CNetChunk Packet;
mem_zero(&Packet, sizeof(Packet));
mem_zero(&Packet, sizeof(Packet));
m_VersionInfo.m_VersionServeraddr.m_Addr.port = VERSIONSRV_PORT;
m_VersionInfo.m_VersionServeraddr.m_Addr.port = VERSIONSRV_PORT;
Packet.m_ClientID = -1;
Packet.m_Address = m_VersionInfo.m_VersionServeraddr.m_Addr;
Packet.m_pData = VERSIONSRV_GETVERSION;
Packet.m_DataSize = sizeof(VERSIONSRV_GETVERSION);
Packet.m_Flags = NETSENDFLAG_CONNLESS;
Packet.m_ClientID = -1;
Packet.m_Address = m_VersionInfo.m_VersionServeraddr.m_Addr;
Packet.m_pData = VERSIONSRV_GETVERSION;
Packet.m_DataSize = sizeof(VERSIONSRV_GETVERSION);
Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_ContactClient.Send(&Packet);
m_VersionInfo.m_State = CVersionInfo::STATE_READY;
m_ContactClient.Send(&Packet);
m_VersionInfo.m_State = CVersionInfo::STATE_READY;
}
else
m_VersionInfo.m_State = CVersionInfo::STATE_ERROR;
}
}
}
@ -2071,6 +2085,8 @@ void CClient::Run()
m_pGraphics->Shutdown();
m_pSound->Shutdown();
m_ServerBrowser.SaveServerlist();
// shutdown SDL
{
SDL_Quit();
@ -2395,8 +2411,6 @@ void CClient::RegisterCommands()
// used for server browser update
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);
@ -2431,14 +2445,27 @@ void CClient::HandleTeeworldsConnectLink(const char *pConLink)
int main(int argc, const char **argv) // ignore_convention
{
#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
{
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
{
FreeConsole();
HideConsole = true;
break;
}
}
if(HideConsole)
FreeConsole();
#endif
bool UseDefaultConfig = false;

View file

@ -174,6 +174,7 @@ class CClient : public IClient, public CDemoPlayer::IListner
STATE_INIT=0,
STATE_START,
STATE_READY,
STATE_ERROR,
};
int m_State;
@ -211,7 +212,6 @@ public:
virtual IGraphics::CTextureHandle GetDebugFont() const { return m_DebugFont; }
void DirectInput(int *pInput, int Size);
void SendInput();
// TODO: OPT: do this alot smarter!

View file

@ -360,6 +360,8 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig
}
if(Flags&IGraphics::TEXLOAD_MULTI_DIMENSION)
Cmd.m_Flags |= CCommandBuffer::TEXFLAG_TEXTURE3D;
if(Flags&IGraphics::TEXLOAD_NOMIPMAPS)
Cmd.m_Flags |= CCommandBuffer::TEXTFLAG_LINEARMIPMAPS;
// copy texture data

View file

@ -100,6 +100,7 @@ public:
TEXFLAG_QUALITY = 4,
TEXFLAG_TEXTURE3D = 8,
TEXFLAG_TEXTURE2D = 16,
TEXTFLAG_LINEARMIPMAPS = 32,
};
enum

View file

@ -3,6 +3,8 @@
#include <base/math.h>
#include <base/system.h>
#include <engine/external/json-parser/json.h>
#include <engine/shared/config.h>
#include <engine/shared/memheap.h>
#include <engine/shared/network.h>
@ -13,12 +15,15 @@
#include <engine/engine.h>
#include <engine/friends.h>
#include <engine/masterserver.h>
#include <engine/storage.h>
#include <mastersrv/mastersrv.h>
#include "serverbrowser.h"
static const char *s_pFilename = "serverlist.json";
inline int AddrHash(const NETADDR *pAddr)
{
if(pAddr->type==NETTYPE_IPV4)
@ -39,6 +44,7 @@ void CServerBrowser::CServerlist::Clear()
m_ServerlistHeap.Reset();
m_NumServers = 0;
m_NumPlayers = 0;
m_NumClients = 0;
mem_zero(m_aServerlistIp, sizeof(m_aServerlistIp));
}
@ -66,11 +72,13 @@ CServerBrowser::CServerBrowser()
m_ActServerlistType = 0;
m_BroadcastTime = 0;
m_MasterRefreshTime = 0;
}
void CServerBrowser::Init(class CNetClient *pNetClient, const char *pNetVersion)
{
m_pConsole = Kernel()->RequestInterface<IConsole>();
m_pStorage = Kernel()->RequestInterface<IStorage>();
m_pMasterServer = Kernel()->RequestInterface<IMasterServer>();
m_pNetClient = pNetClient;
@ -88,6 +96,8 @@ void CServerBrowser::Set(const NETADDR &Addr, int SetType, int Token, const CSer
if(!(m_RefreshFlags&IServerBrowser::REFRESHFLAG_INTERNET))
return;
m_MasterRefreshTime = 0;
if(!Find(IServerBrowser::TYPE_INTERNET, Addr))
{
pEntry = Add(IServerBrowser::TYPE_INTERNET, Addr);
@ -95,17 +105,18 @@ void CServerBrowser::Set(const NETADDR &Addr, int SetType, int Token, const CSer
}
}
break;
/*else if(Type == SET_FAV_ADD)
{
if(m_ServerlistType != IServerBrowser::TYPE_FAVORITES)
return;
if(!Find(Addr))
case SET_FAV_ADD:
{
pEntry = Add(Addr);
QueueRequest(pEntry);
if(!(m_RefreshFlags&IServerBrowser::REFRESHFLAG_INTERNET))
return;
if(!Find(IServerBrowser::TYPE_INTERNET, Addr))
{
pEntry = Add(IServerBrowser::TYPE_INTERNET, Addr);
QueueRequest(pEntry);
}
}
}*/
break;
case SET_TOKEN:
{
int Type;
@ -116,7 +127,7 @@ void CServerBrowser::Set(const NETADDR &Addr, int SetType, int Token, const CSer
Type = IServerBrowser::TYPE_INTERNET;
pEntry = Find(Type, Addr);
if(pEntry && (pEntry->m_InfoState != CServerEntry::STATE_PENDING || Token != pEntry->m_CurrentToken))
pEntry = 0;
pEntry = 0;
}
// lan entry
@ -125,7 +136,7 @@ void CServerBrowser::Set(const NETADDR &Addr, int SetType, int Token, const CSer
Type = IServerBrowser::TYPE_LAN;
pEntry = Add(Type, Addr);
}
// set info
if(pEntry)
{
@ -172,10 +183,22 @@ void CServerBrowser::Update(bool ForceResort)
m_pNetClient->Send(&Packet);
}
m_MasterRefreshTime = Now;
if(g_Config.m_Debug)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", "requesting server list");
}
// load server list backup from file in case the masters don't response
if(m_MasterRefreshTime && m_MasterRefreshTime+2*Timeout < Now)
{
LoadServerlist();
m_MasterRefreshTime = 0;
if(g_Config.m_Debug)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", "using backup server list");
}
// do timeouts
pEntry = m_pFirstReqServer;
while(1)
@ -283,6 +306,10 @@ void CServerBrowser::Refresh(int RefreshFlags)
if(RefreshFlags&IServerBrowser::REFRESHFLAG_INTERNET)
{
// clear out everything
for(CServerEntry *pEntry = m_pFirstReqServer; pEntry; pEntry = pEntry->m_pNextReq)
{
m_pNetClient->PurgeStoredPacket(pEntry->m_TrackID);
}
m_aServerlist[IServerBrowser::TYPE_INTERNET].Clear();
if(m_ActServerlistType == IServerBrowser::TYPE_INTERNET)
m_ServerBrowserFilter.Clear();
@ -291,13 +318,10 @@ void CServerBrowser::Refresh(int RefreshFlags)
m_NumRequests = 0;
m_NeedRefresh = 1;
for(int i = 0; i < m_ServerBrowserFavorites.m_NumFavoriteServers; i++)
if(m_ServerBrowserFavorites.m_aFavoriteServers[i].m_State >= CServerBrowserFavorites::FAVSTATE_ADDR)
Set(m_ServerBrowserFavorites.m_aFavoriteServers[i].m_Addr, SET_FAV_ADD, -1, 0);
}
/*else if(Type == IServerBrowser::TYPE_FAVORITES)
{
for(int i = 0; i < m_NumFavoriteServers; i++)
if(m_aFavoriteServers[i].m_State >= FAVSTATE_ADDR)
Set(m_aFavoriteServers[i].m_Addr, SET_FAV_ADD, -1, 0);
}*/
}
int CServerBrowser::LoadingProgression() const
@ -330,7 +354,7 @@ void CServerBrowser::AddFavorite(const CServerInfo *pInfo)
}
void CServerBrowser::RemoveFavorite(const CServerInfo *pInfo)
{
{
if(m_ServerBrowserFavorites.RemoveFavoriteEx(pInfo->m_aHostname, &pInfo->m_NetAddr))
{
for(int i = 0; i < NUM_TYPES; ++i)
@ -445,7 +469,29 @@ void CServerBrowser::RemoveRequest(CServerEntry *pEntry)
}
}
void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) const
void CServerBrowser::CBFTrackPacket(int TrackID, void *pCallbackUser)
{
if(!pCallbackUser)
return;
CServerBrowser *pSelf = (CServerBrowser *)pCallbackUser;
CServerEntry *pEntry = pSelf->m_pFirstReqServer;
while(1)
{
if(!pEntry) // no more entries
break;
if(pEntry->m_TrackID == TrackID) // got it -> update
{
pEntry->m_RequestTime = time_get();
break;
}
pEntry = pEntry->m_pNextReq;
}
}
void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry)
{
if(g_Config.m_Debug)
{
@ -460,15 +506,18 @@ void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) cons
Packer.Reset();
Packer.AddRaw(SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO));
Packer.AddInt(pEntry ? pEntry->m_CurrentToken : m_CurrentLanToken);
CNetChunk Packet;
Packet.m_ClientID = -1;
Packet.m_Address = Addr;
Packet.m_Flags = NETSENDFLAG_CONNLESS;
Packet.m_DataSize = Packer.Size();
Packet.m_pData = Packer.Data();
m_pNetClient->Send(&Packet);
CSendCBData Data;
Data.m_pfnCallback = CBFTrackPacket;
Data.m_pCallbackUser = this;
m_pNetClient->Send(&Packet, NET_TOKEN_NONE, &Data);
pEntry->m_TrackID = Data.m_TrackID;
if(pEntry)
{
@ -483,7 +532,7 @@ void CServerBrowser::SetInfo(int ServerlistType, CServerEntry *pEntry, const CSe
pEntry->m_Info = Info;
pEntry->m_Info.m_Flags &= FLAG_PASSWORD;
if(str_comp(pEntry->m_Info.m_aGameType, "DM") == 0 || str_comp(pEntry->m_Info.m_aGameType, "TDM") == 0 || str_comp(pEntry->m_Info.m_aGameType, "CTF") == 0 ||
str_comp(pEntry->m_Info.m_aGameType, "SUR") == 0 || str_comp(pEntry->m_Info.m_aGameType, "LMS") == 0)
str_comp(pEntry->m_Info.m_aGameType, "LTS") == 0 || str_comp(pEntry->m_Info.m_aGameType, "LMS") == 0)
pEntry->m_Info.m_Flags |= FLAG_PURE;
if(str_comp(pEntry->m_Info.m_aMap, "dm1") == 0 || str_comp(pEntry->m_Info.m_aMap, "dm2") == 0 || str_comp(pEntry->m_Info.m_aMap, "dm3") == 0 ||
str_comp(pEntry->m_Info.m_aMap, "dm6") == 0 || str_comp(pEntry->m_Info.m_aMap, "dm7") == 0 || str_comp(pEntry->m_Info.m_aMap, "dm8") == 0 ||
@ -491,12 +540,79 @@ void CServerBrowser::SetInfo(int ServerlistType, CServerEntry *pEntry, const CSe
str_comp(pEntry->m_Info.m_aMap, "ctf1") == 0 || str_comp(pEntry->m_Info.m_aMap, "ctf2") == 0 || str_comp(pEntry->m_Info.m_aMap, "ctf3") == 0 ||
str_comp(pEntry->m_Info.m_aMap, "ctf4") == 0 || str_comp(pEntry->m_Info.m_aMap, "ctf5") == 0 || str_comp(pEntry->m_Info.m_aMap, "ctf6") == 0 ||
str_comp(pEntry->m_Info.m_aMap, "ctf7") == 0 || str_comp(pEntry->m_Info.m_aMap, "ctf8") == 0 ||
str_comp(pEntry->m_Info.m_aMap, "sur1") == 0)
str_comp(pEntry->m_Info.m_aMap, "lms1") == 0)
pEntry->m_Info.m_Flags |= FLAG_PUREMAP;
pEntry->m_Info.m_Favorite = Fav;
pEntry->m_Info.m_NetAddr = pEntry->m_Addr;
m_aServerlist[ServerlistType].m_NumPlayers += pEntry->m_Info.m_NumPlayers;
m_aServerlist[ServerlistType].m_NumClients += pEntry->m_Info.m_NumClients;
pEntry->m_InfoState = CServerEntry::STATE_READY;
}
void CServerBrowser::LoadServerlist()
{
// read file data into buffer
IOHANDLE File = Storage()->OpenFile(s_pFilename, IOFLAG_READ, IStorage::TYPE_ALL);
if(!File)
return;
int FileSize = (int)io_length(File);
char *pFileData = (char *)mem_alloc(FileSize, 1);
io_read(File, pFileData, FileSize);
io_close(File);
// parse json data
json_settings JsonSettings;
mem_zero(&JsonSettings, sizeof(JsonSettings));
char aError[256];
json_value *pJsonData = json_parse_ex(&JsonSettings, pFileData, FileSize, aError);
mem_free(pFileData);
if(pJsonData == 0)
{
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, s_pFilename, aError);
return;
}
// extract server list
const json_value &rEntry = (*pJsonData)["serverlist"];
for(unsigned i = 0; i < rEntry.u.array.length; ++i)
{
if(rEntry[i].type == json_string)
{
NETADDR Addr = { 0 };
if(!net_addr_from_str(&Addr, rEntry[i]))
Set(Addr, SET_MASTER_ADD, -1, 0);
}
}
// clean up
json_value_free(pJsonData);
}
void CServerBrowser::SaveServerlist()
{
IOHANDLE File = Storage()->OpenFile(s_pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(!File)
return;
char aBuf[512];
// server list
const char *p = "{\"serverlist\": [\n";
io_write(File, p, str_length(p));
for(int i = 0; i < m_aServerlist[IServerBrowser::TYPE_INTERNET].m_NumServers; ++i)
{
// entry
str_format(aBuf, sizeof(aBuf), "\t\"%s\",\n", m_aServerlist[IServerBrowser::TYPE_INTERNET].m_ppServerlist[i]->m_Info.m_aAddress);
io_write(File, aBuf, str_length(aBuf));
}
// server list end
p = "\t]\n}\n";
io_write(File, p, str_length(p));
io_close(File);
}

View file

@ -32,9 +32,11 @@ public:
int NumServers() const { return m_aServerlist[m_ActServerlistType].m_NumServers; }
int NumPlayers() const { return m_aServerlist[m_ActServerlistType].m_NumPlayers; }
int NumClients() const { return m_aServerlist[m_ActServerlistType].m_NumClients; }
const CServerInfo *Get(int Index) const { return &m_aServerlist[m_ActServerlistType].m_ppServerlist[Index]->m_Info; };
int NumSortedServers(int Index) const { return m_ServerBrowserFilter.GetNumSortedServers(Index); }
int NumSortedPlayers(int Index) const { return m_ServerBrowserFilter.GetNumSortedPlayers(Index); }
int NumSortedServers(int FilterIndex) const { return m_ServerBrowserFilter.GetNumSortedServers(FilterIndex); }
int NumSortedPlayers(int FilterIndex) const { return m_ServerBrowserFilter.GetNumSortedPlayers(FilterIndex); }
const CServerInfo *SortedGet(int FilterIndex, int Index) const { return &m_aServerlist[m_ActServerlistType].m_ppServerlist[m_ServerBrowserFilter.GetIndex(FilterIndex, Index)]->m_Info; };
const void *GetID(int FilterIndex, int Index) const { return m_ServerBrowserFilter.GetID(FilterIndex, Index); };
@ -47,14 +49,23 @@ public:
void GetFilter(int Index, CServerFilterInfo *pFilterInfo) { m_ServerBrowserFilter.GetFilter(Index, pFilterInfo); };
void RemoveFilter(int Index) { m_ServerBrowserFilter.RemoveFilter(Index); };
static void CBFTrackPacket(int TrackID, void *pUser);
void LoadServerlist();
void SaveServerlist();
private:
class CNetClient *m_pNetClient;
class IConsole *m_pConsole;
class IStorage *m_pStorage;
class IMasterServer *m_pMasterServer;
class CServerBrowserFavorites m_ServerBrowserFavorites;
class CServerBrowserFilter m_ServerBrowserFilter;
class IConsole *Console() const { return m_pConsole; }
class IStorage *Storage() const { return m_pStorage; }
// serverlist
int m_ActServerlistType;
class CServerlist
@ -62,6 +73,7 @@ private:
public:
class CHeap m_ServerlistHeap;
int m_NumClients;
int m_NumPlayers;
int m_NumServers;
int m_NumServerCapacity;
@ -83,12 +95,13 @@ private:
int m_RefreshFlags;
int64 m_BroadcastTime;
int64 m_MasterRefreshTime;
CServerEntry *Add(int ServerlistType, const NETADDR &Addr);
CServerEntry *Find(int ServerlistType, const NETADDR &Addr);
void QueueRequest(CServerEntry *pEntry);
void RemoveRequest(CServerEntry *pEntry);
void RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) const;
void RequestImpl(const NETADDR &Addr, CServerEntry *pEntry);
void SetInfo(int ServerlistType, CServerEntry *pEntry, const CServerInfo &Info);
};

View file

@ -17,6 +17,7 @@ public:
int64 m_RequestTime;
int m_InfoState;
int m_CurrentToken; // the token is to keep server refresh separated from each other
int m_TrackID;
class CServerInfo m_Info;
CServerEntry *m_pNextIp; // ip hashed list

View file

@ -28,11 +28,13 @@ CServerBrowserFilter::CServerFilter::CServerFilter()
{
m_pServerBrowserFilter = 0;
m_SortHash = 0;
m_Ping = 0;
m_Country = 0;
m_aGametype[0] = 0;
m_aServerAddress[0] = 0;
m_FilterInfo.m_SortHash = 0;
m_FilterInfo.m_Ping = 0;
m_FilterInfo.m_Country = 0;
m_FilterInfo.m_ServerLevel = 0;
for(int i = 0; i < CServerFilterInfo::MAX_GAMETYPES; ++i)
m_FilterInfo.m_aGametype[i][0] = 0;
m_FilterInfo.m_aAddress[0] = 0;
m_NumSortedPlayers = 0;
m_NumSortedServers = 0;
@ -43,7 +45,37 @@ CServerBrowserFilter::CServerFilter::CServerFilter()
CServerBrowserFilter::CServerFilter::~CServerFilter()
{
mem_free(m_pSortedServerlist);
if(m_pSortedServerlist)
mem_free(m_pSortedServerlist);
}
CServerBrowserFilter::CServerFilter& CServerBrowserFilter::CServerFilter::operator=(const CServerBrowserFilter::CServerFilter& Other)
{
if(&Other != this)
{
m_pServerBrowserFilter = Other.m_pServerBrowserFilter;
m_FilterInfo.m_SortHash = Other.m_FilterInfo.m_SortHash;
m_FilterInfo.m_Ping = Other.m_FilterInfo.m_Ping;
m_FilterInfo.m_Country = Other.m_FilterInfo.m_Country;
m_FilterInfo.m_ServerLevel = Other.m_FilterInfo.m_ServerLevel;
for(int i = 0; i < CServerFilterInfo::MAX_GAMETYPES; ++i)
{
if(Other.m_FilterInfo.m_aGametype[i][0])
str_copy(m_FilterInfo.m_aGametype[i], Other.m_FilterInfo.m_aGametype[i], sizeof(m_FilterInfo.m_aGametype[i]));
else
m_FilterInfo.m_aGametype[i][0] = 0;
}
str_copy(m_FilterInfo.m_aAddress, Other.m_FilterInfo.m_aAddress, sizeof(m_FilterInfo.m_aAddress));
m_NumSortedPlayers = Other.m_NumSortedPlayers;
m_NumSortedServers = Other.m_NumSortedServers;
m_SortedServersCapacity = Other.m_SortedServersCapacity;
m_pSortedServerlist = (int *)mem_alloc(m_SortedServersCapacity * sizeof(int), 1);
for(int i = 0; i < m_SortedServersCapacity; ++i)
m_pSortedServerlist[i] = Other.m_pSortedServerlist[i];
}
return *this;
}
void CServerBrowserFilter::CServerFilter::Filter()
@ -66,38 +98,51 @@ void CServerBrowserFilter::CServerFilter::Filter()
{
int Filtered = 0;
if(m_SortHash&IServerBrowser::FILTER_EMPTY && ((m_SortHash&IServerBrowser::FILTER_SPECTATORS && m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumPlayers == 0) || m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumClients == 0))
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_EMPTY && ((m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS && m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumPlayers == 0) || m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumClients == 0))
Filtered = 1;
else if(m_SortHash&IServerBrowser::FILTER_FULL && ((m_SortHash&IServerBrowser::FILTER_SPECTATORS && m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumPlayers == m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_MaxPlayers) ||
else if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FULL && ((m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS && m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumPlayers == m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_MaxPlayers) ||
m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumClients == m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_MaxClients))
Filtered = 1;
else if(m_SortHash&IServerBrowser::FILTER_PW && m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Flags&IServerBrowser::FLAG_PASSWORD)
else if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_PW && m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Flags&IServerBrowser::FLAG_PASSWORD)
Filtered = 1;
else if(m_SortHash&IServerBrowser::FILTER_FAVORITE && !m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Favorite)
else if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FAVORITE && !m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Favorite)
Filtered = 1;
else if(m_SortHash&IServerBrowser::FILTER_PURE && !(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Flags&IServerBrowser::FLAG_PURE))
else if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE && !(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Flags&IServerBrowser::FLAG_PURE))
Filtered = 1;
else if(m_SortHash&IServerBrowser::FILTER_PURE_MAP && !(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Flags&IServerBrowser::FLAG_PUREMAP))
else if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE_MAP && !(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Flags&IServerBrowser::FLAG_PUREMAP))
Filtered = 1;
else if(m_SortHash&IServerBrowser::FILTER_PING && m_Ping < m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Latency)
else if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_PING && m_FilterInfo.m_Ping < m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_Latency)
Filtered = 1;
else if(m_SortHash&IServerBrowser::FILTER_COMPAT_VERSION && str_comp_num(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aVersion, m_pServerBrowserFilter->m_aNetVersion, 3) != 0)
else if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_COMPAT_VERSION && str_comp_num(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aVersion, m_pServerBrowserFilter->m_aNetVersion, 3) != 0)
Filtered = 1;
else if(m_aServerAddress[0] && !str_find_nocase(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aAddress, m_aServerAddress))
else if(m_FilterInfo.m_aAddress[0] && !str_find_nocase(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aAddress, m_FilterInfo.m_aAddress))
Filtered = 1;
else if(m_SortHash&IServerBrowser::FILTER_GAMETYPE_STRICT && m_aGametype[0] && str_comp_nocase(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aGameType, m_aGametype))
Filtered = 1;
else if(!(m_SortHash&IServerBrowser::FILTER_GAMETYPE_STRICT) && m_aGametype[0] && !str_find_nocase(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aGameType, m_aGametype))
else if(m_FilterInfo.m_ServerLevel & (1 << m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_ServerLevel))
Filtered = 1;
else
{
if(m_SortHash&IServerBrowser::FILTER_COUNTRY)
if(m_FilterInfo.m_aGametype[0][0])
{
Filtered = 1;
for(int Index = 0; Index < CServerFilterInfo::MAX_GAMETYPES; ++Index)
{
if(!m_FilterInfo.m_aGametype[Index][0])
break;
if(!str_comp_nocase(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aGameType, m_FilterInfo.m_aGametype[Index]))
{
Filtered = 0;
break;
}
}
}
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_COUNTRY)
{
Filtered = 1;
// match against player country
for(int p = 0; p < m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumClients; p++)
{
if(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aClients[p].m_Country == m_Country)
if(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aClients[p].m_Country == m_FilterInfo.m_Country)
{
Filtered = 0;
break;
@ -153,10 +198,18 @@ void CServerBrowserFilter::CServerFilter::Filter()
m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_FriendState = max(m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_FriendState, m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_aClients[p].m_FriendState);
}
if(!(m_SortHash&IServerBrowser::FILTER_FRIENDS) || m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_FriendState != IFriends::FRIEND_NO)
if(!(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FRIENDS) || m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_FriendState != IFriends::FRIEND_NO)
{
m_pSortedServerlist[m_NumSortedServers++] = i;
m_NumSortedPlayers += (m_SortHash&IServerBrowser::FILTER_SPECTATORS) ? m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumPlayers : m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumClients;
int Count = (m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) ? m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumPlayers : m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumClients;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_BOTS)
{
Count -= m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumBotPlayers;
if(!(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS))
Count -= m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumBotSpectators;
}
m_NumSortedPlayers += Count;
}
}
}
@ -164,20 +217,20 @@ void CServerBrowserFilter::CServerFilter::Filter()
int CServerBrowserFilter::CServerFilter::GetSortHash() const
{
int i = g_Config.m_BrSort&0xf;
i |= g_Config.m_BrSortOrder<<4;
if(m_SortHash&IServerBrowser::FILTER_EMPTY) i |= 1<<5;
if(m_SortHash&IServerBrowser::FILTER_FULL) i |= 1<<6;
if(m_SortHash&IServerBrowser::FILTER_SPECTATORS) i |= 1<<7;
if(m_SortHash&IServerBrowser::FILTER_FRIENDS) i |= 1<<8;
if(m_SortHash&IServerBrowser::FILTER_PW) i |= 1<<9;
if(m_SortHash&IServerBrowser::FILTER_FAVORITE) i |= 1<<10;
if(m_SortHash&IServerBrowser::FILTER_COMPAT_VERSION) i |= 1<<11;
if(m_SortHash&IServerBrowser::FILTER_PURE) i |= 1<<12;
if(m_SortHash&IServerBrowser::FILTER_PURE_MAP) i |= 1<<13;
if(m_SortHash&IServerBrowser::FILTER_GAMETYPE_STRICT) i |= 1<<14;
if(m_SortHash&IServerBrowser::FILTER_COUNTRY) i |= 1<<15;
if(m_SortHash&IServerBrowser::FILTER_PING) i |= 1<<16;
int i = g_Config.m_BrSort&0x7;
i |= g_Config.m_BrSortOrder<<3;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_BOTS) i |= 1 << 4;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_EMPTY) i |= 1<<5;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FULL) i |= 1<<6;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) i |= 1<<7;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FRIENDS) i |= 1<<8;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_PW) i |= 1<<9;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FAVORITE) i |= 1<<10;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_COMPAT_VERSION) i |= 1<<11;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE) i |= 1<<12;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE_MAP) i |= 1<<13;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_COUNTRY) i |= 1<<14;
if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_PING) i |= 1<<15;
return i;
}
@ -200,13 +253,13 @@ void CServerBrowserFilter::CServerFilter::Sort()
break;
case IServerBrowser::SORT_NUMPLAYERS:
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this,
(m_SortHash&IServerBrowser::FILTER_SPECTATORS) ? &CServerBrowserFilter::CServerFilter::SortCompareNumPlayers : &CServerBrowserFilter::CServerFilter::SortCompareNumClients));
(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) ? &CServerBrowserFilter::CServerFilter::SortCompareNumPlayers : &CServerBrowserFilter::CServerFilter::SortCompareNumClients));
break;
case IServerBrowser::SORT_GAMETYPE:
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowserFilter::CServerFilter::SortCompareGametype));
}
m_SortHash = GetSortHash();
m_FilterInfo.m_SortHash = GetSortHash();
}
bool CServerBrowserFilter::CServerFilter::SortCompareName(int Index1, int Index2) const
@ -281,7 +334,7 @@ void CServerBrowserFilter::Sort(CServerEntry **ppServerlist, int NumServers, int
{
// check if we need to resort
CServerFilter *pFilter = &m_lFilters[i];
if((ResortFlags&RESORT_FLAG_FORCE) || ((ResortFlags&RESORT_FLAG_FAV) && pFilter->m_SortHash&IServerBrowser::FILTER_FAVORITE) || pFilter->m_SortHash != pFilter->GetSortHash())
if((ResortFlags&RESORT_FLAG_FORCE) || ((ResortFlags&RESORT_FLAG_FAV) && pFilter->m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FAVORITE) || pFilter->m_FilterInfo.m_SortHash != pFilter->GetSortHash())
pFilter->Sort();
}
}
@ -289,11 +342,13 @@ void CServerBrowserFilter::Sort(CServerEntry **ppServerlist, int NumServers, int
int CServerBrowserFilter::AddFilter(const CServerFilterInfo *pFilterInfo)
{
CServerFilter Filter;
Filter.m_SortHash = pFilterInfo->m_SortHash;
Filter.m_Ping = pFilterInfo->m_Ping;
Filter.m_Country = pFilterInfo->m_Country;
str_copy(Filter.m_aGametype, pFilterInfo->m_aGametype, sizeof(Filter.m_aGametype));
str_copy(Filter.m_aServerAddress, pFilterInfo->m_aAddress, sizeof(Filter.m_aServerAddress));
Filter.m_FilterInfo.m_SortHash = pFilterInfo->m_SortHash;
Filter.m_FilterInfo.m_Ping = pFilterInfo->m_Ping;
Filter.m_FilterInfo.m_Country = pFilterInfo->m_Country;
Filter.m_FilterInfo.m_ServerLevel = pFilterInfo->m_ServerLevel;
for(int i = 0; i < CServerFilterInfo::MAX_GAMETYPES; ++i)
str_copy(Filter.m_FilterInfo.m_aGametype[i], pFilterInfo->m_aGametype[i], sizeof(Filter.m_FilterInfo.m_aGametype[i]));
str_copy(Filter.m_FilterInfo.m_aAddress, pFilterInfo->m_aAddress, sizeof(Filter.m_FilterInfo.m_aAddress));
Filter.m_pSortedServerlist = 0;
Filter.m_NumSortedPlayers = 0;
Filter.m_NumSortedServers = 0;
@ -307,21 +362,25 @@ int CServerBrowserFilter::AddFilter(const CServerFilterInfo *pFilterInfo)
void CServerBrowserFilter::GetFilter(int Index, CServerFilterInfo *pFilterInfo) const
{
const CServerFilter *pFilter = &m_lFilters[Index];
pFilterInfo->m_SortHash = pFilter->m_SortHash;
pFilterInfo->m_Ping = pFilter->m_Ping;
pFilterInfo->m_Country = pFilter->m_Country;
str_copy(pFilterInfo->m_aGametype, pFilter->m_aGametype, sizeof(pFilterInfo->m_aGametype));
str_copy(pFilterInfo->m_aAddress, pFilter->m_aServerAddress, sizeof(pFilterInfo->m_aAddress));
pFilterInfo->m_SortHash = pFilter->m_FilterInfo.m_SortHash;
pFilterInfo->m_Ping = pFilter->m_FilterInfo.m_Ping;
pFilterInfo->m_Country = pFilter->m_FilterInfo.m_Country;
pFilterInfo->m_ServerLevel = pFilter->m_FilterInfo.m_ServerLevel;
for(int i = 0; i < CServerFilterInfo::MAX_GAMETYPES; ++i)
str_copy(pFilterInfo->m_aGametype[i], pFilter->m_FilterInfo.m_aGametype[i], sizeof(pFilterInfo->m_aGametype[i]));
str_copy(pFilterInfo->m_aAddress, pFilter->m_FilterInfo.m_aAddress, sizeof(pFilterInfo->m_aAddress));
}
void CServerBrowserFilter::SetFilter(int Index, const CServerFilterInfo *pFilterInfo)
{
CServerFilter *pFilter = &m_lFilters[Index];
pFilter->m_SortHash = pFilterInfo->m_SortHash;
pFilter->m_Ping = pFilterInfo->m_Ping;
pFilter->m_Country = pFilterInfo->m_Country;
str_copy(pFilter->m_aGametype, pFilterInfo->m_aGametype, sizeof(pFilter->m_aGametype));
str_copy(pFilter->m_aServerAddress, pFilterInfo->m_aAddress, sizeof(pFilter->m_aServerAddress));
pFilter->m_FilterInfo.m_SortHash = pFilterInfo->m_SortHash;
pFilter->m_FilterInfo.m_Ping = pFilterInfo->m_Ping;
pFilter->m_FilterInfo.m_Country = pFilterInfo->m_Country;
pFilter->m_FilterInfo.m_ServerLevel = pFilterInfo->m_ServerLevel;
for(int i = 0; i < CServerFilterInfo::MAX_GAMETYPES; ++i)
str_copy(pFilter->m_FilterInfo.m_aGametype[i], pFilterInfo->m_aGametype[i], sizeof(pFilter->m_FilterInfo.m_aGametype[i]));
str_copy(pFilter->m_FilterInfo.m_aAddress, pFilterInfo->m_aAddress, sizeof(pFilter->m_FilterInfo.m_aAddress));
pFilter->Sort();
}

View file

@ -20,11 +20,7 @@ public:
CServerBrowserFilter *m_pServerBrowserFilter;
// filter settings
int m_SortHash;
int m_Ping;
int m_Country;
char m_aGametype[32];
char m_aServerAddress[NETADDR_MAXSTRSIZE];
CServerFilterInfo m_FilterInfo;
// stats
int m_NumSortedPlayers;
@ -34,6 +30,7 @@ public:
CServerFilter();
~CServerFilter();
CServerFilter& operator=(const CServerFilter& Other);
void Filter();
int GetSortHash() const;
@ -62,8 +59,8 @@ public:
// stats
const void *GetID(int FilterIndex, int Index) const { return &m_lFilters[FilterIndex].m_pSortedServerlist[Index]; }
int GetIndex(int FilterIndex, int Index) const { return m_lFilters[FilterIndex].m_pSortedServerlist[Index]; }
int GetNumSortedServers(int Index) const { return m_lFilters[Index].m_NumSortedServers; }
int GetNumSortedPlayers(int Index) const { return m_lFilters[Index].m_NumSortedPlayers; }
int GetNumSortedServers(int FilterIndex) const { return m_lFilters[FilterIndex].m_NumSortedServers; }
int GetNumSortedPlayers(int FilterIndex) const { return m_lFilters[FilterIndex].m_NumSortedPlayers; }
private:
class IFriends *m_pFriends;

View file

@ -206,7 +206,7 @@ int CSound::Init()
m_SoundLock = lock_create();
if(!g_Config.m_SndEnable)
if(!g_Config.m_SndInit)
return 0;
if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)

View file

@ -67,6 +67,11 @@ public:
CFontSizeData m_aSizes[NUM_FONT_SIZES];
};
struct CQuadChar
{
float m_aUvs[4];
IGraphics::CQuadItem m_QuadItem;
};
class CTextRender : public IEngineTextRender
{
@ -165,7 +170,7 @@ class CTextRender : public IEngineTextRender
pSizeData->m_TextureWidth = Width;
pSizeData->m_TextureHeight = Height;
pSizeData->m_CurrentCharacter = 0;
dbg_msg("", "pFont memory usage: %d", FontMemoryUsage);
mem_free(pMem);
@ -538,6 +543,227 @@ public:
m_TextOutlineA = a;
}
virtual void TextShadowed(CTextCursor *pCursor, const char *pText, int Length, vec2 ShadowOffset,
vec4 ShadowColor, vec4 TextColor_)
{
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
float FakeToScreenX, FakeToScreenY;
// to correct coords, convert to screen coords, round, and convert back
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
FakeToScreenX = (Graphics()->ScreenWidth()/(ScreenX1-ScreenX0));
FakeToScreenY = (Graphics()->ScreenHeight()/(ScreenY1-ScreenY0));
ShadowOffset.x /= FakeToScreenX;
ShadowOffset.y /= FakeToScreenY;
CQuadChar aTextQuads[1024];
int TextQuadCount = 0;
IGraphics::CTextureHandle FontTexture;
TextDeferredRenderEx(pCursor, pText, Length, aTextQuads, sizeof(aTextQuads)/sizeof(aTextQuads[0]),
&TextQuadCount, &FontTexture);
Graphics()->TextureSet(FontTexture);
Graphics()->QuadsBegin();
// shadow pass
Graphics()->SetColor(ShadowColor.r, ShadowColor.g, ShadowColor.b, ShadowColor.a);
for(int i = 0; i < TextQuadCount; i++)
{
const CQuadChar& q = aTextQuads[i];
Graphics()->QuadsSetSubset(q.m_aUvs[0], q.m_aUvs[1], q.m_aUvs[2], q.m_aUvs[3]);
IGraphics::CQuadItem QuadItem = q.m_QuadItem;
QuadItem.m_X += ShadowOffset.x;
QuadItem.m_Y += ShadowOffset.y;
Graphics()->QuadsDrawTL(&QuadItem, 1);
}
// text pass
Graphics()->SetColor(TextColor_.r, TextColor_.g, TextColor_.b, TextColor_.a);
for(int i = 0; i < TextQuadCount; i++)
{
const CQuadChar& q = aTextQuads[i];
Graphics()->QuadsSetSubset(q.m_aUvs[0], q.m_aUvs[1], q.m_aUvs[2], q.m_aUvs[3]);
Graphics()->QuadsDrawTL(&q.m_QuadItem, 1);
}
Graphics()->QuadsEnd();
}
virtual void TextDeferredRenderEx(CTextCursor *pCursor, const char *pText, int Length,
CQuadChar* aQuadChar, int QuadCharMaxCount, int* pQuadCharCount,
IGraphics::CTextureHandle* pFontTexture)
{
CFont *pFont = pCursor->m_pFont;
CFontSizeData *pSizeData = NULL;
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
float FakeToScreenX, FakeToScreenY;
int ActualX, ActualY;
int ActualSize;
int GotNewLine = 0;
float DrawX = 0.0f, DrawY = 0.0f;
int LineCount = 0;
float CursorX, CursorY;
float Size = pCursor->m_FontSize;
// to correct coords, convert to screen coords, round, and convert back
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
FakeToScreenX = (Graphics()->ScreenWidth()/(ScreenX1-ScreenX0));
FakeToScreenY = (Graphics()->ScreenHeight()/(ScreenY1-ScreenY0));
ActualX = (int)(pCursor->m_X * FakeToScreenX);
ActualY = (int)(pCursor->m_Y * FakeToScreenY);
CursorX = ActualX / FakeToScreenX;
CursorY = ActualY / FakeToScreenY;
// same with size
ActualSize = (int)(Size * FakeToScreenY);
Size = ActualSize / FakeToScreenY;
// fetch pFont data
if(!pFont)
pFont = m_pDefaultFont;
if(!pFont)
return;
pSizeData = GetSize(pFont, ActualSize);
RenderSetup(pFont, ActualSize);
*pFontTexture = pSizeData->m_aTextures[0];
float Scale = 1.0f/pSizeData->m_FontSize;
// set length
if(Length < 0)
Length = str_length(pText);
const char *pCurrent = (char *)pText;
const char *pEnd = pCurrent+Length;
DrawX = CursorX;
DrawY = CursorY;
LineCount = pCursor->m_LineCount;
while(pCurrent < pEnd && (pCursor->m_MaxLines < 1 || LineCount <= pCursor->m_MaxLines))
{
int NewLine = 0;
const char *pBatchEnd = pEnd;
if(pCursor->m_LineWidth > 0 && !(pCursor->m_Flags&TEXTFLAG_STOP_AT_END))
{
int Wlen = min(WordLength((char *)pCurrent), (int)(pEnd-pCurrent));
CTextCursor Compare = *pCursor;
Compare.m_X = DrawX;
Compare.m_Y = DrawY;
Compare.m_Flags &= ~TEXTFLAG_RENDER;
Compare.m_LineWidth = -1;
TextDeferredRenderEx(&Compare, pCurrent, Wlen, aQuadChar, QuadCharMaxCount, pQuadCharCount,
pFontTexture);
if(Compare.m_X-DrawX > pCursor->m_LineWidth)
{
// word can't be fitted in one line, cut it
CTextCursor Cutter = *pCursor;
Cutter.m_CharCount = 0;
Cutter.m_X = DrawX;
Cutter.m_Y = DrawY;
Cutter.m_Flags &= ~TEXTFLAG_RENDER;
Cutter.m_Flags |= TEXTFLAG_STOP_AT_END;
TextDeferredRenderEx(&Cutter, (const char *)pCurrent, Wlen, aQuadChar, QuadCharMaxCount,
pQuadCharCount, pFontTexture);
Wlen = Cutter.m_CharCount;
NewLine = 1;
if(Wlen <= 3) // if we can't place 3 chars of the word on this line, take the next
Wlen = 0;
}
else if(Compare.m_X-pCursor->m_StartX > pCursor->m_LineWidth)
{
NewLine = 1;
Wlen = 0;
}
pBatchEnd = pCurrent + Wlen;
}
const char *pTmp = pCurrent;
int NextCharacter = str_utf8_decode(&pTmp);
while(pCurrent < pBatchEnd)
{
int Character = NextCharacter;
pCurrent = pTmp;
NextCharacter = str_utf8_decode(&pTmp);
if(Character == '\n')
{
DrawX = pCursor->m_StartX;
DrawY += Size;
DrawX = (int)(DrawX * FakeToScreenX) / FakeToScreenX; // realign
DrawY = (int)(DrawY * FakeToScreenY) / FakeToScreenY;
++LineCount;
if(pCursor->m_MaxLines > 0 && LineCount > pCursor->m_MaxLines)
break;
continue;
}
CFontChar *pChr = GetChar(pFont, pSizeData, Character);
if(pChr)
{
float Advance = pChr->m_AdvanceX + Kerning(pFont, Character, NextCharacter)*Scale;
if(pCursor->m_Flags&TEXTFLAG_STOP_AT_END && DrawX+Advance*Size-pCursor->m_StartX > pCursor->m_LineWidth)
{
// we hit the end of the line, no more to render or count
pCurrent = pEnd;
break;
}
if(pCursor->m_Flags&TEXTFLAG_RENDER)
{
dbg_assert(*pQuadCharCount < QuadCharMaxCount, "aQuadChar size is too small");
CQuadChar QuadChar;
memmove(QuadChar.m_aUvs, pChr->m_aUvs, sizeof(pChr->m_aUvs));
IGraphics::CQuadItem QuadItem(DrawX+pChr->m_OffsetX*Size,
DrawY+pChr->m_OffsetY*Size,
pChr->m_Width*Size,
pChr->m_Height*Size);
QuadChar.m_QuadItem = QuadItem;
aQuadChar[(*pQuadCharCount)++] = QuadChar;
}
DrawX += Advance*Size;
pCursor->m_CharCount++;
}
}
if(NewLine)
{
DrawX = pCursor->m_StartX;
DrawY += Size;
GotNewLine = 1;
DrawX = (int)(DrawX * FakeToScreenX) / FakeToScreenX; // realign
DrawY = (int)(DrawY * FakeToScreenY) / FakeToScreenY;
++LineCount;
}
}
pCursor->m_X = DrawX;
pCursor->m_LineCount = LineCount;
if(GotNewLine)
pCursor->m_Y = DrawY;
}
virtual void TextEx(CTextCursor *pCursor, const char *pText, int Length)
{
CFont *pFont = pCursor->m_pFont;
@ -722,6 +948,38 @@ public:
pCursor->m_Y = DrawY;
}
float TextGetLineBaseY(const CTextCursor *pCursor)
{
CFont *pFont = pCursor->m_pFont;
CFontSizeData *pSizeData = NULL;
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
float Size = pCursor->m_FontSize;
// to correct coords, convert to screen coords, round, and convert back
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
float FakeToScreenY = (Graphics()->ScreenHeight()/(ScreenY1-ScreenY0));
int ActualY = (int)(pCursor->m_Y * FakeToScreenY);
float CursorY = ActualY / FakeToScreenY;
// same with size
int ActualSize = (int)(Size * FakeToScreenY);
Size = ActualSize / FakeToScreenY;
// fetch pFont data
if(!pFont)
pFont = m_pDefaultFont;
if(!pFont)
return 0;
pSizeData = GetSize(pFont, ActualSize);
RenderSetup(pFont, ActualSize);
CFontChar *pChr = GetChar(pFont, pSizeData, ' ');
return CursorY + pChr->m_OffsetY*Size + pChr->m_Height*Size;
}
};
IEngineTextRender *CreateEngineTextRender() { return new CTextRender; }

View file

@ -1 +1 @@
unmarked version: 17.12.2012
unmarked version: 11.11.2018

View file

@ -1,7 +1,6 @@
/* vim: set et ts=3 sw=3 ft=c:
/* vim: set et ts=3 sw=3 sts=3 ft=c:
*
* Copyright (C) 2012 James McLaughlin et al. All rights reserved.
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
*
* Redistribution and use in source and binary forms, with or without
@ -36,50 +35,58 @@
#endif
#endif
#ifdef __cplusplus
const struct _json_value json_value_none; /* zero-d by ctor */
#else
const struct _json_value json_value_none = { 0 };
#endif
const struct _json_value json_value_none;
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
typedef unsigned short json_uchar;
typedef unsigned int json_uchar;
static unsigned char hex_value (json_char c)
{
if (c >= 'A' && c <= 'F')
return (c - 'A') + 10;
if (c >= 'a' && c <= 'f')
return (c - 'a') + 10;
if (c >= '0' && c <= '9')
if (isdigit(c))
return c - '0';
return 0xFF;
switch (c) {
case 'a': case 'A': return 0x0A;
case 'b': case 'B': return 0x0B;
case 'c': case 'C': return 0x0C;
case 'd': case 'D': return 0x0D;
case 'e': case 'E': return 0x0E;
case 'f': case 'F': return 0x0F;
default: return 0xFF;
}
}
typedef struct
{
json_settings settings;
int first_pass;
unsigned long used_memory;
unsigned int uint_max;
unsigned long ulong_max;
json_settings settings;
int first_pass;
const json_char * ptr;
unsigned int cur_line, cur_col;
} json_state;
static void * default_alloc (size_t size, int zero, void * user_data)
{
return zero ? calloc (1, size) : malloc (size);
}
static void default_free (void * ptr, void * user_data)
{
free (ptr);
}
static void * json_alloc (json_state * state, unsigned long size, int zero)
{
void * mem;
if ((state->ulong_max - state->used_memory) < size)
return 0;
@ -89,14 +96,12 @@ static void * json_alloc (json_state * state, unsigned long size, int zero)
return 0;
}
if (! (mem = zero ? calloc (size, 1) : malloc (size)))
return 0;
return mem;
return state->settings.mem_alloc (size, zero, state->settings.user_data);
}
static int new_value
(json_state * state, json_value ** top, json_value ** root, json_value ** alloc, json_type type)
static int new_value (json_state * state,
json_value ** top, json_value ** root, json_value ** alloc,
json_type type)
{
json_value * value;
int values_size;
@ -113,6 +118,9 @@ static int new_value
{
case json_array:
if (value->u.array.length == 0)
break;
if (! (value->u.array.values = (json_value **) json_alloc
(state, value->u.array.length * sizeof (json_value *), 0)) )
{
@ -124,9 +132,12 @@ static int new_value
case json_object:
if (value->u.object.length == 0)
break;
values_size = sizeof (*value->u.object.values) * value->u.object.length;
if (! ((*(void **) &value->u.object.values) = json_alloc
if (! (value->u.object.values = (json_object_entry *) json_alloc
(state, values_size + ((unsigned long) value->u.object.values), 0)) )
{
return 0;
@ -155,10 +166,11 @@ static int new_value
return 1;
}
value = (json_value *) json_alloc (state, sizeof (json_value), 1);
if (!value)
if (! (value = (json_value *) json_alloc
(state, sizeof (json_value) + state->settings.value_extra, 1)))
{
return 0;
}
if (!*root)
*root = value;
@ -166,6 +178,11 @@ static int new_value
value->type = type;
value->parent = *top;
#ifdef JSON_TRACK_SOURCE
value->line = state->cur_line;
value->col = state->cur_col;
#endif
if (*alloc)
(*alloc)->_reserved.next_alloc = value;
@ -174,38 +191,67 @@ static int new_value
return 1;
}
#define e_off \
((int) (i - cur_line_begin))
#define whitespace \
case '\n': ++ cur_line; cur_line_begin = i; \
case '\n': ++ state.cur_line; state.cur_col = 0; \
case ' ': case '\t': case '\r'
#define string_add(b) \
do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0);
const static long
flag_next = 1, flag_reproc = 2, flag_need_comma = 4, flag_seek_value = 8,
flag_escaped = 16, flag_string = 32, flag_need_colon = 64, flag_done = 128,
flag_num_negative = 256, flag_num_zero = 512, flag_num_e = 1024,
flag_num_e_got_sign = 2048, flag_num_e_negative = 4096;
#define line_and_col \
state.cur_line, state.cur_col
json_value * json_parse_ex (json_settings * settings, const json_char * json, char * error_buf)
static const long
flag_next = 1 << 0,
flag_reproc = 1 << 1,
flag_need_comma = 1 << 2,
flag_seek_value = 1 << 3,
flag_escaped = 1 << 4,
flag_string = 1 << 5,
flag_need_colon = 1 << 6,
flag_done = 1 << 7,
flag_num_negative = 1 << 8,
flag_num_zero = 1 << 9,
flag_num_e = 1 << 10,
flag_num_e_got_sign = 1 << 11,
flag_num_e_negative = 1 << 12,
flag_line_comment = 1 << 13,
flag_block_comment = 1 << 14;
json_value * json_parse_ex (json_settings * settings,
const json_char * json,
size_t length,
char * error_buf)
{
json_char error [128];
unsigned int cur_line;
const json_char * cur_line_begin, * i;
json_char error [json_error_max];
const json_char * end;
json_value * top, * root, * alloc = 0;
json_state state;
json_state state = { 0 };
long flags;
long num_digits, num_fraction, num_e;
long num_digits = 0, num_e = 0;
json_int_t num_fraction = 0;
/* Skip UTF-8 BOM
*/
if (length >= 3 && ((unsigned char) json [0]) == 0xEF
&& ((unsigned char) json [1]) == 0xBB
&& ((unsigned char) json [2]) == 0xBF)
{
json += 3;
length -= 3;
}
error[0] = '\0';
num_digits = num_fraction = num_e = 0;
end = (json + length);
memset (&state, 0, sizeof (json_state));
memcpy (&state.settings, settings, sizeof (json_settings));
if (!state.settings.mem_alloc)
state.settings.mem_alloc = default_alloc;
if (!state.settings.mem_free)
state.settings.mem_free = default_free;
memset (&state.uint_max, 0xFF, sizeof (state.uint_max));
memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max));
@ -216,41 +262,22 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
{
json_uchar uchar;
unsigned char uc_b1, uc_b2, uc_b3, uc_b4;
json_char * string;
unsigned int string_length;
json_char * string = 0;
unsigned int string_length = 0;
top = root = 0;
flags = flag_seek_value;
string_length = 0;
string = 0;
cur_line = 1;
cur_line_begin = json;
state.cur_line = 1;
for (i = json ;; ++ i)
for (state.ptr = json ;; ++ state.ptr)
{
json_char b = *i;
if (flags & flag_done)
{
if (!b)
break;
switch (b)
{
whitespace:
continue;
default:
sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b);
goto e_failed;
};
}
json_char b = (state.ptr == end ? 0 : *state.ptr);
if (flags & flag_string)
{
if (!b)
{ sprintf (error, "Unexpected EOF in string (at %d:%d)", cur_line, e_off);
{ sprintf (error, "Unexpected EOF in string (at %d:%d)", line_and_col);
goto e_failed;
}
@ -270,19 +297,41 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
case 't': string_add ('\t'); break;
case 'u':
if ((uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF
|| (uc_b3 = hex_value (*++ i)) == 0xFF || (uc_b4 = hex_value (*++ i)) == 0xFF)
if (end - state.ptr <= 4 ||
(uc_b1 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b2 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
{
sprintf (error, "Invalid character value `%c` (at %d:%d)", b, cur_line, e_off);
sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col);
goto e_failed;
}
uc_b1 = uc_b1 * 16 + uc_b2;
uc_b2 = uc_b3 * 16 + uc_b4;
uc_b1 = (uc_b1 << 4) | uc_b2;
uc_b2 = (uc_b3 << 4) | uc_b4;
uchar = (uc_b1 << 8) | uc_b2;
uchar = ((json_char) uc_b1) * 256 + uc_b2;
if ((uchar & 0xF800) == 0xD800) {
json_uchar uchar2;
if (end - state.ptr <= 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' ||
(uc_b1 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b2 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
(uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
{
sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col);
goto e_failed;
}
if (sizeof (json_char) >= sizeof (json_uchar) || (uc_b1 == 0 && uc_b2 <= 0x7F))
uc_b1 = (uc_b1 << 4) | uc_b2;
uc_b2 = (uc_b3 << 4) | uc_b4;
uchar2 = (uc_b1 << 8) | uc_b2;
uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF);
}
if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F))
{
string_add ((json_char) uchar);
break;
@ -293,19 +342,32 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
if (state.first_pass)
string_length += 2;
else
{ string [string_length ++] = 0xC0 | ((uc_b2 & 0xC0) >> 6) | ((uc_b1 & 0x7) << 2);
string [string_length ++] = 0x80 | (uc_b2 & 0x3F);
{ string [string_length ++] = 0xC0 | (uchar >> 6);
string [string_length ++] = 0x80 | (uchar & 0x3F);
}
break;
}
if (uchar <= 0xFFFF) {
if (state.first_pass)
string_length += 3;
else
{ string [string_length ++] = 0xE0 | (uchar >> 12);
string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F);
string [string_length ++] = 0x80 | (uchar & 0x3F);
}
break;
}
if (state.first_pass)
string_length += 3;
string_length += 4;
else
{ string [string_length ++] = 0xE0 | ((uc_b1 & 0xF0) >> 4);
string [string_length ++] = 0x80 | ((uc_b1 & 0xF) << 2) | ((uc_b2 & 0xC0) >> 6);
string [string_length ++] = 0x80 | (uc_b2 & 0x3F);
{ string [string_length ++] = 0xF0 | (uchar >> 18);
string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F);
string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F);
string [string_length ++] = 0x80 | (uchar & 0x3F);
}
break;
@ -349,6 +411,9 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
top->u.object.values [top->u.object.length].name
= (json_char *) top->_reserved.object_mem;
top->u.object.values [top->u.object.length].name_length
= string_length;
(*(json_char **) &top->_reserved.object_mem) += string_length + 1;
}
@ -366,6 +431,85 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
}
}
if (state.settings.settings & json_enable_comments)
{
if (flags & (flag_line_comment | flag_block_comment))
{
if (flags & flag_line_comment)
{
if (b == '\r' || b == '\n' || !b)
{
flags &= ~ flag_line_comment;
-- state.ptr; /* so null can be reproc'd */
}
continue;
}
if (flags & flag_block_comment)
{
if (!b)
{ sprintf (error, "%d:%d: Unexpected EOF in block comment", line_and_col);
goto e_failed;
}
if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/')
{
flags &= ~ flag_block_comment;
++ state.ptr; /* skip closing sequence */
}
continue;
}
}
else if (b == '/')
{
if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object)
{ sprintf (error, "%d:%d: Comment not allowed here", line_and_col);
goto e_failed;
}
if (++ state.ptr == end)
{ sprintf (error, "%d:%d: EOF unexpected", line_and_col);
goto e_failed;
}
switch (b = *state.ptr)
{
case '/':
flags |= flag_line_comment;
continue;
case '*':
flags |= flag_block_comment;
continue;
default:
sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", line_and_col, b);
goto e_failed;
};
}
}
if (flags & flag_done)
{
if (!b)
break;
switch (b)
{
whitespace:
continue;
default:
sprintf (error, "%d:%d: Trailing garbage: `%c`",
state.cur_line, state.cur_col, b);
goto e_failed;
};
}
if (flags & flag_seek_value)
{
switch (b)
@ -375,10 +519,10 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
case ']':
if (top->type == json_array)
if (top && top->type == json_array)
flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
else if (!state.settings.settings & json_relaxed_commas)
{ sprintf (error, "%d:%d: Unexpected ]", cur_line, e_off);
else
{ sprintf (error, "%d:%d: Unexpected ]", line_and_col);
goto e_failed;
}
@ -393,7 +537,10 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
continue;
}
else
{ sprintf (error, "%d:%d: Expected , before %c", cur_line, e_off, b);
{
sprintf (error, "%d:%d: Expected , before %c",
state.cur_line, state.cur_col, b);
goto e_failed;
}
}
@ -405,7 +552,10 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
continue;
}
else
{ sprintf (error, "%d:%d: Expected : before %c", cur_line, e_off, b);
{
sprintf (error, "%d:%d: Expected : before %c",
state.cur_line, state.cur_col, b);
goto e_failed;
}
}
@ -443,8 +593,11 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
case 't':
if (*(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e')
if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' ||
*(++ state.ptr) != 'u' || *(++ state.ptr) != 'e')
{
goto e_unknown_value;
}
if (!new_value (&state, &top, &root, &alloc, json_boolean))
goto e_alloc_failure;
@ -456,8 +609,12 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
case 'f':
if (*(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e')
if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' ||
*(++ state.ptr) != 'l' || *(++ state.ptr) != 's' ||
*(++ state.ptr) != 'e')
{
goto e_unknown_value;
}
if (!new_value (&state, &top, &root, &alloc, json_boolean))
goto e_alloc_failure;
@ -467,8 +624,11 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
case 'n':
if (*(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l')
if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' ||
*(++ state.ptr) != 'l' || *(++ state.ptr) != 'l')
{
goto e_unknown_value;
}
if (!new_value (&state, &top, &root, &alloc, json_null))
goto e_alloc_failure;
@ -488,7 +648,13 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
while (isdigit (b) || b == '+' || b == '-'
|| b == 'e' || b == 'E' || b == '.')
{
b = *++ i;
if ( (++ state.ptr) == end)
{
b = 0;
break;
}
b = *state.ptr;
}
flags |= flag_next | flag_reproc;
@ -513,7 +679,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
continue;
}
else
{ sprintf (error, "%d:%d: Unexpected %c when seeking value", cur_line, e_off, b);
{ sprintf (error, "%d:%d: Unexpected %c when seeking value", line_and_col, b);
goto e_failed;
}
};
@ -532,9 +698,8 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
case '"':
if (flags & flag_need_comma && (!state.settings.settings & json_relaxed_commas))
{
sprintf (error, "%d:%d: Expected , before \"", cur_line, e_off);
if (flags & flag_need_comma)
{ sprintf (error, "%d:%d: Expected , before \"", line_and_col);
goto e_failed;
}
@ -559,8 +724,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
}
default:
sprintf (error, "%d:%d: Unexpected `%c` in object", cur_line, e_off, b);
sprintf (error, "%d:%d: Unexpected `%c` in object", line_and_col, b);
goto e_failed;
};
@ -578,7 +742,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
if (! (flags & flag_num_e))
{
if (flags & flag_num_zero)
{ sprintf (error, "%d:%d: Unexpected `0` before `%c`", cur_line, e_off, b);
{ sprintf (error, "%d:%d: Unexpected `0` before `%c`", line_and_col, b);
goto e_failed;
}
@ -615,12 +779,12 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
else if (b == '.' && top->type == json_integer)
{
if (!num_digits)
{ sprintf (error, "%d:%d: Expected digit before `.`", cur_line, e_off);
{ sprintf (error, "%d:%d: Expected digit before `.`", line_and_col);
goto e_failed;
}
top->type = json_double;
top->u.dbl = top->u.integer;
top->u.dbl = (double) top->u.integer;
num_digits = 0;
continue;
@ -631,11 +795,11 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
if (top->type == json_double)
{
if (!num_digits)
{ sprintf (error, "%d:%d: Expected digit after `.`", cur_line, e_off);
{ sprintf (error, "%d:%d: Expected digit after `.`", line_and_col);
goto e_failed;
}
top->u.dbl += ((double) num_fraction) / (pow (10, num_digits));
top->u.dbl += ((double) num_fraction) / (pow (10.0, (double) num_digits));
}
if (b == 'e' || b == 'E')
@ -645,7 +809,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
if (top->type == json_integer)
{
top->type = json_double;
top->u.dbl = top->u.integer;
top->u.dbl = (double) top->u.integer;
}
num_digits = 0;
@ -657,11 +821,12 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
else
{
if (!num_digits)
{ sprintf (error, "%d:%d: Expected digit after `e`", cur_line, e_off);
{ sprintf (error, "%d:%d: Expected digit after `e`", line_and_col);
goto e_failed;
}
top->u.dbl *= pow (10, flags & flag_num_e_negative ? - num_e : num_e);
top->u.dbl *= pow (10.0, (double)
(flags & flag_num_e_negative ? - num_e : num_e));
}
if (flags & flag_num_negative)
@ -683,7 +848,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
if (flags & flag_reproc)
{
flags &= ~ flag_reproc;
-- i;
-- state.ptr;
}
if (flags & flag_next)
@ -742,7 +907,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch
e_unknown_value:
sprintf (error, "%d:%d: Unknown value", cur_line, e_off);
sprintf (error, "%d:%d: Unknown value", line_and_col);
goto e_failed;
e_alloc_failure:
@ -752,7 +917,7 @@ e_alloc_failure:
e_overflow:
sprintf (error, "%d:%d: Too long (caught overflow)", cur_line, e_off);
sprintf (error, "%d:%d: Too long (caught overflow)", line_and_col);
goto e_failed;
e_failed:
@ -771,25 +936,23 @@ e_failed:
while (alloc)
{
top = alloc->_reserved.next_alloc;
free (alloc);
state.settings.mem_free (alloc, state.settings.user_data);
alloc = top;
}
if (!state.first_pass)
json_value_free (root);
json_value_free_ex (&state.settings, root);
return 0;
}
json_value * json_parse (const json_char * json)
json_value * json_parse (const json_char * json, size_t length)
{
json_settings settings;
memset (&settings, 0, sizeof (json_settings));
return json_parse_ex (&settings, json, 0);
json_settings settings = { 0 };
return json_parse_ex (&settings, json, length, 0);
}
void json_value_free (json_value * value)
void json_value_free_ex (json_settings * settings, json_value * value)
{
json_value * cur_value;
@ -806,7 +969,7 @@ void json_value_free (json_value * value)
if (!value->u.array.length)
{
free (value->u.array.values);
settings->mem_free (value->u.array.values, settings->user_data);
break;
}
@ -817,7 +980,7 @@ void json_value_free (json_value * value)
if (!value->u.object.length)
{
free (value->u.object.values);
settings->mem_free (value->u.object.values, settings->user_data);
break;
}
@ -826,7 +989,7 @@ void json_value_free (json_value * value)
case json_string:
free (value->u.string.ptr);
settings->mem_free (value->u.string.ptr, settings->user_data);
break;
default:
@ -835,7 +998,14 @@ void json_value_free (json_value * value)
cur_value = value;
value = value->parent;
free (cur_value);
settings->mem_free (cur_value, settings->user_data);
}
}
void json_value_free (json_value * value)
{
json_settings settings = { 0 };
settings.mem_free = default_free;
json_value_free_ex (&settings, value);
}

View file

@ -1,7 +1,7 @@
/* vim: set et ts=3 sw=3 ft=c:
/* vim: set et ts=3 sw=3 sts=3 ft=c:
*
* Copyright (C) 2012 James McLaughlin et al. All rights reserved.
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
*
* Redistribution and use in source and binary forms, with or without
@ -35,6 +35,17 @@
#define json_char char
#endif
#ifndef json_int_t
#ifndef _MSC_VER
#include <inttypes.h>
#define json_int_t int64_t
#else
#define json_int_t __int64
#endif
#endif
#include <stdlib.h>
#ifdef __cplusplus
#include <string.h>
@ -49,9 +60,19 @@ typedef struct
unsigned long max_memory;
int settings;
/* Custom allocator support (leave null to use malloc/free)
*/
void * (* mem_alloc) (size_t, int zero, void * user_data);
void (* mem_free) (void *, void * user_data);
void * user_data; /* will be passed to mem_alloc and mem_free */
size_t value_extra; /* how much extra space to allocate for values? */
} json_settings;
#define json_relaxed_commas 1
#define json_enable_comments 0x01
typedef enum
{
@ -67,6 +88,15 @@ typedef enum
} json_type;
extern const struct _json_value json_value_none;
typedef struct _json_object_entry
{
json_char * name;
unsigned int name_length;
struct _json_value * value;
} json_object_entry;
typedef struct _json_value
{
@ -77,7 +107,7 @@ typedef struct _json_value
union
{
int boolean;
long integer;
json_int_t integer;
double dbl;
struct
@ -91,12 +121,16 @@ typedef struct _json_value
{
unsigned int length;
struct
{
json_char * name;
struct _json_value * value;
json_object_entry * values;
} * values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
{ return values;
}
decltype(values) end () const
{ return values + length;
}
#endif
} object;
@ -105,6 +139,15 @@ typedef struct _json_value
unsigned int length;
struct _json_value ** values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
{ return values;
}
decltype(values) end () const
{ return values + length;
}
#endif
} array;
} u;
@ -116,6 +159,14 @@ typedef struct _json_value
} _reserved;
#ifdef JSON_TRACK_SOURCE
/* Location of the value in the source JSON
*/
unsigned int line, col;
#endif
/* Some C++ operator sugar */
@ -162,27 +213,67 @@ typedef struct _json_value
};
}
inline operator long () const
{ return u.integer;
inline operator json_int_t () const
{
switch (type)
{
case json_integer:
return u.integer;
case json_double:
return (json_int_t) u.dbl;
default:
return 0;
};
}
inline operator bool () const
{ return u.boolean != 0;
{
if (type != json_boolean)
return false;
return u.boolean != 0;
}
inline operator double () const
{
switch (type)
{
case json_integer:
return (double) u.integer;
case json_double:
return u.dbl;
default:
return 0;
};
}
#endif
} json_value;
json_value * json_parse (const json_char * json,
size_t length);
json_value * json_parse
(const json_char * json);
json_value * json_parse_ex
(json_settings * settings, const json_char * json, char * error);
#define json_error_max 128
json_value * json_parse_ex (json_settings * settings,
const json_char * json,
size_t length,
char * error);
void json_value_free (json_value *);
/* Not usually necessary, unless you used a custom mem_alloc and now want to
* use a custom mem_free.
*/
void json_value_free_ex (json_settings * settings,
json_value *);
#ifdef __cplusplus
} /* extern "C" */
#endif

View file

@ -1 +1 @@
1.2.5
1.2.11

View file

@ -1,5 +1,5 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2007 Mark Adler
* Copyright (C) 1995-2011, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -7,11 +7,9 @@
#include "zutil.h"
#define local static
local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);
#define BASE 65521UL /* largest prime smaller than 65536 */
#define BASE 65521U /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
@ -21,46 +19,51 @@ local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
/* use NO_DIVIDE if your processor does not do division in hardware */
/* use NO_DIVIDE if your processor does not do division in hardware --
try it both ways to see which is faster */
#ifdef NO_DIVIDE
# define MOD(a) \
/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
(thank you to John Reiser for pointing this out) */
# define CHOP(a) \
do { \
if (a >= (BASE << 16)) a -= (BASE << 16); \
if (a >= (BASE << 15)) a -= (BASE << 15); \
if (a >= (BASE << 14)) a -= (BASE << 14); \
if (a >= (BASE << 13)) a -= (BASE << 13); \
if (a >= (BASE << 12)) a -= (BASE << 12); \
if (a >= (BASE << 11)) a -= (BASE << 11); \
if (a >= (BASE << 10)) a -= (BASE << 10); \
if (a >= (BASE << 9)) a -= (BASE << 9); \
if (a >= (BASE << 8)) a -= (BASE << 8); \
if (a >= (BASE << 7)) a -= (BASE << 7); \
if (a >= (BASE << 6)) a -= (BASE << 6); \
if (a >= (BASE << 5)) a -= (BASE << 5); \
if (a >= (BASE << 4)) a -= (BASE << 4); \
if (a >= (BASE << 3)) a -= (BASE << 3); \
if (a >= (BASE << 2)) a -= (BASE << 2); \
if (a >= (BASE << 1)) a -= (BASE << 1); \
unsigned long tmp = a >> 16; \
a &= 0xffffUL; \
a += (tmp << 4) - tmp; \
} while (0)
# define MOD28(a) \
do { \
CHOP(a); \
if (a >= BASE) a -= BASE; \
} while (0)
# define MOD4(a) \
# define MOD(a) \
do { \
if (a >= (BASE << 4)) a -= (BASE << 4); \
if (a >= (BASE << 3)) a -= (BASE << 3); \
if (a >= (BASE << 2)) a -= (BASE << 2); \
if (a >= (BASE << 1)) a -= (BASE << 1); \
CHOP(a); \
MOD28(a); \
} while (0)
# define MOD63(a) \
do { /* this assumes a is not negative */ \
z_off64_t tmp = a >> 32; \
a &= 0xffffffffL; \
a += (tmp << 8) - (tmp << 5) + tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
if (a >= BASE) a -= BASE; \
} while (0)
#else
# define MOD(a) a %= BASE
# define MOD4(a) a %= BASE
# define MOD28(a) a %= BASE
# define MOD63(a) a %= BASE
#endif
/* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len)
uLong ZEXPORT adler32_z(adler, buf, len)
uLong adler;
const Bytef *buf;
uInt len;
z_size_t len;
{
unsigned long sum2;
unsigned n;
@ -92,7 +95,7 @@ uLong ZEXPORT adler32(adler, buf, len)
}
if (adler >= BASE)
adler -= BASE;
MOD4(sum2); /* only added so many BASE's */
MOD28(sum2); /* only added so many BASE's */
return adler | (sum2 << 16);
}
@ -127,6 +130,15 @@ uLong ZEXPORT adler32(adler, buf, len)
return adler | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len)
uLong adler;
const Bytef *buf;
uInt len;
{
return adler32_z(adler, buf, len);
}
/* ========================================================================= */
local uLong adler32_combine_(adler1, adler2, len2)
uLong adler1;
@ -137,8 +149,13 @@ local uLong adler32_combine_(adler1, adler2, len2)
unsigned long sum2;
unsigned rem;
/* for negative len, return invalid adler32 as a clue for debugging */
if (len2 < 0)
return 0xffffffffUL;
/* the derivation of this formula is left as an exercise for the reader */
rem = (unsigned)(len2 % BASE);
MOD63(len2); /* assumes len2 >= 0 */
rem = (unsigned)len2;
sum1 = adler1 & 0xffff;
sum2 = rem * sum1;
MOD(sum2);
@ -146,7 +163,7 @@ local uLong adler32_combine_(adler1, adler2, len2)
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}

View file

@ -1,5 +1,5 @@
/* compress.c -- compress a memory buffer
* Copyright (C) 1995-2005 Jean-loup Gailly.
* Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -28,16 +28,11 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
{
z_stream stream;
int err;
const uInt max = (uInt)-1;
uLong left;
stream.next_in = (Bytef*)source;
stream.avail_in = (uInt)sourceLen;
#ifdef MAXSEG_64K
/* Check for source > 64K on 16-bit machine: */
if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
#endif
stream.next_out = dest;
stream.avail_out = (uInt)*destLen;
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
left = *destLen;
*destLen = 0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
@ -46,15 +41,26 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
err = deflateInit(&stream, level);
if (err != Z_OK) return err;
err = deflate(&stream, Z_FINISH);
if (err != Z_STREAM_END) {
deflateEnd(&stream);
return err == Z_OK ? Z_BUF_ERROR : err;
}
*destLen = stream.total_out;
stream.next_out = dest;
stream.avail_out = 0;
stream.next_in = (z_const Bytef *)source;
stream.avail_in = 0;
err = deflateEnd(&stream);
return err;
do {
if (stream.avail_out == 0) {
stream.avail_out = left > (uLong)max ? max : (uInt)left;
left -= stream.avail_out;
}
if (stream.avail_in == 0) {
stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;
sourceLen -= stream.avail_in;
}
err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
} while (err == Z_OK);
*destLen = stream.total_out;
deflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK : err;
}
/* ===========================================================================

View file

@ -1,5 +1,5 @@
/* crc32.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-2006, 2010 Mark Adler
* Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*
* Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
@ -17,6 +17,8 @@
of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
first call get_crc_table() to initialize the tables before allowing more than
one thread to use crc32().
DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.
*/
#ifdef MAKECRCH
@ -28,37 +30,15 @@
#include "zutil.h" /* for STDC and FAR definitions */
#define local static
/* Find a four-byte integer type for crc32_little() and crc32_big(). */
#ifndef NOBYFOUR
# ifdef STDC /* need ANSI C limits.h to determine sizes */
# include <limits.h>
# define BYFOUR
# if (UINT_MAX == 0xffffffffUL)
typedef unsigned int u4;
# else
# if (ULONG_MAX == 0xffffffffUL)
typedef unsigned long u4;
# else
# if (USHRT_MAX == 0xffffffffUL)
typedef unsigned short u4;
# else
# undef BYFOUR /* can't find a four-byte integer type! */
# endif
# endif
# endif
# endif /* STDC */
#endif /* !NOBYFOUR */
/* Definitions for doing the crc four data bytes at a time. */
#if !defined(NOBYFOUR) && defined(Z_U4)
# define BYFOUR
#endif
#ifdef BYFOUR
# define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \
(((w)&0xff00)<<8)+(((w)&0xff)<<24))
local unsigned long crc32_little OF((unsigned long,
const unsigned char FAR *, unsigned));
const unsigned char FAR *, z_size_t));
local unsigned long crc32_big OF((unsigned long,
const unsigned char FAR *, unsigned));
const unsigned char FAR *, z_size_t));
# define TBLS 8
#else
# define TBLS 1
@ -68,16 +48,16 @@
local unsigned long gf2_matrix_times OF((unsigned long *mat,
unsigned long vec));
local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2);
local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));
#ifdef DYNAMIC_CRC_TABLE
local volatile int crc_table_empty = 1;
local unsigned long FAR crc_table[TBLS][256];
local z_crc_t FAR crc_table[TBLS][256];
local void make_crc_table OF((void));
#ifdef MAKECRCH
local void write_table OF((FILE *, const unsigned long FAR *));
local void write_table OF((FILE *, const z_crc_t FAR *));
#endif /* MAKECRCH */
/*
Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
@ -107,9 +87,9 @@ local void make_crc_table OF((void));
*/
local void make_crc_table()
{
unsigned long c;
z_crc_t c;
int n, k;
unsigned long poly; /* polynomial exclusive-or pattern */
z_crc_t poly; /* polynomial exclusive-or pattern */
/* terms of polynomial defining this crc (except x^32): */
static volatile int first = 1; /* flag to limit concurrent making */
static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
@ -121,13 +101,13 @@ local void make_crc_table()
first = 0;
/* make exclusive-or pattern from polynomial (0xedb88320UL) */
poly = 0UL;
for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
poly |= 1UL << (31 - p[n]);
poly = 0;
for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
poly |= (z_crc_t)1 << (31 - p[n]);
/* generate a crc for every 8-bit value */
for (n = 0; n < 256; n++) {
c = (unsigned long)n;
c = (z_crc_t)n;
for (k = 0; k < 8; k++)
c = c & 1 ? poly ^ (c >> 1) : c >> 1;
crc_table[0][n] = c;
@ -138,11 +118,11 @@ local void make_crc_table()
and then the byte reversal of those as well as the first table */
for (n = 0; n < 256; n++) {
c = crc_table[0][n];
crc_table[4][n] = REV(c);
crc_table[4][n] = ZSWAP32(c);
for (k = 1; k < 4; k++) {
c = crc_table[0][c & 0xff] ^ (c >> 8);
crc_table[k][n] = c;
crc_table[k + 4][n] = REV(c);
crc_table[k + 4][n] = ZSWAP32(c);
}
}
#endif /* BYFOUR */
@ -164,7 +144,7 @@ local void make_crc_table()
if (out == NULL) return;
fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
fprintf(out, "local const unsigned long FAR ");
fprintf(out, "local const z_crc_t FAR ");
fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
write_table(out, crc_table[0]);
# ifdef BYFOUR
@ -184,12 +164,13 @@ local void make_crc_table()
#ifdef MAKECRCH
local void write_table(out, table)
FILE *out;
const unsigned long FAR *table;
const z_crc_t FAR *table;
{
int n;
for (n = 0; n < 256; n++)
fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ",
(unsigned long)(table[n]),
n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
}
#endif /* MAKECRCH */
@ -204,13 +185,13 @@ local void write_table(out, table)
/* =========================================================================
* This function can be used by asm versions of crc32()
*/
const unsigned long FAR * ZEXPORT get_crc_table()
const z_crc_t FAR * ZEXPORT get_crc_table()
{
#ifdef DYNAMIC_CRC_TABLE
if (crc_table_empty)
make_crc_table();
#endif /* DYNAMIC_CRC_TABLE */
return (const unsigned long FAR *)crc_table;
return (const z_crc_t FAR *)crc_table;
}
/* ========================================================================= */
@ -218,10 +199,10 @@ const unsigned long FAR * ZEXPORT get_crc_table()
#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
/* ========================================================================= */
unsigned long ZEXPORT crc32(crc, buf, len)
unsigned long ZEXPORT crc32_z(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
uInt len;
z_size_t len;
{
if (buf == Z_NULL) return 0UL;
@ -232,7 +213,7 @@ unsigned long ZEXPORT crc32(crc, buf, len)
#ifdef BYFOUR
if (sizeof(void *) == sizeof(ptrdiff_t)) {
u4 endian;
z_crc_t endian;
endian = 1;
if (*((unsigned char *)(&endian)))
@ -252,8 +233,29 @@ unsigned long ZEXPORT crc32(crc, buf, len)
return crc ^ 0xffffffffUL;
}
/* ========================================================================= */
unsigned long ZEXPORT crc32(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
uInt len;
{
return crc32_z(crc, buf, len);
}
#ifdef BYFOUR
/*
This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit
integer pointer type. This violates the strict aliasing rule, where a
compiler can assume, for optimization purposes, that two pointers to
fundamentally different types won't ever point to the same memory. This can
manifest as a problem only if one of the pointers is written to. This code
only reads from those pointers. So long as this code remains isolated in
this compilation unit, there won't be a problem. For this reason, this code
should not be copied and pasted into a compilation unit in which other code
writes to the buffer that is passed to these routines.
*/
/* ========================================================================= */
#define DOLIT4 c ^= *buf4++; \
c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
@ -264,19 +266,19 @@ unsigned long ZEXPORT crc32(crc, buf, len)
local unsigned long crc32_little(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
unsigned len;
z_size_t len;
{
register u4 c;
register const u4 FAR *buf4;
register z_crc_t c;
register const z_crc_t FAR *buf4;
c = (u4)crc;
c = (z_crc_t)crc;
c = ~c;
while (len && ((ptrdiff_t)buf & 3)) {
c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
len--;
}
buf4 = (const u4 FAR *)(const void FAR *)buf;
buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
while (len >= 32) {
DOLIT32;
len -= 32;
@ -295,7 +297,7 @@ local unsigned long crc32_little(crc, buf, len)
}
/* ========================================================================= */
#define DOBIG4 c ^= *++buf4; \
#define DOBIG4 c ^= *buf4++; \
c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
@ -304,20 +306,19 @@ local unsigned long crc32_little(crc, buf, len)
local unsigned long crc32_big(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
unsigned len;
z_size_t len;
{
register u4 c;
register const u4 FAR *buf4;
register z_crc_t c;
register const z_crc_t FAR *buf4;
c = REV((u4)crc);
c = ZSWAP32((z_crc_t)crc);
c = ~c;
while (len && ((ptrdiff_t)buf & 3)) {
c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
len--;
}
buf4 = (const u4 FAR *)(const void FAR *)buf;
buf4--;
buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
while (len >= 32) {
DOBIG32;
len -= 32;
@ -326,14 +327,13 @@ local unsigned long crc32_big(crc, buf, len)
DOBIG4;
len -= 4;
}
buf4++;
buf = (const unsigned char FAR *)buf4;
if (len) do {
c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
} while (--len);
c = ~c;
return (unsigned long)(REV(c));
return (unsigned long)(ZSWAP32(c));
}
#endif /* BYFOUR */

View file

@ -2,7 +2,7 @@
* Generated automatically by crc32.c
*/
local const unsigned long FAR crc_table[TBLS][256] =
local const z_crc_t FAR crc_table[TBLS][256] =
{
{
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* deflate.h -- internal compression state
* Copyright (C) 1995-2010 Jean-loup Gailly
* Copyright (C) 1995-2016 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -48,13 +48,19 @@
#define MAX_BITS 15
/* All codes must not exceed MAX_BITS bits */
#define INIT_STATE 42
#define EXTRA_STATE 69
#define NAME_STATE 73
#define COMMENT_STATE 91
#define HCRC_STATE 103
#define BUSY_STATE 113
#define FINISH_STATE 666
#define Buf_size 16
/* size of bit buffer in bi_buf */
#define INIT_STATE 42 /* zlib header -> BUSY_STATE */
#ifdef GZIP
# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */
#endif
#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */
#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */
#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */
#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */
#define BUSY_STATE 113 /* deflate -> FINISH_STATE */
#define FINISH_STATE 666 /* stream complete */
/* Stream status */
@ -80,7 +86,7 @@ typedef struct static_tree_desc_s static_tree_desc;
typedef struct tree_desc_s {
ct_data *dyn_tree; /* the dynamic tree */
int max_code; /* largest code with non zero frequency */
static_tree_desc *stat_desc; /* the corresponding static tree */
const static_tree_desc *stat_desc; /* the corresponding static tree */
} FAR tree_desc;
typedef ush Pos;
@ -97,11 +103,11 @@ typedef struct internal_state {
Bytef *pending_buf; /* output still pending */
ulg pending_buf_size; /* size of pending_buf */
Bytef *pending_out; /* next pending byte to output to the stream */
uInt pending; /* nb of bytes in the pending buffer */
ulg pending; /* nb of bytes in the pending buffer */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
gz_headerp gzhead; /* gzip header information to write */
uInt gzindex; /* where in extra, name, or comment */
Byte method; /* STORED (for zip only) or DEFLATED */
ulg gzindex; /* where in extra, name, or comment */
Byte method; /* can only be DEFLATED */
int last_flush; /* value of flush param for previous deflate call */
/* used by deflate.c: */
@ -188,7 +194,7 @@ typedef struct internal_state {
int nice_match; /* Stop searching when current match exceeds this */
/* used by trees.c: */
/* Didn't use ct_data typedef below to supress compiler warning */
/* Didn't use ct_data typedef below to suppress compiler warning */
struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
@ -244,9 +250,9 @@ typedef struct internal_state {
ulg opt_len; /* bit length of current block with optimal trees */
ulg static_len; /* bit length of current block with static trees */
uInt matches; /* number of string matches in current block */
int last_eob_len; /* bit length of EOB code for last block */
uInt insert; /* bytes at end of window left to insert */
#ifdef DEBUG
#ifdef ZLIB_DEBUG
ulg compressed_len; /* total bit length of compressed file mod 2^32 */
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
#endif
@ -272,7 +278,7 @@ typedef struct internal_state {
/* Output a byte on the stream.
* IN assertion: there is enough room in pending_buf.
*/
#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}
#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
@ -294,6 +300,7 @@ void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
ulg stored_len, int last));
void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
ulg stored_len, int last));
@ -305,7 +312,7 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
* used.
*/
#ifndef DEBUG
#ifndef ZLIB_DEBUG
/* Inline versions of _tr_tally for speed: */
#if defined(GEN_TREES_H) || !defined(STDC)
@ -324,8 +331,8 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
flush = (s->last_lit == s->lit_bufsize-1); \
}
# define _tr_tally_dist(s, distance, length, flush) \
{ uch len = (length); \
ush dist = (distance); \
{ uch len = (uch)(length); \
ush dist = (ush)(distance); \
s->d_buf[s->last_lit] = dist; \
s->l_buf[s->last_lit++] = len; \
dist--; \

218
src/engine/external/zlib/gzguts.h vendored Normal file
View file

@ -0,0 +1,218 @@
/* gzguts.h -- zlib internal header definitions for gz* operations
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef _LARGEFILE64_SOURCE
# ifndef _LARGEFILE_SOURCE
# define _LARGEFILE_SOURCE 1
# endif
# ifdef _FILE_OFFSET_BITS
# undef _FILE_OFFSET_BITS
# endif
#endif
#ifdef HAVE_HIDDEN
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
# define ZLIB_INTERNAL
#endif
#include <stdio.h>
#include "zlib.h"
#ifdef STDC
# include <string.h>
# include <stdlib.h>
# include <limits.h>
#endif
#ifndef _POSIX_SOURCE
# define _POSIX_SOURCE
#endif
#include <fcntl.h>
#ifdef _WIN32
# include <stddef.h>
#endif
#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
# include <io.h>
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
# define WIDECHAR
#endif
#ifdef WINAPI_FAMILY
# define open _open
# define read _read
# define write _write
# define close _close
#endif
#ifdef NO_DEFLATE /* for compatibility with old definition */
# define NO_GZCOMPRESS
#endif
#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(__CYGWIN__)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#ifndef HAVE_VSNPRINTF
# ifdef MSDOS
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
but for now we just assume it doesn't. */
# define NO_vsnprintf
# endif
# ifdef __TURBOC__
# define NO_vsnprintf
# endif
# ifdef WIN32
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
# if !defined(vsnprintf) && !defined(NO_vsnprintf)
# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
# define vsnprintf _vsnprintf
# endif
# endif
# endif
# ifdef __SASC
# define NO_vsnprintf
# endif
# ifdef VMS
# define NO_vsnprintf
# endif
# ifdef __OS400__
# define NO_vsnprintf
# endif
# ifdef __MVS__
# define NO_vsnprintf
# endif
#endif
/* unlike snprintf (which is required in C99), _snprintf does not guarantee
null termination of the result -- however this is only used in gzlib.c where
the result is assured to fit in the space provided */
#if defined(_MSC_VER) && _MSC_VER < 1900
# define snprintf _snprintf
#endif
#ifndef local
# define local static
#endif
/* since "static" is used to mean two completely different things in C, we
define "local" for the non-static meaning of "static", for readability
(compile with -Dlocal if your debugger can't find static symbols) */
/* gz* functions always use library allocation functions */
#ifndef STDC
extern voidp malloc OF((uInt size));
extern void free OF((voidpf ptr));
#endif
/* get errno and strerror definition */
#if defined UNDER_CE
# include <windows.h>
# define zstrerror() gz_strwinerror((DWORD)GetLastError())
#else
# ifndef NO_STRERROR
# include <errno.h>
# define zstrerror() strerror(errno)
# else
# define zstrerror() "stdio error (consult errno)"
# endif
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
#endif
/* default memLevel */
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
/* default i/o buffer size -- double this for output when reading (this and
twice this must be able to fit in an unsigned type) */
#define GZBUFSIZE 8192
/* gzip modes, also provide a little integrity check on the passed structure */
#define GZ_NONE 0
#define GZ_READ 7247
#define GZ_WRITE 31153
#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */
/* values for gz_state how */
#define LOOK 0 /* look for a gzip header */
#define COPY 1 /* copy input directly */
#define GZIP 2 /* decompress a gzip stream */
/* internal gzip file state data structure */
typedef struct {
/* exposed contents for gzgetc() macro */
struct gzFile_s x; /* "x" for exposed */
/* x.have: number of bytes available at x.next */
/* x.next: next output data to deliver or write */
/* x.pos: current position in uncompressed data */
/* used for both reading and writing */
int mode; /* see gzip modes above */
int fd; /* file descriptor */
char *path; /* path or fd for error messages */
unsigned size; /* buffer size, zero if not allocated yet */
unsigned want; /* requested buffer size, default is GZBUFSIZE */
unsigned char *in; /* input buffer (double-sized when writing) */
unsigned char *out; /* output buffer (double-sized when reading) */
int direct; /* 0 if processing gzip, 1 if transparent */
/* just for reading */
int how; /* 0: get header, 1: copy, 2: decompress */
z_off64_t start; /* where the gzip data started, for rewinding */
int eof; /* true if end of input file reached */
int past; /* true if read requested past end */
/* just for writing */
int level; /* compression level */
int strategy; /* compression strategy */
/* seek request */
z_off64_t skip; /* amount to skip (already rewound if backwards) */
int seek; /* true if seek request pending */
/* error information */
int err; /* error code */
char *msg; /* error message */
/* zlib inflate or deflate stream */
z_stream strm; /* stream structure in-place (not a pointer) */
} gz_state;
typedef gz_state FAR *gz_statep;
/* shared functions */
void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
#if defined UNDER_CE
char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
#endif
/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
value -- needed when comparing unsigned to z_off64_t, which is signed
(possible z_off64_t types off_t, off64_t, and long are all signed) */
#ifdef INT_MAX
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
#else
unsigned ZLIB_INTERNAL gz_intmax OF((void));
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
#endif

View file

@ -1,5 +1,5 @@
/* infback.c -- inflate using a call-back interface
* Copyright (C) 1995-2009 Mark Adler
* Copyright (C) 1995-2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -42,17 +42,26 @@ int stream_size;
return Z_STREAM_ERROR;
strm->msg = Z_NULL; /* in case we return an error */
if (strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
return Z_STREAM_ERROR;
#else
strm->zalloc = zcalloc;
strm->opaque = (voidpf)0;
#endif
}
if (strm->zfree == (free_func)0) strm->zfree = zcfree;
if (strm->zfree == (free_func)0)
#ifdef Z_SOLO
return Z_STREAM_ERROR;
#else
strm->zfree = zcfree;
#endif
state = (struct inflate_state FAR *)ZALLOC(strm, 1,
sizeof(struct inflate_state));
if (state == Z_NULL) return Z_MEM_ERROR;
Tracev((stderr, "inflate: allocated\n"));
strm->state = (struct internal_state FAR *)state;
state->dmax = 32768U;
state->wbits = windowBits;
state->wbits = (uInt)windowBits;
state->wsize = 1U << windowBits;
state->window = window;
state->wnext = 0;
@ -246,7 +255,7 @@ out_func out;
void FAR *out_desc;
{
struct inflate_state FAR *state;
unsigned char FAR *next; /* next input */
z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */
unsigned have, left; /* available input and output */
unsigned long hold; /* bit buffer */
@ -394,7 +403,6 @@ void FAR *out_desc;
PULLBYTE();
}
if (here.val < 16) {
NEEDBITS(here.bits);
DROPBITS(here.bits);
state->lens[state->have++] = here.val;
}

View file

@ -1,5 +1,5 @@
/* inffast.c -- fast decoding
* Copyright (C) 1995-2008, 2010 Mark Adler
* Copyright (C) 1995-2017 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -8,26 +8,9 @@
#include "inflate.h"
#include "inffast.h"
#ifndef ASMINF
/* Allow machine dependent optimization for post-increment or pre-increment.
Based on testing to date,
Pre-increment preferred for:
- PowerPC G3 (Adler)
- MIPS R5000 (Randers-Pehrson)
Post-increment preferred for:
- none
No measurable difference:
- Pentium III (Anderson)
- M68060 (Nikl)
*/
#ifdef POSTINC
# define OFF 0
# define PUP(a) *(a)++
#ifdef ASMINF
# pragma message("Assembler code may have bugs -- use at your own risk")
#else
# define OFF 1
# define PUP(a) *++(a)
#endif
/*
Decode literal, length, and distance codes and write out the resulting
@ -69,8 +52,8 @@ z_streamp strm;
unsigned start; /* inflate()'s starting value for strm->avail_out */
{
struct inflate_state FAR *state;
unsigned char FAR *in; /* local strm->next_in */
unsigned char FAR *last; /* while in < last, enough input available */
z_const unsigned char FAR *in; /* local strm->next_in */
z_const unsigned char FAR *last; /* have enough input while in < last */
unsigned char FAR *out; /* local strm->next_out */
unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
unsigned char FAR *end; /* while out < end, enough space available */
@ -96,9 +79,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
/* copy state to local variables */
state = (struct inflate_state FAR *)strm->state;
in = strm->next_in - OFF;
in = strm->next_in;
last = in + (strm->avail_in - 5);
out = strm->next_out - OFF;
out = strm->next_out;
beg = out - (start - strm->avail_out);
end = out + (strm->avail_out - 257);
#ifdef INFLATE_STRICT
@ -119,9 +102,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
input data or output space */
do {
if (bits < 15) {
hold += (unsigned long)(PUP(in)) << bits;
hold += (unsigned long)(*in++) << bits;
bits += 8;
hold += (unsigned long)(PUP(in)) << bits;
hold += (unsigned long)(*in++) << bits;
bits += 8;
}
here = lcode[hold & lmask];
@ -134,14 +117,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
"inflate: literal '%c'\n" :
"inflate: literal 0x%02x\n", here.val));
PUP(out) = (unsigned char)(here.val);
*out++ = (unsigned char)(here.val);
}
else if (op & 16) { /* length base */
len = (unsigned)(here.val);
op &= 15; /* number of extra bits */
if (op) {
if (bits < op) {
hold += (unsigned long)(PUP(in)) << bits;
hold += (unsigned long)(*in++) << bits;
bits += 8;
}
len += (unsigned)hold & ((1U << op) - 1);
@ -150,9 +133,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
}
Tracevv((stderr, "inflate: length %u\n", len));
if (bits < 15) {
hold += (unsigned long)(PUP(in)) << bits;
hold += (unsigned long)(*in++) << bits;
bits += 8;
hold += (unsigned long)(PUP(in)) << bits;
hold += (unsigned long)(*in++) << bits;
bits += 8;
}
here = dcode[hold & dmask];
@ -165,10 +148,10 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
dist = (unsigned)(here.val);
op &= 15; /* number of extra bits */
if (bits < op) {
hold += (unsigned long)(PUP(in)) << bits;
hold += (unsigned long)(*in++) << bits;
bits += 8;
if (bits < op) {
hold += (unsigned long)(PUP(in)) << bits;
hold += (unsigned long)(*in++) << bits;
bits += 8;
}
}
@ -196,30 +179,30 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
if (len <= op - whave) {
do {
PUP(out) = 0;
*out++ = 0;
} while (--len);
continue;
}
len -= op - whave;
do {
PUP(out) = 0;
*out++ = 0;
} while (--op > whave);
if (op == 0) {
from = out - dist;
do {
PUP(out) = PUP(from);
*out++ = *from++;
} while (--len);
continue;
}
#endif
}
from = window - OFF;
from = window;
if (wnext == 0) { /* very common case */
from += wsize - op;
if (op < len) { /* some from window */
len -= op;
do {
PUP(out) = PUP(from);
*out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
@ -230,14 +213,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
if (op < len) { /* some from end of window */
len -= op;
do {
PUP(out) = PUP(from);
*out++ = *from++;
} while (--op);
from = window - OFF;
from = window;
if (wnext < len) { /* some from start of window */
op = wnext;
len -= op;
do {
PUP(out) = PUP(from);
*out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
@ -248,35 +231,35 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
if (op < len) { /* some from window */
len -= op;
do {
PUP(out) = PUP(from);
*out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
}
while (len > 2) {
PUP(out) = PUP(from);
PUP(out) = PUP(from);
PUP(out) = PUP(from);
*out++ = *from++;
*out++ = *from++;
*out++ = *from++;
len -= 3;
}
if (len) {
PUP(out) = PUP(from);
*out++ = *from++;
if (len > 1)
PUP(out) = PUP(from);
*out++ = *from++;
}
}
else {
from = out - dist; /* copy direct from output */
do { /* minimum length is three */
PUP(out) = PUP(from);
PUP(out) = PUP(from);
PUP(out) = PUP(from);
*out++ = *from++;
*out++ = *from++;
*out++ = *from++;
len -= 3;
} while (len > 2);
if (len) {
PUP(out) = PUP(from);
*out++ = *from++;
if (len > 1)
PUP(out) = PUP(from);
*out++ = *from++;
}
}
}
@ -313,8 +296,8 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
hold &= (1U << bits) - 1;
/* update state and return */
strm->next_in = in + OFF;
strm->next_out = out + OFF;
strm->next_in = in;
strm->next_out = out;
strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
strm->avail_out = (unsigned)(out < end ?
257 + (end - out) : 257 - (out - end));

View file

@ -2,9 +2,9 @@
* Generated automatically by makefixed().
*/
/* WARNING: this file should *not* be used by applications. It
is part of the implementation of the compression library and
is subject to change. Applications should only use zlib.h.
/* WARNING: this file should *not* be used by applications.
It is part of the implementation of this library and is
subject to change. Applications should only use zlib.h.
*/
static const code lenfix[512] = {

View file

@ -1,5 +1,5 @@
/* inflate.c -- zlib decompression
* Copyright (C) 1995-2010 Mark Adler
* Copyright (C) 1995-2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -92,32 +92,46 @@
#endif
/* function prototypes */
local int inflateStateCheck OF((z_streamp strm));
local void fixedtables OF((struct inflate_state FAR *state));
local int updatewindow OF((z_streamp strm, unsigned out));
local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
unsigned copy));
#ifdef BUILDFIXED
void makefixed OF((void));
#endif
local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
unsigned len));
int ZEXPORT inflateReset(strm)
local int inflateStateCheck(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
if (strm == Z_NULL ||
strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
return 1;
state = (struct inflate_state FAR *)strm->state;
if (state == Z_NULL || state->strm != strm ||
state->mode < HEAD || state->mode > SYNC)
return 1;
return 0;
}
int ZEXPORT inflateResetKeep(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
strm->total_in = strm->total_out = state->total = 0;
strm->msg = Z_NULL;
strm->adler = 1; /* to support ill-conceived Java test suite */
if (state->wrap) /* to support ill-conceived Java test suite */
strm->adler = state->wrap & 1;
state->mode = HEAD;
state->last = 0;
state->havedict = 0;
state->dmax = 32768U;
state->head = Z_NULL;
state->wsize = 0;
state->whave = 0;
state->wnext = 0;
state->hold = 0;
state->bits = 0;
state->lencode = state->distcode = state->next = state->codes;
@ -127,6 +141,19 @@ z_streamp strm;
return Z_OK;
}
int ZEXPORT inflateReset(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
state->wsize = 0;
state->whave = 0;
state->wnext = 0;
return inflateResetKeep(strm);
}
int ZEXPORT inflateReset2(strm, windowBits)
z_streamp strm;
int windowBits;
@ -135,7 +162,7 @@ int windowBits;
struct inflate_state FAR *state;
/* get the state */
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
/* extract wrap request from windowBits parameter */
@ -144,7 +171,7 @@ int windowBits;
windowBits = -windowBits;
}
else {
wrap = (windowBits >> 4) + 1;
wrap = (windowBits >> 4) + 5;
#ifdef GUNZIP
if (windowBits < 48)
windowBits &= 15;
@ -180,16 +207,27 @@ int stream_size;
if (strm == Z_NULL) return Z_STREAM_ERROR;
strm->msg = Z_NULL; /* in case we return an error */
if (strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
return Z_STREAM_ERROR;
#else
strm->zalloc = zcalloc;
strm->opaque = (voidpf)0;
#endif
}
if (strm->zfree == (free_func)0) strm->zfree = zcfree;
if (strm->zfree == (free_func)0)
#ifdef Z_SOLO
return Z_STREAM_ERROR;
#else
strm->zfree = zcfree;
#endif
state = (struct inflate_state FAR *)
ZALLOC(strm, 1, sizeof(struct inflate_state));
if (state == Z_NULL) return Z_MEM_ERROR;
Tracev((stderr, "inflate: allocated\n"));
strm->state = (struct internal_state FAR *)state;
state->strm = strm;
state->window = Z_NULL;
state->mode = HEAD; /* to pass state test in inflateReset2() */
ret = inflateReset2(strm, windowBits);
if (ret != Z_OK) {
ZFREE(strm, state);
@ -213,17 +251,17 @@ int value;
{
struct inflate_state FAR *state;
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (bits < 0) {
state->hold = 0;
state->bits = 0;
return Z_OK;
}
if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;
value &= (1L << bits) - 1;
state->hold += value << state->bits;
state->bits += bits;
state->hold += (unsigned)value << state->bits;
state->bits += (uInt)bits;
return Z_OK;
}
@ -321,8 +359,8 @@ void makefixed()
low = 0;
for (;;) {
if ((low % 7) == 0) printf("\n ");
printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
state.lencode[low].val);
printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
state.lencode[low].bits, state.lencode[low].val);
if (++low == size) break;
putchar(',');
}
@ -355,12 +393,13 @@ void makefixed()
output will fall in the output data, making match copies simpler and faster.
The advantage may be dependent on the size of the processor's data caches.
*/
local int updatewindow(strm, out)
local int updatewindow(strm, end, copy)
z_streamp strm;
unsigned out;
const Bytef *end;
unsigned copy;
{
struct inflate_state FAR *state;
unsigned copy, dist;
unsigned dist;
state = (struct inflate_state FAR *)strm->state;
@ -380,19 +419,18 @@ unsigned out;
}
/* copy state->wsize or less output bytes into the circular window */
copy = out - strm->avail_out;
if (copy >= state->wsize) {
zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
zmemcpy(state->window, end - state->wsize, state->wsize);
state->wnext = 0;
state->whave = state->wsize;
}
else {
dist = state->wsize - state->wnext;
if (dist > copy) dist = copy;
zmemcpy(state->window + state->wnext, strm->next_out - copy, dist);
zmemcpy(state->window + state->wnext, end - copy, dist);
copy -= dist;
if (copy) {
zmemcpy(state->window, strm->next_out - copy, copy);
zmemcpy(state->window, end - copy, copy);
state->wnext = copy;
state->whave = state->wsize;
}
@ -499,11 +537,6 @@ unsigned out;
bits -= bits & 7; \
} while (0)
/* Reverse the bytes in a 32-bit value */
#define REVERSE(q) \
((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
(((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
/*
inflate() uses a state machine to process as much input data and generate as
much output data as possible before returning. The state machine is
@ -591,7 +624,7 @@ z_streamp strm;
int flush;
{
struct inflate_state FAR *state;
unsigned char FAR *next; /* next input */
z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */
unsigned have, left; /* available input and output */
unsigned long hold; /* bit buffer */
@ -609,7 +642,7 @@ int flush;
static const unsigned short order[19] = /* permutation of code lengths */
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||
(strm->next_in == Z_NULL && strm->avail_in != 0))
return Z_STREAM_ERROR;
@ -629,6 +662,8 @@ int flush;
NEEDBITS(16);
#ifdef GUNZIP
if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
if (state->wbits == 0)
state->wbits = 15;
state->check = crc32(0L, Z_NULL, 0);
CRC2(state->check, hold);
INITBITS();
@ -656,7 +691,7 @@ int flush;
len = BITS(4) + 8;
if (state->wbits == 0)
state->wbits = len;
else if (len > state->wbits) {
if (len > 15 || len > state->wbits) {
strm->msg = (char *)"invalid window size";
state->mode = BAD;
break;
@ -683,14 +718,16 @@ int flush;
}
if (state->head != Z_NULL)
state->head->text = (int)((hold >> 8) & 1);
if (state->flags & 0x0200) CRC2(state->check, hold);
if ((state->flags & 0x0200) && (state->wrap & 4))
CRC2(state->check, hold);
INITBITS();
state->mode = TIME;
case TIME:
NEEDBITS(32);
if (state->head != Z_NULL)
state->head->time = hold;
if (state->flags & 0x0200) CRC4(state->check, hold);
if ((state->flags & 0x0200) && (state->wrap & 4))
CRC4(state->check, hold);
INITBITS();
state->mode = OS;
case OS:
@ -699,7 +736,8 @@ int flush;
state->head->xflags = (int)(hold & 0xff);
state->head->os = (int)(hold >> 8);
}
if (state->flags & 0x0200) CRC2(state->check, hold);
if ((state->flags & 0x0200) && (state->wrap & 4))
CRC2(state->check, hold);
INITBITS();
state->mode = EXLEN;
case EXLEN:
@ -708,7 +746,8 @@ int flush;
state->length = (unsigned)(hold);
if (state->head != Z_NULL)
state->head->extra_len = (unsigned)hold;
if (state->flags & 0x0200) CRC2(state->check, hold);
if ((state->flags & 0x0200) && (state->wrap & 4))
CRC2(state->check, hold);
INITBITS();
}
else if (state->head != Z_NULL)
@ -726,7 +765,7 @@ int flush;
len + copy > state->head->extra_max ?
state->head->extra_max - len : copy);
}
if (state->flags & 0x0200)
if ((state->flags & 0x0200) && (state->wrap & 4))
state->check = crc32(state->check, next, copy);
have -= copy;
next += copy;
@ -745,9 +784,9 @@ int flush;
if (state->head != Z_NULL &&
state->head->name != Z_NULL &&
state->length < state->head->name_max)
state->head->name[state->length++] = len;
state->head->name[state->length++] = (Bytef)len;
} while (len && copy < have);
if (state->flags & 0x0200)
if ((state->flags & 0x0200) && (state->wrap & 4))
state->check = crc32(state->check, next, copy);
have -= copy;
next += copy;
@ -766,9 +805,9 @@ int flush;
if (state->head != Z_NULL &&
state->head->comment != Z_NULL &&
state->length < state->head->comm_max)
state->head->comment[state->length++] = len;
state->head->comment[state->length++] = (Bytef)len;
} while (len && copy < have);
if (state->flags & 0x0200)
if ((state->flags & 0x0200) && (state->wrap & 4))
state->check = crc32(state->check, next, copy);
have -= copy;
next += copy;
@ -780,7 +819,7 @@ int flush;
case HCRC:
if (state->flags & 0x0200) {
NEEDBITS(16);
if (hold != (state->check & 0xffff)) {
if ((state->wrap & 4) && hold != (state->check & 0xffff)) {
strm->msg = (char *)"header crc mismatch";
state->mode = BAD;
break;
@ -797,7 +836,7 @@ int flush;
#endif
case DICTID:
NEEDBITS(32);
strm->adler = state->check = REVERSE(hold);
strm->adler = state->check = ZSWAP32(hold);
INITBITS();
state->mode = DICT;
case DICT:
@ -905,7 +944,7 @@ int flush;
while (state->have < 19)
state->lens[order[state->have++]] = 0;
state->next = state->codes;
state->lencode = (code const FAR *)(state->next);
state->lencode = (const code FAR *)(state->next);
state->lenbits = 7;
ret = inflate_table(CODES, state->lens, 19, &(state->next),
&(state->lenbits), state->work);
@ -925,7 +964,6 @@ int flush;
PULLBYTE();
}
if (here.val < 16) {
NEEDBITS(here.bits);
DROPBITS(here.bits);
state->lens[state->have++] = here.val;
}
@ -980,7 +1018,7 @@ int flush;
values here (9 and 6) without reading the comments in inftrees.h
concerning the ENOUGH constants, which depend on those values */
state->next = state->codes;
state->lencode = (code const FAR *)(state->next);
state->lencode = (const code FAR *)(state->next);
state->lenbits = 9;
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
&(state->lenbits), state->work);
@ -989,7 +1027,7 @@ int flush;
state->mode = BAD;
break;
}
state->distcode = (code const FAR *)(state->next);
state->distcode = (const code FAR *)(state->next);
state->distbits = 6;
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
&(state->next), &(state->distbits), state->work);
@ -1162,15 +1200,15 @@ int flush;
out -= left;
strm->total_out += out;
state->total += out;
if (out)
if ((state->wrap & 4) && out)
strm->adler = state->check =
UPDATE(state->check, put - out, out);
out = left;
if ((
if ((state->wrap & 4) && (
#ifdef GUNZIP
state->flags ? hold :
#endif
REVERSE(hold)) != state->check) {
ZSWAP32(hold)) != state->check) {
strm->msg = (char *)"incorrect data check";
state->mode = BAD;
break;
@ -1214,8 +1252,9 @@ int flush;
*/
inf_leave:
RESTORE();
if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
if (updatewindow(strm, out)) {
if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
(state->mode < CHECK || flush != Z_FINISH)))
if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
state->mode = MEM;
return Z_MEM_ERROR;
}
@ -1224,10 +1263,10 @@ int flush;
strm->total_in += in;
strm->total_out += out;
state->total += out;
if (state->wrap && out)
if ((state->wrap & 4) && out)
strm->adler = state->check =
UPDATE(state->check, strm->next_out - out, out);
strm->data_type = state->bits + (state->last ? 64 : 0) +
strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
(state->mode == TYPE ? 128 : 0) +
(state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
@ -1239,7 +1278,7 @@ int ZEXPORT inflateEnd(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
if (inflateStateCheck(strm))
return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (state->window != Z_NULL) ZFREE(strm, state->window);
@ -1249,43 +1288,59 @@ z_streamp strm;
return Z_OK;
}
int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
z_streamp strm;
Bytef *dictionary;
uInt *dictLength;
{
struct inflate_state FAR *state;
/* check state */
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
/* copy dictionary */
if (state->whave && dictionary != Z_NULL) {
zmemcpy(dictionary, state->window + state->wnext,
state->whave - state->wnext);
zmemcpy(dictionary + state->whave - state->wnext,
state->window, state->wnext);
}
if (dictLength != Z_NULL)
*dictLength = state->whave;
return Z_OK;
}
int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
z_streamp strm;
const Bytef *dictionary;
uInt dictLength;
{
struct inflate_state FAR *state;
unsigned long id;
unsigned long dictid;
int ret;
/* check state */
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (state->wrap != 0 && state->mode != DICT)
return Z_STREAM_ERROR;
/* check for correct dictionary id */
/* check for correct dictionary identifier */
if (state->mode == DICT) {
id = adler32(0L, Z_NULL, 0);
id = adler32(id, dictionary, dictLength);
if (id != state->check)
dictid = adler32(0L, Z_NULL, 0);
dictid = adler32(dictid, dictionary, dictLength);
if (dictid != state->check)
return Z_DATA_ERROR;
}
/* copy dictionary to window */
if (updatewindow(strm, strm->avail_out)) {
/* copy dictionary to window using updatewindow(), which will amend the
existing dictionary if appropriate */
ret = updatewindow(strm, dictionary + dictLength, dictLength);
if (ret) {
state->mode = MEM;
return Z_MEM_ERROR;
}
if (dictLength > state->wsize) {
zmemcpy(state->window, dictionary + dictLength - state->wsize,
state->wsize);
state->whave = state->wsize;
}
else {
zmemcpy(state->window + state->wsize - dictLength, dictionary,
dictLength);
state->whave = dictLength;
}
state->havedict = 1;
Tracev((stderr, "inflate: dictionary set\n"));
return Z_OK;
@ -1298,7 +1353,7 @@ gz_headerp head;
struct inflate_state FAR *state;
/* check state */
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
@ -1321,7 +1376,7 @@ gz_headerp head;
*/
local unsigned syncsearch(have, buf, len)
unsigned FAR *have;
unsigned char FAR *buf;
const unsigned char FAR *buf;
unsigned len;
{
unsigned got;
@ -1351,7 +1406,7 @@ z_streamp strm;
struct inflate_state FAR *state;
/* check parameters */
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
@ -1398,7 +1453,7 @@ z_streamp strm;
{
struct inflate_state FAR *state;
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
return state->mode == STORED && state->bits == 0;
}
@ -1413,8 +1468,7 @@ z_streamp source;
unsigned wsize;
/* check input */
if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
if (inflateStateCheck(source) || dest == Z_NULL)
return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)source->state;
@ -1433,8 +1487,9 @@ z_streamp source;
}
/* copy state */
zmemcpy(dest, source, sizeof(z_stream));
zmemcpy(copy, state, sizeof(struct inflate_state));
zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
copy->strm = dest;
if (state->lencode >= state->codes &&
state->lencode <= state->codes + ENOUGH - 1) {
copy->lencode = copy->codes + (state->lencode - state->codes);
@ -1456,25 +1511,51 @@ int subvert;
{
struct inflate_state FAR *state;
if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
state->sane = !subvert;
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
state->sane = !subvert;
return Z_OK;
#else
(void)subvert;
state->sane = 1;
return Z_DATA_ERROR;
#endif
}
int ZEXPORT inflateValidate(strm, check)
z_streamp strm;
int check;
{
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (check)
state->wrap |= 4;
else
state->wrap &= ~4;
return Z_OK;
}
long ZEXPORT inflateMark(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
if (inflateStateCheck(strm))
return -(1L << 16);
state = (struct inflate_state FAR *)strm->state;
return ((long)(state->back) << 16) +
return (long)(((unsigned long)((long)state->back)) << 16) +
(state->mode == COPY ? state->length :
(state->mode == MATCH ? state->was - state->length : 0));
}
unsigned long ZEXPORT inflateCodesUsed(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return (unsigned long)-1;
state = (struct inflate_state FAR *)strm->state;
return (unsigned long)(state->next - state->codes);
}

View file

@ -1,5 +1,5 @@
/* inflate.h -- internal inflate state definition
* Copyright (C) 1995-2009 Mark Adler
* Copyright (C) 1995-2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -18,7 +18,7 @@
/* Possible inflate modes between inflate() calls */
typedef enum {
HEAD, /* i: waiting for magic header */
HEAD = 16180, /* i: waiting for magic header */
FLAGS, /* i: waiting for method and flags (gzip) */
TIME, /* i: waiting for modification time (gzip) */
OS, /* i: waiting for extra flags and operating system (gzip) */
@ -77,11 +77,14 @@ typedef enum {
CHECK -> LENGTH -> DONE
*/
/* state maintained between inflate() calls. Approximately 10K bytes. */
/* State maintained between inflate() calls -- approximately 7K bytes, not
including the allocated sliding window, which is up to 32K bytes. */
struct inflate_state {
z_streamp strm; /* pointer back to this zlib stream */
inflate_mode mode; /* current inflate mode */
int last; /* true if processing last block */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip,
bit 2 true to validate check value */
int havedict; /* true if dictionary provided */
int flags; /* gzip header method and flags (0 if zlib) */
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */

View file

@ -1,5 +1,5 @@
/* inftrees.c -- generate Huffman trees for efficient decoding
* Copyright (C) 1995-2010 Mark Adler
* Copyright (C) 1995-2017 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -9,7 +9,7 @@
#define MAXBITS 15
const char inflate_copyright[] =
" inflate 1.2.5 Copyright 1995-2010 Mark Adler ";
" inflate 1.2.11 Copyright 1995-2017 Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
@ -54,7 +54,7 @@ unsigned short FAR *work;
code FAR *next; /* next available space in table */
const unsigned short FAR *base; /* base value table to use */
const unsigned short FAR *extra; /* extra bits table to use */
int end; /* use base and extra for symbol > end */
unsigned match; /* use base and extra for symbol >= match */
unsigned short count[MAXBITS+1]; /* number of codes of each length */
unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
@ -62,7 +62,7 @@ unsigned short FAR *work;
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195};
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202};
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
@ -181,19 +181,17 @@ unsigned short FAR *work;
switch (type) {
case CODES:
base = extra = work; /* dummy value--not used */
end = 19;
match = 20;
break;
case LENS:
base = lbase;
base -= 257;
extra = lext;
extra -= 257;
end = 256;
match = 257;
break;
default: /* DISTS */
default: /* DISTS */
base = dbase;
extra = dext;
end = -1;
match = 0;
}
/* initialize state for loop */
@ -208,21 +206,21 @@ unsigned short FAR *work;
mask = used - 1; /* mask for comparing low */
/* check available table space */
if ((type == LENS && used >= ENOUGH_LENS) ||
(type == DISTS && used >= ENOUGH_DISTS))
if ((type == LENS && used > ENOUGH_LENS) ||
(type == DISTS && used > ENOUGH_DISTS))
return 1;
/* process all codes and make table entries */
for (;;) {
/* create table entry */
here.bits = (unsigned char)(len - drop);
if ((int)(work[sym]) < end) {
if (work[sym] + 1U < match) {
here.op = (unsigned char)0;
here.val = work[sym];
}
else if ((int)(work[sym]) > end) {
here.op = (unsigned char)(extra[work[sym]]);
here.val = base[work[sym]];
else if (work[sym] >= match) {
here.op = (unsigned char)(extra[work[sym] - match]);
here.val = base[work[sym] - match];
}
else {
here.op = (unsigned char)(32 + 64); /* end of block */
@ -277,8 +275,8 @@ unsigned short FAR *work;
/* check for enough space */
used += 1U << curr;
if ((type == LENS && used >= ENOUGH_LENS) ||
(type == DISTS && used >= ENOUGH_DISTS))
if ((type == LENS && used > ENOUGH_LENS) ||
(type == DISTS && used > ENOUGH_DISTS))
return 1;
/* point entry in root table to sub-table */
@ -289,38 +287,14 @@ unsigned short FAR *work;
}
}
/*
Fill in rest of table for incomplete codes. This loop is similar to the
loop above in incrementing huff for table indices. It is assumed that
len is equal to curr + drop, so there is no loop needed to increment
through high index bits. When the current sub-table is filled, the loop
drops back to the root table to fill in any remaining entries there.
*/
here.op = (unsigned char)64; /* invalid code marker */
here.bits = (unsigned char)(len - drop);
here.val = (unsigned short)0;
while (huff != 0) {
/* when done with sub-table, drop back to root table */
if (drop != 0 && (huff & mask) != low) {
drop = 0;
len = root;
next = *table;
here.bits = (unsigned char)len;
}
/* put invalid code marker in table */
next[huff >> drop] = here;
/* backwards increment the len-bit code huff */
incr = 1U << (len - 1);
while (huff & incr)
incr >>= 1;
if (incr != 0) {
huff &= incr - 1;
huff += incr;
}
else
huff = 0;
/* fill in remaining table entry if code is incomplete (guaranteed to have
at most one remaining entry, since if the code is incomplete, the
maximum code length that was allowed to get this far is one bit) */
if (huff != 0) {
here.op = (unsigned char)64; /* invalid code marker */
here.bits = (unsigned char)(len - drop);
here.val = (unsigned short)0;
next[huff] = here;
}
/* set return parameters */

View file

@ -1,5 +1,5 @@
/* trees.c -- output deflated data using Huffman coding
* Copyright (C) 1995-2010 Jean-loup Gailly
* Copyright (C) 1995-2017 Jean-loup Gailly
* detect_data_type() function provided freely by Cosmin Truta, 2006
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -36,7 +36,7 @@
#include "deflate.h"
#ifdef DEBUG
#ifdef ZLIB_DEBUG
# include <ctype.h>
#endif
@ -74,11 +74,6 @@ local const uch bl_order[BL_CODES]
* probability, to avoid transmitting the lengths for unused bit length codes.
*/
#define Buf_size (8 * 2*sizeof(char))
/* Number of bits used within bi_buf. (bi_buf might be implemented on
* more than 16 bits on some systems.)
*/
/* ===========================================================================
* Local data. These are initialized only once.
*/
@ -127,13 +122,13 @@ struct static_tree_desc_s {
int max_length; /* max bit length for the codes */
};
local static_tree_desc static_l_desc =
local const static_tree_desc static_l_desc =
{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
local static_tree_desc static_d_desc =
local const static_tree_desc static_d_desc =
{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
local static_tree_desc static_bl_desc =
local const static_tree_desc static_bl_desc =
{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
/* ===========================================================================
@ -151,24 +146,22 @@ local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
local int build_bl_tree OF((deflate_state *s));
local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
int blcodes));
local void compress_block OF((deflate_state *s, ct_data *ltree,
ct_data *dtree));
local void compress_block OF((deflate_state *s, const ct_data *ltree,
const ct_data *dtree));
local int detect_data_type OF((deflate_state *s));
local unsigned bi_reverse OF((unsigned value, int length));
local void bi_windup OF((deflate_state *s));
local void bi_flush OF((deflate_state *s));
local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
int header));
#ifdef GEN_TREES_H
local void gen_trees_header OF((void));
#endif
#ifndef DEBUG
#ifndef ZLIB_DEBUG
# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
/* Send a code of the given tree. c and tree must not have side effects */
#else /* DEBUG */
#else /* !ZLIB_DEBUG */
# define send_code(s, c, tree) \
{ if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
send_bits(s, tree[c].Code, tree[c].Len); }
@ -187,7 +180,7 @@ local void gen_trees_header OF((void));
* Send a value on a given number of bits.
* IN assertion: length <= 16 and value fits in length bits.
*/
#ifdef DEBUG
#ifdef ZLIB_DEBUG
local void send_bits OF((deflate_state *s, int value, int length));
local void send_bits(s, value, length)
@ -213,12 +206,12 @@ local void send_bits(s, value, length)
s->bi_valid += length;
}
}
#else /* !DEBUG */
#else /* !ZLIB_DEBUG */
#define send_bits(s, value, length) \
{ int len = length;\
if (s->bi_valid > (int)Buf_size - len) {\
int val = value;\
int val = (int)value;\
s->bi_buf |= (ush)val << s->bi_valid;\
put_short(s, s->bi_buf);\
s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
@ -228,7 +221,7 @@ local void send_bits(s, value, length)
s->bi_valid += len;\
}\
}
#endif /* DEBUG */
#endif /* ZLIB_DEBUG */
/* the arguments must not have side effects */
@ -322,7 +315,7 @@ local void tr_static_init()
* Genererate the file trees.h describing the static trees.
*/
#ifdef GEN_TREES_H
# ifndef DEBUG
# ifndef ZLIB_DEBUG
# include <stdio.h>
# endif
@ -399,8 +392,7 @@ void ZLIB_INTERNAL _tr_init(s)
s->bi_buf = 0;
s->bi_valid = 0;
s->last_eob_len = 8; /* enough lookahead for inflate */
#ifdef DEBUG
#ifdef ZLIB_DEBUG
s->compressed_len = 0L;
s->bits_sent = 0L;
#endif
@ -528,12 +520,12 @@ local void gen_bitlen(s, desc)
xbits = 0;
if (n >= base) xbits = extra[n-base];
f = tree[n].Freq;
s->opt_len += (ulg)f * (bits + xbits);
if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
s->opt_len += (ulg)f * (unsigned)(bits + xbits);
if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);
}
if (overflow == 0) return;
Trace((stderr,"\nbit length overflow\n"));
Tracev((stderr,"\nbit length overflow\n"));
/* This happens for example on obj2 and pic of the Calgary corpus */
/* Find the first bit length which could increase: */
@ -560,9 +552,8 @@ local void gen_bitlen(s, desc)
m = s->heap[--h];
if (m > max_code) continue;
if ((unsigned) tree[m].Len != (unsigned) bits) {
Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
s->opt_len += ((long)bits - (long)tree[m].Len)
*(long)tree[m].Freq;
Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq;
tree[m].Len = (ush)bits;
}
n--;
@ -584,7 +575,7 @@ local void gen_codes (tree, max_code, bl_count)
ushf *bl_count; /* number of codes at each bit length */
{
ush next_code[MAX_BITS+1]; /* next code value for each bit length */
ush code = 0; /* running code value */
unsigned code = 0; /* running code value */
int bits; /* bit index */
int n; /* code index */
@ -592,7 +583,8 @@ local void gen_codes (tree, max_code, bl_count)
* without bit reversal.
*/
for (bits = 1; bits <= MAX_BITS; bits++) {
next_code[bits] = code = (code + bl_count[bits-1]) << 1;
code = (code + bl_count[bits-1]) << 1;
next_code[bits] = (ush)code;
}
/* Check that the bit counts in bl_count are consistent. The last code
* must be all ones.
@ -605,7 +597,7 @@ local void gen_codes (tree, max_code, bl_count)
int len = tree[n].Len;
if (len == 0) continue;
/* Now reverse the bits */
tree[n].Code = bi_reverse(next_code[len]++, len);
tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
@ -827,7 +819,7 @@ local int build_bl_tree(s)
if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
}
/* Update opt_len to include the bit length tree and counts */
s->opt_len += 3*(max_blindex+1) + 5+5+4;
s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4;
Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
s->opt_len, s->static_len));
@ -875,52 +867,46 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
int last; /* one if this is the last block for a file */
{
send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */
#ifdef DEBUG
bi_windup(s); /* align on byte boundary */
put_short(s, (ush)stored_len);
put_short(s, (ush)~stored_len);
zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);
s->pending += stored_len;
#ifdef ZLIB_DEBUG
s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
s->compressed_len += (stored_len + 4) << 3;
s->bits_sent += 2*16;
s->bits_sent += stored_len<<3;
#endif
copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
}
/* ===========================================================================
* Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
*/
void ZLIB_INTERNAL _tr_flush_bits(s)
deflate_state *s;
{
bi_flush(s);
}
/* ===========================================================================
* Send one empty static block to give enough lookahead for inflate.
* This takes 10 bits, of which 7 may remain in the bit buffer.
* The current inflate code requires 9 bits of lookahead. If the
* last two codes for the previous block (real code plus EOB) were coded
* on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
* the last real code. In this case we send two empty static blocks instead
* of one. (There are no problems if the previous block is stored or fixed.)
* To simplify the code, we assume the worst case of last real code encoded
* on one bit only.
*/
void ZLIB_INTERNAL _tr_align(s)
deflate_state *s;
{
send_bits(s, STATIC_TREES<<1, 3);
send_code(s, END_BLOCK, static_ltree);
#ifdef DEBUG
#ifdef ZLIB_DEBUG
s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
#endif
bi_flush(s);
/* Of the 10 bits for the empty block, we have already sent
* (10 - bi_valid) bits. The lookahead for the last real code (before
* the EOB of the previous block) was thus at least one plus the length
* of the EOB plus what we have just sent of the empty static block.
*/
if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
send_bits(s, STATIC_TREES<<1, 3);
send_code(s, END_BLOCK, static_ltree);
#ifdef DEBUG
s->compressed_len += 10L;
#endif
bi_flush(s);
}
s->last_eob_len = 7;
}
/* ===========================================================================
* Determine the best encoding for the current block: dynamic trees, static
* trees or store, and output the encoded block to the zip file.
* trees or store, and write out the encoded block.
*/
void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
deflate_state *s;
@ -990,16 +976,18 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
} else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
#endif
send_bits(s, (STATIC_TREES<<1)+last, 3);
compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
#ifdef DEBUG
compress_block(s, (const ct_data *)static_ltree,
(const ct_data *)static_dtree);
#ifdef ZLIB_DEBUG
s->compressed_len += 3 + s->static_len;
#endif
} else {
send_bits(s, (DYN_TREES<<1)+last, 3);
send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
max_blindex+1);
compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
#ifdef DEBUG
compress_block(s, (const ct_data *)s->dyn_ltree,
(const ct_data *)s->dyn_dtree);
#ifdef ZLIB_DEBUG
s->compressed_len += 3 + s->opt_len;
#endif
}
@ -1011,7 +999,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
if (last) {
bi_windup(s);
#ifdef DEBUG
#ifdef ZLIB_DEBUG
s->compressed_len += 7; /* align on byte boundary */
#endif
}
@ -1075,8 +1063,8 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
*/
local void compress_block(s, ltree, dtree)
deflate_state *s;
ct_data *ltree; /* literal tree */
ct_data *dtree; /* distance tree */
const ct_data *ltree; /* literal tree */
const ct_data *dtree; /* distance tree */
{
unsigned dist; /* distance of matched string */
int lc; /* match length or unmatched char (if dist == 0) */
@ -1106,7 +1094,7 @@ local void compress_block(s, ltree, dtree)
send_code(s, code, dtree); /* send the distance code */
extra = extra_dbits[code];
if (extra != 0) {
dist -= base_dist[code];
dist -= (unsigned)base_dist[code];
send_bits(s, dist, extra); /* send the extra distance bits */
}
} /* literal or match pair ? */
@ -1118,7 +1106,6 @@ local void compress_block(s, ltree, dtree)
} while (lx < s->last_lit);
send_code(s, END_BLOCK, ltree);
s->last_eob_len = ltree[END_BLOCK].Len;
}
/* ===========================================================================
@ -1210,35 +1197,7 @@ local void bi_windup(s)
}
s->bi_buf = 0;
s->bi_valid = 0;
#ifdef DEBUG
#ifdef ZLIB_DEBUG
s->bits_sent = (s->bits_sent+7) & ~7;
#endif
}
/* ===========================================================================
* Copy a stored block, storing first the length and its
* one's complement if requested.
*/
local void copy_block(s, buf, len, header)
deflate_state *s;
charf *buf; /* the input data */
unsigned len; /* its length */
int header; /* true if block header must be written */
{
bi_windup(s); /* align on byte boundary */
s->last_eob_len = 8; /* enough lookahead for inflate */
if (header) {
put_short(s, (ush)len);
put_short(s, (ush)~len);
#ifdef DEBUG
s->bits_sent += 2*16;
#endif
}
#ifdef DEBUG
s->bits_sent += (ulg)len<<3;
#endif
while (len--) {
put_byte(s, *buf++);
}
}

View file

@ -1,5 +1,5 @@
/* uncompr.c -- decompress a memory buffer
* Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
* Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -9,51 +9,85 @@
#include "zlib.h"
/* ===========================================================================
Decompresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total
size of the destination buffer, which must be large enough to hold the
entire uncompressed data. (The size of the uncompressed data must have
been saved previously by the compressor and transmitted to the decompressor
by some mechanism outside the scope of this compression library.)
Upon exit, destLen is the actual size of the compressed buffer.
Decompresses the source buffer into the destination buffer. *sourceLen is
the byte length of the source buffer. Upon entry, *destLen is the total size
of the destination buffer, which must be large enough to hold the entire
uncompressed data. (The size of the uncompressed data must have been saved
previously by the compressor and transmitted to the decompressor by some
mechanism outside the scope of this compression library.) Upon exit,
*destLen is the size of the decompressed data and *sourceLen is the number
of source bytes consumed. Upon return, source + *sourceLen points to the
first unused input byte.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
buffer, or Z_DATA_ERROR if the input data was corrupted.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
Z_DATA_ERROR if the input data was corrupted, including if the input data is
an incomplete zlib stream.
*/
int ZEXPORT uncompress2 (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong *sourceLen;
{
z_stream stream;
int err;
const uInt max = (uInt)-1;
uLong len, left;
Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */
len = *sourceLen;
if (*destLen) {
left = *destLen;
*destLen = 0;
}
else {
left = 1;
dest = buf;
}
stream.next_in = (z_const Bytef *)source;
stream.avail_in = 0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = inflateInit(&stream);
if (err != Z_OK) return err;
stream.next_out = dest;
stream.avail_out = 0;
do {
if (stream.avail_out == 0) {
stream.avail_out = left > (uLong)max ? max : (uInt)left;
left -= stream.avail_out;
}
if (stream.avail_in == 0) {
stream.avail_in = len > (uLong)max ? max : (uInt)len;
len -= stream.avail_in;
}
err = inflate(&stream, Z_NO_FLUSH);
} while (err == Z_OK);
*sourceLen -= len + stream.avail_in;
if (dest != buf)
*destLen = stream.total_out;
else if (stream.total_out && err == Z_BUF_ERROR)
left = 1;
inflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK :
err == Z_NEED_DICT ? Z_DATA_ERROR :
err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
err;
}
int ZEXPORT uncompress (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
{
z_stream stream;
int err;
stream.next_in = (Bytef*)source;
stream.avail_in = (uInt)sourceLen;
/* Check for source > 64K on 16-bit machine: */
if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
stream.next_out = dest;
stream.avail_out = (uInt)*destLen;
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
err = inflateInit(&stream);
if (err != Z_OK) return err;
err = inflate(&stream, Z_FINISH);
if (err != Z_STREAM_END) {
inflateEnd(&stream);
if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
return Z_DATA_ERROR;
return err;
}
*destLen = stream.total_out;
err = inflateEnd(&stream);
return err;
return uncompress2(dest, destLen, source, &sourceLen);
}

View file

@ -1,5 +1,5 @@
/* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995-2010 Jean-loup Gailly.
* Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -15,11 +15,13 @@
* this permanently in zconf.h using "./configure --zprefix".
*/
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
# define Z_PREFIX_SET
/* all linked symbols */
/* all linked symbols and init macros */
# define _dist_code z__dist_code
# define _length_code z__length_code
# define _tr_align z__tr_align
# define _tr_flush_bits z__tr_flush_bits
# define _tr_flush_block z__tr_flush_block
# define _tr_init z__tr_init
# define _tr_stored_block z__tr_stored_block
@ -27,81 +29,111 @@
# define adler32 z_adler32
# define adler32_combine z_adler32_combine
# define adler32_combine64 z_adler32_combine64
# define compress z_compress
# define compress2 z_compress2
# define compressBound z_compressBound
# define adler32_z z_adler32_z
# ifndef Z_SOLO
# define compress z_compress
# define compress2 z_compress2
# define compressBound z_compressBound
# endif
# define crc32 z_crc32
# define crc32_combine z_crc32_combine
# define crc32_combine64 z_crc32_combine64
# define crc32_z z_crc32_z
# define deflate z_deflate
# define deflateBound z_deflateBound
# define deflateCopy z_deflateCopy
# define deflateEnd z_deflateEnd
# define deflateGetDictionary z_deflateGetDictionary
# define deflateInit z_deflateInit
# define deflateInit2 z_deflateInit2
# define deflateInit2_ z_deflateInit2_
# define deflateInit_ z_deflateInit_
# define deflateParams z_deflateParams
# define deflatePending z_deflatePending
# define deflatePrime z_deflatePrime
# define deflateReset z_deflateReset
# define deflateResetKeep z_deflateResetKeep
# define deflateSetDictionary z_deflateSetDictionary
# define deflateSetHeader z_deflateSetHeader
# define deflateTune z_deflateTune
# define deflate_copyright z_deflate_copyright
# define get_crc_table z_get_crc_table
# define gz_error z_gz_error
# define gz_intmax z_gz_intmax
# define gz_strwinerror z_gz_strwinerror
# define gzbuffer z_gzbuffer
# define gzclearerr z_gzclearerr
# define gzclose z_gzclose
# define gzclose_r z_gzclose_r
# define gzclose_w z_gzclose_w
# define gzdirect z_gzdirect
# define gzdopen z_gzdopen
# define gzeof z_gzeof
# define gzerror z_gzerror
# define gzflush z_gzflush
# define gzgetc z_gzgetc
# define gzgets z_gzgets
# define gzoffset z_gzoffset
# define gzoffset64 z_gzoffset64
# define gzopen z_gzopen
# define gzopen64 z_gzopen64
# define gzprintf z_gzprintf
# define gzputc z_gzputc
# define gzputs z_gzputs
# define gzread z_gzread
# define gzrewind z_gzrewind
# define gzseek z_gzseek
# define gzseek64 z_gzseek64
# define gzsetparams z_gzsetparams
# define gztell z_gztell
# define gztell64 z_gztell64
# define gzungetc z_gzungetc
# define gzwrite z_gzwrite
# ifndef Z_SOLO
# define gz_error z_gz_error
# define gz_intmax z_gz_intmax
# define gz_strwinerror z_gz_strwinerror
# define gzbuffer z_gzbuffer
# define gzclearerr z_gzclearerr
# define gzclose z_gzclose
# define gzclose_r z_gzclose_r
# define gzclose_w z_gzclose_w
# define gzdirect z_gzdirect
# define gzdopen z_gzdopen
# define gzeof z_gzeof
# define gzerror z_gzerror
# define gzflush z_gzflush
# define gzfread z_gzfread
# define gzfwrite z_gzfwrite
# define gzgetc z_gzgetc
# define gzgetc_ z_gzgetc_
# define gzgets z_gzgets
# define gzoffset z_gzoffset
# define gzoffset64 z_gzoffset64
# define gzopen z_gzopen
# define gzopen64 z_gzopen64
# ifdef _WIN32
# define gzopen_w z_gzopen_w
# endif
# define gzprintf z_gzprintf
# define gzputc z_gzputc
# define gzputs z_gzputs
# define gzread z_gzread
# define gzrewind z_gzrewind
# define gzseek z_gzseek
# define gzseek64 z_gzseek64
# define gzsetparams z_gzsetparams
# define gztell z_gztell
# define gztell64 z_gztell64
# define gzungetc z_gzungetc
# define gzvprintf z_gzvprintf
# define gzwrite z_gzwrite
# endif
# define inflate z_inflate
# define inflateBack z_inflateBack
# define inflateBackEnd z_inflateBackEnd
# define inflateBackInit z_inflateBackInit
# define inflateBackInit_ z_inflateBackInit_
# define inflateCodesUsed z_inflateCodesUsed
# define inflateCopy z_inflateCopy
# define inflateEnd z_inflateEnd
# define inflateGetDictionary z_inflateGetDictionary
# define inflateGetHeader z_inflateGetHeader
# define inflateInit z_inflateInit
# define inflateInit2 z_inflateInit2
# define inflateInit2_ z_inflateInit2_
# define inflateInit_ z_inflateInit_
# define inflateMark z_inflateMark
# define inflatePrime z_inflatePrime
# define inflateReset z_inflateReset
# define inflateReset2 z_inflateReset2
# define inflateResetKeep z_inflateResetKeep
# define inflateSetDictionary z_inflateSetDictionary
# define inflateSync z_inflateSync
# define inflateSyncPoint z_inflateSyncPoint
# define inflateUndermine z_inflateUndermine
# define inflateValidate z_inflateValidate
# define inflate_copyright z_inflate_copyright
# define inflate_fast z_inflate_fast
# define inflate_table z_inflate_table
# define uncompress z_uncompress
# ifndef Z_SOLO
# define uncompress z_uncompress
# define uncompress2 z_uncompress2
# endif
# define zError z_zError
# define zcalloc z_zcalloc
# define zcfree z_zcfree
# ifndef Z_SOLO
# define zcalloc z_zcalloc
# define zcfree z_zcfree
# endif
# define zlibCompileFlags z_zlibCompileFlags
# define zlibVersion z_zlibVersion
@ -111,7 +143,9 @@
# define alloc_func z_alloc_func
# define charf z_charf
# define free_func z_free_func
# define gzFile z_gzFile
# ifndef Z_SOLO
# define gzFile z_gzFile
# endif
# define gz_header z_gz_header
# define gz_headerp z_gz_headerp
# define in_func z_in_func
@ -197,9 +231,25 @@
# endif
#endif
/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
# define NO_DUMMY_DECL
#if defined(ZLIB_CONST) && !defined(z_const)
# define z_const const
#else
# define z_const
#endif
#ifdef Z_SOLO
typedef unsigned long z_size_t;
#else
# define z_longlong long long
# if defined(NO_SIZE_T)
typedef unsigned NO_SIZE_T z_size_t;
# elif defined(STDC)
# include <stddef.h>
typedef size_t z_size_t;
# else
typedef unsigned long z_size_t;
# endif
# undef z_longlong
#endif
/* Maximum value for memLevel in deflateInit2 */
@ -229,7 +279,7 @@
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus a few kilobytes
that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
for small objects.
*/
@ -243,6 +293,14 @@
# endif
#endif
#ifndef Z_ARG /* function prototypes for stdarg */
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
# define Z_ARG(args) args
# else
# define Z_ARG(args) ()
# endif
#endif
/* The following definitions for FAR are needed only for MSDOS mixed
* model programming (small or medium model with some far allocations).
* This was tested only with MSC; for other MSDOS compilers you may have
@ -356,12 +414,47 @@ typedef uLong FAR uLongf;
typedef Byte *voidp;
#endif
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
# include <limits.h>
# if (UINT_MAX == 0xffffffffUL)
# define Z_U4 unsigned
# elif (ULONG_MAX == 0xffffffffUL)
# define Z_U4 unsigned long
# elif (USHRT_MAX == 0xffffffffUL)
# define Z_U4 unsigned short
# endif
#endif
#ifdef Z_U4
typedef Z_U4 z_crc_t;
#else
typedef unsigned long z_crc_t;
#endif
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
# define Z_HAVE_UNISTD_H
#endif
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
# define Z_HAVE_STDARG_H
#endif
#ifdef STDC
# include <sys/types.h> /* for off_t */
# ifndef Z_SOLO
# include <sys/types.h> /* for off_t */
# endif
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifndef Z_SOLO
# include <stdarg.h> /* for va_list */
# endif
#endif
#ifdef _WIN32
# ifndef Z_SOLO
# include <stddef.h> /* for wchar_t */
# endif
#endif
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
@ -370,21 +463,38 @@ typedef uLong FAR uLongf;
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
* equivalently requesting no 64-bit operations
*/
#if -_LARGEFILE64_SOURCE - -1 == 1
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
# undef _LARGEFILE64_SOURCE
#endif
#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
# include <unistd.h> /* for SEEK_* and off_t */
# ifdef VMS
# include <unixio.h> /* for off_t */
# endif
# ifndef z_off_t
# define z_off_t off_t
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
# define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
# ifdef VMS
# include <unixio.h> /* for off_t */
# endif
# ifndef z_off_t
# define z_off_t off_t
# endif
# endif
#endif
#ifndef SEEK_SET
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
# define Z_LFS64
#endif
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
# define Z_LARGE64
#endif
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
# define Z_WANT64
#endif
#if !defined(SEEK_SET) && !defined(Z_SOLO)
# define SEEK_SET 0 /* Seek from beginning of file. */
# define SEEK_CUR 1 /* Seek from current position. */
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
@ -394,18 +504,14 @@ typedef uLong FAR uLongf;
# define z_off_t long
#endif
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
#if !defined(_WIN32) && defined(Z_LARGE64)
# define z_off64_t off64_t
#else
# define z_off64_t z_off_t
#endif
#if defined(__OS400__)
# define NO_vsnprintf
#endif
#if defined(__MVS__)
# define NO_vsnprintf
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
# define z_off64_t __int64
# else
# define z_off64_t z_off_t
# endif
#endif
/* MVS linker does not support external names larger than 8 bytes */

File diff suppressed because it is too large Load diff

View file

@ -1,27 +1,27 @@
/* zutil.c -- target dependent utility functions for the compression library
* Copyright (C) 1995-2005, 2010 Jean-loup Gailly.
* Copyright (C) 1995-2017 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "zutil.h"
#ifndef NO_DUMMY_DECL
struct internal_state {int dummy;}; /* for buggy compilers */
#ifndef Z_SOLO
# include "gzguts.h"
#endif
const char * const z_errmsg[10] = {
"need dictionary", /* Z_NEED_DICT 2 */
"stream end", /* Z_STREAM_END 1 */
"", /* Z_OK 0 */
"file error", /* Z_ERRNO (-1) */
"stream error", /* Z_STREAM_ERROR (-2) */
"data error", /* Z_DATA_ERROR (-3) */
"insufficient memory", /* Z_MEM_ERROR (-4) */
"buffer error", /* Z_BUF_ERROR (-5) */
"incompatible version",/* Z_VERSION_ERROR (-6) */
""};
z_const char * const z_errmsg[10] = {
(z_const char *)"need dictionary", /* Z_NEED_DICT 2 */
(z_const char *)"stream end", /* Z_STREAM_END 1 */
(z_const char *)"", /* Z_OK 0 */
(z_const char *)"file error", /* Z_ERRNO (-1) */
(z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */
(z_const char *)"data error", /* Z_DATA_ERROR (-3) */
(z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */
(z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */
(z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */
(z_const char *)""
};
const char * ZEXPORT zlibVersion()
@ -58,7 +58,7 @@ uLong ZEXPORT zlibCompileFlags()
case 8: flags += 2 << 6; break;
default: flags += 3 << 6;
}
#ifdef DEBUG
#ifdef ZLIB_DEBUG
flags += 1 << 8;
#endif
#if defined(ASMV) || defined(ASMINF)
@ -85,35 +85,35 @@ uLong ZEXPORT zlibCompileFlags()
#ifdef FASTEST
flags += 1L << 21;
#endif
#ifdef STDC
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifdef NO_vsnprintf
flags += 1L << 25;
flags += 1L << 25;
# ifdef HAS_vsprintf_void
flags += 1L << 26;
flags += 1L << 26;
# endif
# else
# ifdef HAS_vsnprintf_void
flags += 1L << 26;
flags += 1L << 26;
# endif
# endif
#else
flags += 1L << 24;
flags += 1L << 24;
# ifdef NO_snprintf
flags += 1L << 25;
flags += 1L << 25;
# ifdef HAS_sprintf_void
flags += 1L << 26;
flags += 1L << 26;
# endif
# else
# ifdef HAS_snprintf_void
flags += 1L << 26;
flags += 1L << 26;
# endif
# endif
#endif
return flags;
}
#ifdef DEBUG
#ifdef ZLIB_DEBUG
#include <stdlib.h>
# ifndef verbose
# define verbose 0
# endif
@ -181,6 +181,7 @@ void ZLIB_INTERNAL zmemzero(dest, len)
}
#endif
#ifndef Z_SOLO
#ifdef SYS16BIT
@ -215,9 +216,11 @@ local ptr_table table[MAX_PTR];
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
{
voidpf buf = opaque; /* just to make some compilers happy */
voidpf buf;
ulg bsize = (ulg)items*size;
(void)opaque;
/* If we allocate less than 65520 bytes, we assume that farmalloc
* will return a usable pointer which doesn't have to be normalized.
*/
@ -240,6 +243,9 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
{
int n;
(void)opaque;
if (*(ush*)&ptr != 0) { /* object < 64K */
farfree(ptr);
return;
@ -255,7 +261,6 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
next_ptr--;
return;
}
ptr = opaque; /* just to make some compilers happy */
Assert(0, "zcfree: ptr not found");
}
@ -274,13 +279,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
{
if (opaque) opaque = 0; /* to make compiler happy */
(void)opaque;
return _halloc((long)items, size);
}
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
{
if (opaque) opaque = 0; /* to make compiler happy */
(void)opaque;
_hfree(ptr);
}
@ -302,7 +307,7 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
unsigned items;
unsigned size;
{
if (opaque) items += size - size; /* make compiler happy */
(void)opaque;
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
(voidpf)calloc(items, size);
}
@ -311,8 +316,10 @@ void ZLIB_INTERNAL zcfree (opaque, ptr)
voidpf opaque;
voidpf ptr;
{
(void)opaque;
free(ptr);
if (opaque) return; /* make compiler happy */
}
#endif /* MY_ZCALLOC */
#endif /* !Z_SOLO */

View file

@ -1,5 +1,5 @@
/* zutil.h -- internal interface and configuration of the compression library
* Copyright (C) 1995-2010 Jean-loup Gailly.
* Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@ -13,7 +13,7 @@
#ifndef ZUTIL_H
#define ZUTIL_H
#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ)
#ifdef HAVE_HIDDEN
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
# define ZLIB_INTERNAL
@ -21,7 +21,7 @@
#include "zlib.h"
#ifdef STDC
#if defined(STDC) && !defined(Z_SOLO)
# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
# include <stddef.h>
# endif
@ -29,10 +29,16 @@
# include <stdlib.h>
#endif
#ifdef Z_SOLO
typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
/* since "static" is used to mean two completely different things in C, we
define "local" for the non-static meaning of "static", for readability
(compile with -Dlocal if your debugger can't find static symbols) */
typedef unsigned char uch;
typedef uch FAR uchf;
@ -40,13 +46,13 @@ typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long ulg;
extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* (size given to avoid silly warnings with Visual C++) */
#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
#define ERR_RETURN(strm,err) \
return (strm->msg = (char*)ERR_MSG(err), (err))
return (strm->msg = ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */
/* common constants */
@ -78,63 +84,83 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
# define OS_CODE 0x00
# if defined(__TURBOC__) || defined(__BORLANDC__)
# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
/* Allow compilation with ANSI keywords only enabled */
void _Cdecl farfree( void *block );
void *_Cdecl farmalloc( unsigned long nbytes );
# else
# include <alloc.h>
# ifndef Z_SOLO
# if defined(__TURBOC__) || defined(__BORLANDC__)
# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
/* Allow compilation with ANSI keywords only enabled */
void _Cdecl farfree( void *block );
void *_Cdecl farmalloc( unsigned long nbytes );
# else
# include <alloc.h>
# endif
# else /* MSC or DJGPP */
# include <malloc.h>
# endif
# else /* MSC or DJGPP */
# include <malloc.h>
# endif
#endif
#ifdef AMIGA
# define OS_CODE 0x01
# define OS_CODE 1
#endif
#if defined(VAXC) || defined(VMS)
# define OS_CODE 0x02
# define OS_CODE 2
# define F_OPEN(name, mode) \
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif
#ifdef __370__
# if __TARGET_LIB__ < 0x20000000
# define OS_CODE 4
# elif __TARGET_LIB__ < 0x40000000
# define OS_CODE 11
# else
# define OS_CODE 8
# endif
#endif
#if defined(ATARI) || defined(atarist)
# define OS_CODE 0x05
# define OS_CODE 5
#endif
#ifdef OS2
# define OS_CODE 0x06
# ifdef M_I86
# define OS_CODE 6
# if defined(M_I86) && !defined(Z_SOLO)
# include <malloc.h>
# endif
#endif
#if defined(MACOS) || defined(TARGET_OS_MAC)
# define OS_CODE 0x07
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
# include <unix.h> /* for fdopen */
# else
# ifndef fdopen
# define fdopen(fd,mode) NULL /* No fdopen() */
# define OS_CODE 7
# ifndef Z_SOLO
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
# include <unix.h> /* for fdopen */
# else
# ifndef fdopen
# define fdopen(fd,mode) NULL /* No fdopen() */
# endif
# endif
# endif
#endif
#ifdef TOPS20
# define OS_CODE 0x0a
#ifdef __acorn
# define OS_CODE 13
#endif
#ifdef WIN32
# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
# define OS_CODE 0x0b
# endif
#if defined(WIN32) && !defined(__CYGWIN__)
# define OS_CODE 10
#endif
#ifdef __50SERIES /* Prime/PRIMOS */
# define OS_CODE 0x0f
#ifdef _BEOS_
# define OS_CODE 16
#endif
#ifdef __TOS_OS400__
# define OS_CODE 18
#endif
#ifdef __APPLE__
# define OS_CODE 19
#endif
#if defined(_BEOS_) || defined(RISCOS)
@ -153,14 +179,15 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# endif
#endif
#if defined(__BORLANDC__)
#if defined(__BORLANDC__) && !defined(MSDOS)
#pragma warn -8004
#pragma warn -8008
#pragma warn -8066
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
#if !defined(_WIN32) && \
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
#endif
@ -168,7 +195,7 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* common defaults */
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
# define OS_CODE 3 /* assume Unix */
#endif
#ifndef F_OPEN
@ -177,42 +204,7 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* functions */
#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(__CYGWIN__)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#ifndef HAVE_VSNPRINTF
# ifdef MSDOS
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
but for now we just assume it doesn't. */
# define NO_vsnprintf
# endif
# ifdef __TURBOC__
# define NO_vsnprintf
# endif
# ifdef WIN32
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
# if !defined(vsnprintf) && !defined(NO_vsnprintf)
# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
# define vsnprintf _vsnprintf
# endif
# endif
# endif
# ifdef __SASC
# define NO_vsnprintf
# endif
#endif
#ifdef VMS
# define NO_vsnprintf
#endif
#if defined(pyr)
#if defined(pyr) || defined(Z_SOLO)
# define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
@ -242,7 +234,7 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#endif
/* Diagnostic functions */
#ifdef DEBUG
#ifdef ZLIB_DEBUG
# include <stdio.h>
extern int ZLIB_INTERNAL z_verbose;
extern void ZLIB_INTERNAL z_error OF((char *m));
@ -261,14 +253,19 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# define Tracecv(c,x)
#endif
voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
unsigned size));
void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
#ifndef Z_SOLO
voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
unsigned size));
void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
#endif
#define ZALLOC(strm, items, size) \
(*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
/* Reverse the bytes in a 32-bit value */
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
(((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
#endif /* ZUTIL_H */

View file

@ -69,6 +69,7 @@ public:
TEXLOAD_NOMIPMAPS = 2,
TEXLOAD_ARRAY_256 = 4,
TEXLOAD_MULTI_DIMENSION = 8,
TEXLOAD_LINEARMIPMAPS = 16,
};
/* Constants: Wrap Modes */

View file

@ -266,6 +266,7 @@ int CRegister::RegisterProcessPacket(CNetChunk *pPacket, TOKEN Token)
if(m_RegisterFirst && m_RegisterState != REGISTERSTATE_REGISTERED)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "register", "no firewall/nat problems detected");
RegisterNewState(REGISTERSTATE_REGISTERED);
m_pNetServer->AddToken(&pPacket->m_Address, Token);
return 1;
}
else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWERROR) &&

View file

@ -886,6 +886,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
{
CClient::CInput *pInput;
int64 TagTime;
int64 Now = time_get();
m_aClients[ClientID].m_LastAckedSnapshot = Unpacker.GetInt();
int IntendedTick = Unpacker.GetInt();
@ -898,14 +899,11 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
if(m_aClients[ClientID].m_LastAckedSnapshot > 0)
m_aClients[ClientID].m_SnapRate = CClient::SNAPRATE_FULL;
if(m_aClients[ClientID].m_Snapshots.Get(m_aClients[ClientID].m_LastAckedSnapshot, &TagTime, 0, 0) >= 0)
m_aClients[ClientID].m_Latency = (int)(((time_get()-TagTime)*1000)/time_freq());
// add message to report the input timing
// skip packets that are old
if(IntendedTick > m_aClients[ClientID].m_LastInputTick)
{
int TimeLeft = ((TickStartTime(IntendedTick)-time_get())*1000) / time_freq();
int TimeLeft = ((TickStartTime(IntendedTick)-Now)*1000) / time_freq();
CMsgPacker Msg(NETMSG_INPUTTIMING, true);
Msg.AddInt(IntendedTick);
@ -925,6 +923,13 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
for(int i = 0; i < Size/4; i++)
pInput->m_aData[i] = Unpacker.GetInt();
int PingCorrection = clamp(Unpacker.GetInt(), 0, 50);
if(m_aClients[ClientID].m_Snapshots.Get(m_aClients[ClientID].m_LastAckedSnapshot, &TagTime, 0, 0) >= 0)
{
m_aClients[ClientID].m_Latency = (int)(((Now-TagTime)*1000)/time_freq());
m_aClients[ClientID].m_Latency = max(0, m_aClients[ClientID].m_Latency - PingCorrection);
}
mem_copy(m_aClients[ClientID].m_LatestInput.m_aData, pInput->m_aData, MAX_INPUT_SIZE*sizeof(int));
m_aClients[ClientID].m_CurrentInput++;
@ -1095,7 +1100,7 @@ void CServer::GenerateServerInfo(CPacker *pPacker, int Token)
pPacker->AddString(ClientClan(i), MAX_CLAN_LENGTH); // client clan
pPacker->AddInt(m_aClients[i].m_Country); // client country
pPacker->AddInt(m_aClients[i].m_Score); // client score
pPacker->AddInt(GameServer()->IsClientPlayer(i)?1:0); // is player?
pPacker->AddInt(GameServer()->IsClientPlayer(i)?0:1); // flag spectator=1, bot=2 (player=0)
}
}
}

View file

@ -23,9 +23,16 @@ public:
char m_aClan[MAX_CLAN_LENGTH];
int m_Country;
int m_Score;
bool m_Player;
int m_PlayerType;
int m_FriendState;
enum
{
PLAYERFLAG_SPEC=1,
PLAYERFLAG_BOT=2,
PLAYERFLAG_MASK=3,
};
};
//int m_SortedIndex;
@ -40,6 +47,8 @@ public:
int m_NumClients;
int m_MaxPlayers;
int m_NumPlayers;
int m_NumBotPlayers;
int m_NumBotSpectators;
int m_Flags;
int m_ServerLevel;
int m_Favorite;
@ -56,10 +65,15 @@ public:
class CServerFilterInfo
{
public:
enum
{
MAX_GAMETYPES=8,
};
int m_SortHash;
int m_Ping;
int m_Country;
char m_aGametype[16];
int m_ServerLevel;
char m_aGametype[MAX_GAMETYPES][16];
char m_aAddress[NETADDR_MAXSTRSIZE];
};
@ -97,6 +111,7 @@ public:
FLAG_PURE=2,
FLAG_PUREMAP=4,
FILTER_BOTS=16,
FILTER_EMPTY=32,
FILTER_FULL=64,
FILTER_SPECTATORS=128,
@ -106,9 +121,8 @@ public:
FILTER_COMPAT_VERSION=2048,
FILTER_PURE=4096,
FILTER_PURE_MAP=8192,
FILTER_GAMETYPE_STRICT=16384,
FILTER_COUNTRY=32768,
FILTER_PING=65536,
FILTER_COUNTRY= 16384,
FILTER_PING= 32768,
};
virtual void SetType(int Type) = 0;
@ -119,6 +133,8 @@ public:
virtual int NumServers() const = 0;
virtual int NumPlayers() const = 0;
virtual int NumClients() const = 0;
virtual const CServerInfo *Get(int Index) const = 0;
virtual int NumSortedServers(int Index) const = 0;
virtual int NumSortedPlayers(int Index) const = 0;

View file

@ -34,11 +34,11 @@ MACRO_CONFIG_INT(BrMaxRequests, br_max_requests, 25, 0, 1000, CFGFLAG_SAVE|CFGFL
MACRO_CONFIG_INT(SndBufferSize, snd_buffer_size, 512, 128, 32768, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound buffer size")
MACRO_CONFIG_INT(SndRate, snd_rate, 48000, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound mixing rate")
MACRO_CONFIG_INT(SndEnable, snd_enable, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound enable")
MACRO_CONFIG_INT(SndEnable, snd_enable, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Enable sounds")
MACRO_CONFIG_INT(SndInit, snd_init, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Initialize sound systems")
MACRO_CONFIG_INT(SndMusic, snd_enable_music, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Play background music")
MACRO_CONFIG_INT(SndVolume, snd_volume, 100, 0, 100, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound volume")
MACRO_CONFIG_INT(SndDevice, snd_device, -1, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "(deprecated) Sound device to use")
MACRO_CONFIG_INT(SndNonactiveMute, snd_nonactive_mute, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(GfxScreen, gfx_screen, 0, 0, 0, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Screen index")

View file

@ -97,14 +97,15 @@ void CNetBase::SendPacketConnless(NETSOCKET Socket, const NETADDR *pAddr, TOKEN
dbg_assert((ResponseToken&~NET_TOKEN_MASK) == 0, "resp token out of range");
int i = 0;
aBuffer[i++] = (Token>>12)&0xff; // token
aBuffer[i++] = (Token>>4)&0xff;
aBuffer[i++] = ((Token&0xf)<<4)
| (NET_PACKETFLAG_CONNLESS&0xf); // connless flag
aBuffer[i++] = ((NET_PACKETVERSION&0x0f)<<4) // version
| ((ResponseToken>>16)&0xf); // response token
aBuffer[i++] = ((NET_PACKETFLAG_CONNLESS<<2)&0xfc) | (NET_PACKETVERSION&0x03); // connless flag and version
aBuffer[i++] = (Token>>24)&0xff; // token
aBuffer[i++] = (Token>>16)&0xff;
aBuffer[i++] = (Token>>8)&0xff;
aBuffer[i++] = (Token)&0xff;
aBuffer[i++] = (ResponseToken>>24)&0xff; // response token
aBuffer[i++] = (ResponseToken>>16)&0xff;
aBuffer[i++] = (ResponseToken>>8)&0xff;
aBuffer[i++] = ResponseToken&0xff;
aBuffer[i++] = (ResponseToken)&0xff;
dbg_assert(i == NET_PACKETHEADERSIZE_CONNLESS, "inconsistency");
@ -154,13 +155,13 @@ void CNetBase::SendPacket(NETSOCKET Socket, const NETADDR *pAddr, CNetPacketCons
FinalSize += NET_PACKETHEADERSIZE;
int i = 0;
aBuffer[i++] = (pPacket->m_Token>>12)&0xff; // token
aBuffer[i++] = (pPacket->m_Token>>4)&0xff;
aBuffer[i++] = ((pPacket->m_Token<<4)&0xf0)
| ((pPacket->m_Flags)&0xf); // flags
aBuffer[i++] = (pPacket->m_Ack>>2)&0xff; // ack
aBuffer[i++] = ((pPacket->m_Ack<<6)&0xc0)
| (pPacket->m_NumChunks&0x3f);
aBuffer[i++] = ((pPacket->m_Flags<<2)&0xfc) | ((pPacket->m_Ack>>8)&0x03); // flags and ack
aBuffer[i++] = (pPacket->m_Ack)&0xff; // ack
aBuffer[i++] = (pPacket->m_NumChunks)&0xff; // num chunks
aBuffer[i++] = (pPacket->m_Token>>24)&0xff; // token
aBuffer[i++] = (pPacket->m_Token>>16)&0xff;
aBuffer[i++] = (pPacket->m_Token>>8)&0xff;
aBuffer[i++] = (pPacket->m_Token)&0xff;
dbg_assert(i == NET_PACKETHEADERSIZE, "inconsistency");
@ -200,11 +201,9 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
}
// read the packet
pPacket->m_Token = (pBuffer[0]<<12) | (pBuffer[1]<<4) | (pBuffer[2]>>4);
// TTTTTTTT TTTTTTTT TTTTxxxx
pPacket->m_Flags = pBuffer[2]&0x0f;
// xxxxFFFF
pPacket->m_Flags = (pBuffer[0]&0xfc)>>2;
// FFFFFFxx
if(pPacket->m_Flags&NET_PACKETFLAG_CONNLESS)
{
if(Size < NET_PACKETHEADERSIZE_CONNLESS)
@ -217,15 +216,17 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
pPacket->m_Flags = NET_PACKETFLAG_CONNLESS;
pPacket->m_Ack = 0;
pPacket->m_NumChunks = 0;
int Version = (pBuffer[3]>>4);
// VVVVxxxx
int Version = pBuffer[0]&0x3;
// xxxxxxVV
if(Version != NET_PACKETVERSION)
return -1;
pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE_CONNLESS;
pPacket->m_ResponseToken = ((pBuffer[3]&0x0f)<<16) | (pBuffer[4]<<8) | pBuffer[5];
// xxxxRRRR RRRRRRRR RRRRRRRR
pPacket->m_Token = (pBuffer[1] << 24) | (pBuffer[2] << 16) | (pBuffer[3] << 8) | pBuffer[4];
// TTTTTTTT TTTTTTTT TTTTTTTT TTTTTTTT
pPacket->m_ResponseToken = (pBuffer[5]<<24) | (pBuffer[6]<<16) | (pBuffer[7]<<8) | pBuffer[8];
// RRRRRRRR RRRRRRRR RRRRRRRR RRRRRRRR
mem_copy(pPacket->m_aChunkData, &pBuffer[NET_PACKETHEADERSIZE_CONNLESS], pPacket->m_DataSize);
}
else
@ -237,12 +238,14 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
return -1;
}
pPacket->m_Ack = (pBuffer[3]<<2) | ((pBuffer[4]&0xc0)>>6);
// AAAAAAAA AAxxxxxx
pPacket->m_NumChunks = pBuffer[4]&0x3f;
// xxNNNNNN
pPacket->m_Ack = ((pBuffer[0]&0x3)<<8) | pBuffer[1];
// xxxxxxAA AAAAAAAA
pPacket->m_NumChunks = pBuffer[2];
// NNNNNNNN
pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE;
pPacket->m_Token = (pBuffer[3] << 24) | (pBuffer[4] << 16) | (pBuffer[5] << 8) | pBuffer[6];
// TTTTTTTT TTTTTTTT TTTTTTTT TTTTTTTT
pPacket->m_ResponseToken = NET_TOKEN_NONE;
if(pPacket->m_Flags&NET_PACKETFLAG_COMPRESSION)
@ -262,13 +265,13 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
// set the response token (a bit hacky because this function shouldn't know about control packets)
if(pPacket->m_Flags&NET_PACKETFLAG_CONTROL)
{
if(pPacket->m_DataSize >= 4) // control byte + token
if(pPacket->m_DataSize >= 5) // control byte + token
{
if(pPacket->m_aChunkData[0] == NET_CTRLMSG_CONNECT
|| pPacket->m_aChunkData[0] == NET_CTRLMSG_TOKEN)
{
pPacket->m_ResponseToken = ((pPacket->m_aChunkData[1]&0xf)<<16)
| (pPacket->m_aChunkData[2]<<8) | pPacket->m_aChunkData[3];
pPacket->m_ResponseToken = (pPacket->m_aChunkData[1]<<24) | (pPacket->m_aChunkData[2]<<16)
| (pPacket->m_aChunkData[3]<<8) | pPacket->m_aChunkData[4];
}
}
}
@ -304,17 +307,17 @@ void CNetBase::SendControlMsg(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Toke
}
void CNetBase::SendControlMsgWithToken(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken)
void CNetBase::SendControlMsgWithToken(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken, bool Extended)
{
dbg_assert((Token&~NET_TOKEN_MASK) == 0, "token out of range");
dbg_assert((MyToken&~NET_TOKEN_MASK) == 0, "resp token out of range");
unsigned char aToken[3];
aToken[0] = (MyToken>>16)&0xff;
aToken[1] = (MyToken>>8)&0xff;
aToken[2] = (MyToken)&0xff;
SendControlMsg(Socket, pAddr, Token, 0, ControlMsg, aToken, sizeof(aToken));
static unsigned char aBuf[NET_TOKENREQUEST_DATASIZE] = { 0 };
aBuf[0] = (MyToken>>24)&0xff;
aBuf[1] = (MyToken>>16)&0xff;
aBuf[2] = (MyToken>>8)&0xff;
aBuf[3] = (MyToken)&0xff;
SendControlMsg(Socket, pAddr, Token, 0, ControlMsg, aBuf, Extended ? sizeof(aBuf) : 4);
}
unsigned char *CNetChunkHeader::Pack(unsigned char *pData)

View file

@ -9,32 +9,36 @@
/*
CURRENT:
packet header: 5 bytes (6 bytes for connless)
unsigned char token[2]; // 16bit token
unsigned char token_flags; // 4bit token, 4bit flags
unsigned char ack; // 8bit ack
unsigned char ack_numchunks; // 2bit ack, 6bit chunks
// TTTTTTTT
// TTTTTTTT
// TTTTffff
packet header: 7 bytes (9 bytes for connless)
unsigned char flags_ack; // 6bit flags, 2bit ack
unsigned char ack; // 8bit ack
unsigned char numchunks; // 8bit chunks
unsigned char token[4]; // 32bit token
// ffffffaa
// aaaaaaaa
// aaNNNNNN
// NNNNNNNN
// TTTTTTTT
// TTTTTTTT
// TTTTTTTT
// TTTTTTTT
packet header (CONNLESS):
unsigned char token[2]; // 16bit token
unsigned char token_flag; // 4bit token, 4bit flags
unsigned char version_responsetoken; // 4bit version, 4bit response token
unsigned char responsetoken[2]; // 16bit response token
unsigned char flag_version; // 6bit flags, 2bits version
unsigned char token[4]; // 32bit token
unsigned char responsetoken[4]; // 32bit response token
// ffffffvv
// TTTTTTTT
// TTTTTTTT
// TTTTffff
// vvvvRRRR
// TTTTTTTT
// TTTTTTTT
// RRRRRRRR
// RRRRRRRR
// RRRRRRRR
// RRRRRRRR
if the token isn't explicitely set by any means, it must be set to
0xfffff
0xffffffff
chunk header: 2-3 bytes
unsigned char flags_size; // 2bit flags, 6 bit size
@ -62,13 +66,11 @@ enum
enum
{
NET_VERSION = 2,
NET_MAX_CHUNKHEADERSIZE = 3,
// packets
NET_PACKETHEADERSIZE = 5,
NET_PACKETHEADERSIZE_CONNLESS = NET_PACKETHEADERSIZE + 1,
NET_PACKETHEADERSIZE = 7,
NET_PACKETHEADERSIZE_CONNLESS = NET_PACKETHEADERSIZE + 2,
NET_MAX_PACKETHEADERSIZE = NET_PACKETHEADERSIZE_CONNLESS,
NET_MAX_PACKETSIZE = 1400,
@ -81,16 +83,27 @@ enum
NET_PACKETFLAG_COMPRESSION=4,
NET_PACKETFLAG_CONNLESS=8,
NET_MAX_PACKET_CHUNKS=256,
// token
NET_SEEDTIME = 10,
NET_SEEDTIME = 16,
NET_TOKENCACHE_SIZE = 16,
NET_TOKENCACHE_ADDRESSEXPIRY = NET_SEEDTIME/2,
NET_TOKENCACHE_PACKETEXPIRY = NET_TOKENCACHE_ADDRESSEXPIRY,
NET_TOKEN_MAX = 0xfffff,
NET_TOKENCACHE_SIZE = 64,
NET_TOKENCACHE_ADDRESSEXPIRY = NET_SEEDTIME,
NET_TOKENCACHE_PACKETEXPIRY = 5,
};
enum
{
NET_TOKEN_MAX = 0xffffffff,
NET_TOKEN_NONE = NET_TOKEN_MAX,
NET_TOKEN_MASK = NET_TOKEN_MAX,
};
enum
{
NET_TOKENFLAG_ALLOWBROADCAST = 1,
NET_TOKENFLAG_RESPONSEONLY = 2,
NET_TOKENREQUEST_DATASIZE = 512,
//
NET_MAX_CLIENTS = 16,
@ -182,9 +195,9 @@ public:
void GenerateSeed();
int ProcessMessage(const NETADDR *pAddr, const CNetPacketConstruct *pPacket, bool Notify);
int ProcessMessage(const NETADDR *pAddr, const CNetPacketConstruct *pPacket);
bool CheckToken(const NETADDR *pAddr, TOKEN Token, TOKEN ResponseToken, bool Notify);
bool CheckToken(const NETADDR *pAddr, TOKEN Token, TOKEN ResponseToken, bool *BroadcastResponse);
TOKEN GenerateToken(const NETADDR *pAddr) const;
static TOKEN GenerateToken(const NETADDR *pAddr, int64 Seed);
@ -201,6 +214,13 @@ private:
int64 m_NextSeedTime;
};
typedef void(*FSendCallback)(int TrackID, void *pUser);
struct CSendCBData
{
FSendCallback m_pfnCallback;
void *m_pCallbackUser;
int m_TrackID;
};
class CNetTokenCache
{
@ -208,20 +228,30 @@ public:
CNetTokenCache();
~CNetTokenCache();
void Init(NETSOCKET Socket, const CNetTokenManager *pTokenManager);
void SendPacketConnless(const NETADDR *pAddr, const void *pData, int DataSize);
void SendPacketConnless(const NETADDR *pAddr, const void *pData, int DataSize, CSendCBData *pCallbackData = 0);
void PurgeStoredPacket(int TrackID);
void FetchToken(const NETADDR *pAddr);
void AddToken(const NETADDR *pAddr, TOKEN PeerToken);
void AddToken(const NETADDR *pAddr, TOKEN PeerToken, int TokenFlag);
TOKEN GetToken(const NETADDR *pAddr);
void Update();
private:
struct CConnlessPacketInfo
class CConnlessPacketInfo
{
private:
static int m_UniqueID;
public:
CConnlessPacketInfo() : m_TrackID(CConnlessPacketInfo::m_UniqueID++) {}
NETADDR m_Addr;
int m_DataSize;
char m_aData[NET_MAX_PAYLOAD];
int64 m_Expiry;
int64 m_LastTokenRequest;
const int m_TrackID;
FSendCallback m_pfnCallback;
void *m_pCallbackUser;
CConnlessPacketInfo *m_pNext;
};
@ -406,6 +436,7 @@ public:
int Recv(CNetChunk *pChunk, TOKEN *pResponseToken = 0);
int Send(CNetChunk *pChunk, TOKEN Token = NET_TOKEN_NONE);
int Update();
void AddToken(const NETADDR *pAddr, TOKEN Token) { m_TokenCache.AddToken(pAddr, Token, 0); };
//
int Drop(int ClientID, const char *pReason);
@ -483,7 +514,8 @@ public:
// communication
int Recv(CNetChunk *pChunk, TOKEN *pResponseToken = 0);
int Send(CNetChunk *pChunk, TOKEN Token = NET_TOKEN_NONE);
int Send(CNetChunk *pChunk, TOKEN Token = NET_TOKEN_NONE, CSendCBData *pCallbackData = 0);
void PurgeStoredPacket(int TrackID);
// pumping
int Update();
@ -514,7 +546,7 @@ public:
static int Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize);
static void SendControlMsg(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, const void *pExtra, int ExtraSize);
static void SendControlMsgWithToken(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken);
static void SendControlMsgWithToken(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken, bool Extended);
static void SendPacketConnless(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, TOKEN ResponseToken, const void *pData, int DataSize);
static void SendPacket(NETSOCKET Socket, const NETADDR *pAddr, CNetPacketConstruct *pPacket);
static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket);

View file

@ -90,16 +90,16 @@ int CNetClient::Recv(CNetChunk *pChunk, TOKEN *pResponseToken)
}
else
{
int Accept = m_TokenManager.ProcessMessage(&Addr, &m_RecvUnpacker.m_Data, true);
int Accept = m_TokenManager.ProcessMessage(&Addr, &m_RecvUnpacker.m_Data);
if(!Accept)
continue;
if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL)
{
if(m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_TOKEN)
m_TokenCache.AddToken(&Addr, m_RecvUnpacker.m_Data.m_ResponseToken);
m_TokenCache.AddToken(&Addr, m_RecvUnpacker.m_Data.m_ResponseToken, NET_TOKENFLAG_ALLOWBROADCAST|NET_TOKENFLAG_RESPONSEONLY);
}
else if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS)
else if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS && Accept != -1)
{
pChunk->m_Flags = NETSENDFLAG_CONNLESS;
pChunk->m_ClientID = -1;
@ -117,7 +117,7 @@ int CNetClient::Recv(CNetChunk *pChunk, TOKEN *pResponseToken)
return 0;
}
int CNetClient::Send(CNetChunk *pChunk, TOKEN Token)
int CNetClient::Send(CNetChunk *pChunk, TOKEN Token, CSendCBData *pCallbackData)
{
if(pChunk->m_Flags&NETSENDFLAG_CONNLESS)
{
@ -142,7 +142,7 @@ int CNetClient::Send(CNetChunk *pChunk, TOKEN Token)
{
if(pChunk->m_ClientID == -1)
{
m_TokenCache.SendPacketConnless(&pChunk->m_Address, pChunk->m_pData, pChunk->m_DataSize);
m_TokenCache.SendPacketConnless(&pChunk->m_Address, pChunk->m_pData, pChunk->m_DataSize, pCallbackData);
}
else
{
@ -173,6 +173,11 @@ int CNetClient::Send(CNetChunk *pChunk, TOKEN Token)
return 0;
}
void CNetClient::PurgeStoredPacket(int TrackID)
{
m_TokenCache.PurgeStoredPacket(TrackID);
}
int CNetClient::State() const
{
if(m_Connection.State() == NET_CONNSTATE_ONLINE)

View file

@ -108,7 +108,7 @@ int CNetConnection::QueueChunkEx(int Flags, int DataSize, const void *pData, int
unsigned char *pChunkData;
// check if we have space for it, if not, flush the connection
if(m_Construct.m_DataSize + DataSize + NET_MAX_CHUNKHEADERSIZE > (int)sizeof(m_Construct.m_aChunkData))
if(m_Construct.m_DataSize + DataSize + NET_MAX_CHUNKHEADERSIZE > (int)sizeof(m_Construct.m_aChunkData) || m_Construct.m_NumChunks == NET_MAX_PACKET_CHUNKS)
Flush();
// pack all the data
@ -174,7 +174,7 @@ void CNetConnection::SendPacketConnless(const char *pData, int DataSize)
void CNetConnection::SendControlWithToken(int ControlMsg)
{
m_LastSendTime = time_get();
CNetBase::SendControlMsgWithToken(m_Socket, &m_PeerAddr, m_PeerToken, 0, ControlMsg, m_Token);
CNetBase::SendControlMsgWithToken(m_Socket, &m_PeerAddr, m_PeerToken, 0, ControlMsg, m_Token, true);
}
void CNetConnection::ResendChunk(CNetChunkResend *pResend)

View file

@ -159,12 +159,12 @@ int CNetServer::Recv(CNetChunk *pChunk, TOKEN *pResponseToken)
if(Found)
continue;
int Accept = m_TokenManager.ProcessMessage(&Addr, &m_RecvUnpacker.m_Data, true);
int Accept = m_TokenManager.ProcessMessage(&Addr, &m_RecvUnpacker.m_Data);
if(Accept <= 0)
continue;
if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL)
{
if(!Accept)
continue;
if(m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT)
{
bool Found = false;
@ -199,7 +199,6 @@ int CNetServer::Recv(CNetChunk *pChunk, TOKEN *pResponseToken)
Found = true;
m_aSlots[i].m_Connection.SetToken(m_RecvUnpacker.m_Data.m_Token);
m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr);
m_aSlots[i].m_Connection.SetToken(m_RecvUnpacker.m_Data.m_Token); // HACK!
if(m_pfnNewClient)
m_pfnNewClient(i, m_UserPtr);
break;
@ -213,12 +212,10 @@ int CNetServer::Recv(CNetChunk *pChunk, TOKEN *pResponseToken)
}
}
else if(m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_TOKEN)
m_TokenCache.AddToken(&Addr, m_RecvUnpacker.m_Data.m_ResponseToken);
m_TokenCache.AddToken(&Addr, m_RecvUnpacker.m_Data.m_ResponseToken, NET_TOKENFLAG_RESPONSEONLY);
}
else if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONNLESS)
{
if(Accept <= 0)
continue;
pChunk->m_Flags = NETSENDFLAG_CONNLESS;
pChunk->m_ClientID = -1;
pChunk->m_Address = Addr;

View file

@ -20,6 +20,8 @@ static unsigned int Hash(char *pData, int Size)
return (aDigest[0] ^ aDigest[1] ^ aDigest[2] ^ aDigest[3]);
}
int CNetTokenCache::CConnlessPacketInfo::m_UniqueID = 0;
void CNetTokenManager::Init(NETSOCKET Socket, int SeedTime)
{
m_Socket = Socket;
@ -33,10 +35,11 @@ void CNetTokenManager::Update()
GenerateSeed();
}
int CNetTokenManager::ProcessMessage(const NETADDR *pAddr, const CNetPacketConstruct *pPacket, bool Notify)
int CNetTokenManager::ProcessMessage(const NETADDR *pAddr, const CNetPacketConstruct *pPacket)
{
bool BroadcastResponse = false;
if(pPacket->m_Token != NET_TOKEN_NONE
&& !CheckToken(pAddr, pPacket->m_Token, pPacket->m_ResponseToken, Notify))
&& !CheckToken(pAddr, pPacket->m_Token, pPacket->m_ResponseToken, &BroadcastResponse))
return 0; // wrong token, silent ignore
bool Verified = pPacket->m_Token != NET_TOKEN_NONE;
@ -44,11 +47,11 @@ int CNetTokenManager::ProcessMessage(const NETADDR *pAddr, const CNetPacketConst
&& pPacket->m_aChunkData[0] == NET_CTRLMSG_TOKEN;
if(pPacket->m_Flags&NET_PACKETFLAG_CONNLESS)
return (Verified) ? 1 : 0; // connless packets without token are not allowed
return (Verified && !BroadcastResponse) ? 1 : 0; // connless packets without token are not allowed
if(!TokenMessage)
{
if(Verified)
if(Verified && !BroadcastResponse)
return 1; // verified packet
else
// the only allowed not connless packet
@ -57,12 +60,15 @@ int CNetTokenManager::ProcessMessage(const NETADDR *pAddr, const CNetPacketConst
}
if(Verified && TokenMessage)
return 1; // everything is fine, token exchange complete
return BroadcastResponse ? -1 : 1; // everything is fine, token exchange complete
// client requesting token
CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr,
pPacket->m_ResponseToken, 0, NET_CTRLMSG_TOKEN,
GenerateToken(pAddr));
if(pPacket->m_DataSize >= NET_TOKENREQUEST_DATASIZE)
{
CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr,
pPacket->m_ResponseToken, 0, NET_CTRLMSG_TOKEN,
GenerateToken(pAddr), false);
}
return 0; // no need to process NET_CTRLMSG_TOKEN further
}
@ -93,7 +99,7 @@ TOKEN CNetTokenManager::GenerateToken(const NETADDR *pAddr, int64 Seed)
static const NETADDR NullAddr = { 0 };
NETADDR Addr;
char aBuf[sizeof(NETADDR) + sizeof(int64)];
int Result;
unsigned int Result;
if(pAddr->type & NETTYPE_LINK_BROADCAST)
return GenerateToken(&NullAddr, Seed);
@ -110,7 +116,7 @@ TOKEN CNetTokenManager::GenerateToken(const NETADDR *pAddr, int64 Seed)
return Result;
}
bool CNetTokenManager::CheckToken(const NETADDR *pAddr, TOKEN Token, TOKEN ResponseToken, bool Notify)
bool CNetTokenManager::CheckToken(const NETADDR *pAddr, TOKEN Token, TOKEN ResponseToken, bool *BroadcastResponse)
{
TOKEN CurrentToken = GenerateToken(pAddr, m_Seed);
if(CurrentToken == Token)
@ -118,20 +124,18 @@ bool CNetTokenManager::CheckToken(const NETADDR *pAddr, TOKEN Token, TOKEN Respo
if(GenerateToken(pAddr, m_PrevSeed) == Token)
{
if(Notify)
CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr,
ResponseToken, 0, NET_CTRLMSG_TOKEN, CurrentToken);
// notify the peer about the new token
// no need to notify the peer, just a one time thing
return true;
}
else if(Token == m_GlobalToken)
{
*BroadcastResponse = true;
return true;
}
else if(Token == m_PrevGlobalToken)
{
if(Notify)
CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr,
ResponseToken, 0, NET_CTRLMSG_TOKEN, m_GlobalToken);
// notify the peer about the new token
// no need to notify the peer, just a broadcast token response
*BroadcastResponse = true;
return true;
}
@ -167,7 +171,7 @@ void CNetTokenCache::Init(NETSOCKET Socket, const CNetTokenManager *pTokenManage
m_pTokenManager = pTokenManager;
}
void CNetTokenCache::SendPacketConnless(const NETADDR *pAddr, const void *pData, int DataSize)
void CNetTokenCache::SendPacketConnless(const NETADDR *pAddr, const void *pData, int DataSize, CSendCBData *pCallbackData)
{
TOKEN Token = GetToken(pAddr);
if(Token != NET_TOKEN_NONE)
@ -187,8 +191,50 @@ void CNetTokenCache::SendPacketConnless(const NETADDR *pAddr, const void *pData,
mem_copy((*ppInfo)->m_aData, pData, DataSize);
(*ppInfo)->m_Addr = *pAddr;
(*ppInfo)->m_DataSize = DataSize;
(*ppInfo)->m_Expiry = time_get() + time_freq() * NET_TOKENCACHE_PACKETEXPIRY;
int64 Now = time_get();
(*ppInfo)->m_Expiry = Now + time_freq() * NET_TOKENCACHE_PACKETEXPIRY;
(*ppInfo)->m_LastTokenRequest = Now;
(*ppInfo)->m_pNext = 0;
if(pCallbackData)
{
(*ppInfo)->m_pfnCallback = pCallbackData->m_pfnCallback;
(*ppInfo)->m_pCallbackUser = pCallbackData->m_pCallbackUser;
pCallbackData->m_TrackID = (*ppInfo)->m_TrackID;
}
else
{
(*ppInfo)->m_pfnCallback = 0;
(*ppInfo)->m_pCallbackUser = 0;
}
}
}
void CNetTokenCache::PurgeStoredPacket(int TrackID)
{
CConnlessPacketInfo *pPrevInfo = 0;
CConnlessPacketInfo *pInfo = m_pConnlessPacketList;
while(pInfo)
{
if(pInfo->m_TrackID == TrackID)
{
// purge desired packet
CConnlessPacketInfo *pNext = pInfo->m_pNext;
if(pPrevInfo)
pPrevInfo->m_pNext = pNext;
if(pInfo == m_pConnlessPacketList)
m_pConnlessPacketList = pNext;
delete pInfo;
break;
}
else
{
if(pPrevInfo)
pPrevInfo = pPrevInfo->m_pNext;
else
pPrevInfo = pInfo;
pInfo = pInfo->m_pNext;
}
}
}
@ -209,33 +255,30 @@ TOKEN CNetTokenCache::GetToken(const NETADDR *pAddr)
void CNetTokenCache::FetchToken(const NETADDR *pAddr)
{
CNetBase::SendControlMsgWithToken(m_Socket, pAddr, NET_TOKEN_NONE, 0,
NET_CTRLMSG_TOKEN, m_pTokenManager->GenerateToken(pAddr));
NET_CTRLMSG_TOKEN, m_pTokenManager->GenerateToken(pAddr), true);
}
void CNetTokenCache::AddToken(const NETADDR *pAddr, TOKEN Token)
void CNetTokenCache::AddToken(const NETADDR *pAddr, TOKEN Token, int TokenFLag)
{
if(Token == NET_TOKEN_NONE)
return;
CAddressInfo Info;
Info.m_Addr = *pAddr;
Info.m_Token = Token;
Info.m_Expiry = time_get() + time_freq() * NET_TOKENCACHE_ADDRESSEXPIRY;
(*m_TokenCache.Allocate(sizeof(Info))) = Info;
// search the list of packets to be sent
// for this address
CConnlessPacketInfo *pPrevInfo = 0;
CConnlessPacketInfo *pInfo = m_pConnlessPacketList;
bool Found = false;
while(pInfo)
{
static NETADDR NullAddr = { 0 };
NullAddr.type = 7; // cover broadcasts
NullAddr.port = pAddr->port;
if(net_addr_comp(&pInfo->m_Addr, pAddr) == 0 || net_addr_comp(&pInfo->m_Addr, &NullAddr) == 0)
if(net_addr_comp(&pInfo->m_Addr, pAddr) == 0 || ((TokenFLag&NET_TOKENFLAG_ALLOWBROADCAST) && net_addr_comp(&pInfo->m_Addr, &NullAddr) == 0))
{
CNetBase::SendPacketConnless(m_Socket, pAddr, Token,
// notify the user that the packet gets delivered
if(pInfo->m_pfnCallback)
pInfo->m_pfnCallback(pInfo->m_TrackID, pInfo->m_pCallbackUser);
CNetBase::SendPacketConnless(m_Socket, &(pInfo->m_Addr), Token,
m_pTokenManager->GenerateToken(pAddr),
pInfo->m_aData, pInfo->m_DataSize);
CConnlessPacketInfo *pNext = pInfo->m_pNext;
@ -255,6 +298,16 @@ void CNetTokenCache::AddToken(const NETADDR *pAddr, TOKEN Token)
pInfo = pInfo->m_pNext;
}
}
// add the token
if(Found || !(TokenFLag&NET_TOKENFLAG_RESPONSEONLY))
{
CAddressInfo Info;
Info.m_Addr = *pAddr;
Info.m_Token = Token;
Info.m_Expiry = time_get() + time_freq() * NET_TOKENCACHE_ADDRESSEXPIRY;
(*m_TokenCache.Allocate(sizeof(Info))) = Info;
}
}
void CNetTokenCache::Update()
@ -266,6 +319,17 @@ void CNetTokenCache::Update()
while((pAddrInfo = m_TokenCache.First()) && (pAddrInfo->m_Expiry <= Now))
m_TokenCache.PopFirst();
// try to fetch the token again for stored packets
CConnlessPacketInfo * pEntry = m_pConnlessPacketList;
while(pEntry)
{
if(pEntry->m_LastTokenRequest + 2*time_freq() <= Now)
{
FetchToken(&pEntry->m_Addr);
pEntry->m_LastTokenRequest = Now;
}
pEntry = pEntry->m_pNext;
}
// drop expired packets
while(m_pConnlessPacketList && m_pConnlessPacketList->m_Expiry <= Now)

View file

@ -3,6 +3,8 @@
#ifndef ENGINE_TEXTRENDER_H
#define ENGINE_TEXTRENDER_H
#include "kernel.h"
#include <base/vmath.h>
#include <engine/graphics.h>
enum
{
@ -40,6 +42,11 @@ public:
//
virtual void TextEx(CTextCursor *pCursor, const char *pText, int Length) = 0;
virtual void TextDeferredRenderEx(CTextCursor *pCursor, const char *pText, int Length,
struct CQuadChar* aQuadChar, int QuadCharMaxCount, int* out_pQuadCharCount,
IGraphics::CTextureHandle* pFontTexture) = 0;
virtual void TextShadowed(CTextCursor *pCursor, const char *pText, int Length, vec2 ShadowOffset,
vec4 ShadowColor, vec4 TextColor_) = 0;
// old foolish interface
virtual void TextColor(float r, float g, float b, float a) = 0;
@ -47,6 +54,8 @@ public:
virtual void Text(void *pFontSetV, float x, float y, float Size, const char *pText, int MaxWidth) = 0;
virtual float TextWidth(void *pFontSetV, float Size, const char *pText, int Length) = 0;
virtual int TextLineCount(void *pFontSetV, float Size, const char *pText, float LineWidth) = 0;
virtual float TextGetLineBaseY(const CTextCursor *pCursor) = 0;
};
class IEngineTextRender : public ITextRender

View file

@ -14,14 +14,24 @@ CCamera::CCamera()
{
m_CamType = CAMTYPE_UNDEFINED;
m_RotationCenter = vec2(0.0f, 0.0f);
m_AnimationStartPos = vec2(0.0f, 0.0f);
m_Center = vec2(0.0f, 0.0f);
m_PrevCenter = vec2(0.0f, 0.0f);
m_MenuCenter = vec2(0.0f, 0.0f);
m_Positions[POS_START] = vec2(500.0f, 500.0f);
m_Positions[POS_INTERNET] = vec2(1000.0f, 1000.0f);
m_Positions[POS_DEMOS] = vec2(500.0f, 1000.0f);
m_Positions[POS_SETTINGS] = vec2(1000.0f, 500.0f);
m_Positions[POS_LAN] = vec2(1100.0f, 1000.0f);
m_Positions[POS_DEMOS] = vec2(1500.0f, 500.0f);
m_Positions[POS_SETTINGS_GENERAL] = vec2(500.0f, 1000.0f);
m_Positions[POS_SETTINGS_PLAYER] = vec2(600.0f, 1000.0f);
m_Positions[POS_SETTINGS_TEE] = vec2(700.0f, 1000.0f);
m_Positions[POS_SETTINGS_CONTROLS] = vec2(800.0f, 1000.0f);
m_Positions[POS_SETTINGS_GRAPHICS] = vec2(900.0f, 1000.0f);
m_Positions[POS_SETTINGS_SOUND] = vec2(1000.0f, 1000.0f);
m_CurrentPosition = -1;
m_MoveTime = 0.0f;
}
void CCamera::OnRender()
@ -31,7 +41,8 @@ void CCamera::OnRender()
m_Zoom = 1.0f;
// update camera center
if(m_pClient->m_Snap.m_SpecInfo.m_Active && !m_pClient->m_Snap.m_SpecInfo.m_UsePosition)
if(m_pClient->m_Snap.m_SpecInfo.m_Active && !m_pClient->m_Snap.m_SpecInfo.m_UsePosition &&
(m_pClient->m_Snap.m_SpecInfo.m_SpecMode == SPEC_FREEVIEW || (m_pClient->m_Snap.m_pLocalInfo && !(m_pClient->m_Snap.m_pLocalInfo->m_PlayerFlags&PLAYERFLAG_DEAD))))
{
if(m_CamType != CAMTYPE_SPEC)
{
@ -52,7 +63,7 @@ void CCamera::OnRender()
vec2 CameraOffset(0, 0);
float l = length(m_pClient->m_pControls->m_MousePos);
if(l > 0.0001f) // make sure that this isn't 0
if(g_Config.m_ClDynamicCamera && l > 0.0001f) // make sure that this isn't 0
{
float DeadZone = g_Config.m_ClMouseDeadzone;
float FollowFactor = g_Config.m_ClMouseFollowfactor/100.0f;
@ -81,9 +92,17 @@ void CCamera::OnRender()
}
else
{
Dir = normalize(m_RotationCenter-m_Center);
m_Center += Dir*(500.0f*Client()->RenderFrameTime());
Dir = normalize(m_Center-m_RotationCenter);
// positions for the animation
Dir = normalize(m_AnimationStartPos - m_RotationCenter);
vec2 TargetPos = m_RotationCenter + Dir * (float)g_Config.m_ClRotationRadius;
float Distance = distance(m_AnimationStartPos, TargetPos);
// move time
m_MoveTime += Client()->RenderFrameTime()*g_Config.m_ClCameraSpeed / 10.0f;
float XVal = 1 - m_MoveTime;
XVal = pow(XVal, 7.0);
m_Center = TargetPos + Dir * (XVal*Distance);
}
}
@ -92,8 +111,12 @@ void CCamera::OnRender()
void CCamera::ChangePosition(int PositionNumber)
{
if(PositionNumber < 0 || PositionNumber > NUM_POS-1)
return;
m_AnimationStartPos = m_Center;
m_RotationCenter = m_Positions[PositionNumber];
m_CurrentPosition = PositionNumber;
m_MoveTime = 0.0f;
}
int CCamera::GetCurrentPosition()

View file

@ -10,33 +10,34 @@ class CCamera : public CComponent
public:
enum
{
POS_START=0,
POS_START = 0,
POS_INTERNET,
POS_LAN,
POS_FAVORITES,
POS_DEMOS,
POS_SETTINGS,
POS_SETTINGS_GENERAL, // order here should be the same like enum for settings pages in menu
POS_SETTINGS_PLAYER,
POS_SETTINGS_TEE,
POS_SETTINGS_CONTROLS,
POS_SETTINGS_GRAPHICS,
POS_SETTINGS_SOUND,
NUM_POS,
};
vec2 m_Center;
vec2 m_MenuCenter;
vec2 m_RotationCenter;
float m_Zoom;
CCamera();
virtual void OnRender();
void ChangePosition(int PositionNumber);
int GetCurrentPosition();
const vec2 *GetCenter() const { return &m_Center; };
float GetZoom() const { return m_Zoom; };
static void ConSetPosition(IConsole::IResult *pResult, void *pUserData);
virtual void OnConsoleInit();
virtual void OnStateChange(int NewState, int OldState);
public:
private:
enum
{
CAMTYPE_UNDEFINED=-1,
@ -44,10 +45,16 @@ public:
CAMTYPE_PLAYER,
};
vec2 m_Center;
vec2 m_MenuCenter;
vec2 m_RotationCenter;
float m_Zoom;
int m_CamType;
vec2 m_PrevCenter;
vec2 m_Positions[NUM_POS];
int m_CurrentPosition;
vec2 m_AnimationStartPos;
float m_MoveTime;
};
#endif

View file

@ -81,7 +81,7 @@ void CChat::ConSayTeam(IConsole::IResult *pResult, void *pUserData)
void CChat::ConWhisper(IConsole::IResult *pResult, void *pUserData)
{
CChat *pChat = (CChat *)pUserData;
int Target = pResult->GetInteger(0);
if(Target < 0 || Target >= MAX_CLIENTS || !pChat->m_pClient->m_aClients[Target].m_Active || pChat->m_pClient->m_LocalClientID == Target)
pChat->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", "please enter a valid ClientID");
@ -103,15 +103,15 @@ void CChat::ConChat(IConsole::IResult *pResult, void *pUserData)
pChat->EnableMode(CHAT_TEAM);
else if(str_comp(pMode, "whisper") == 0)
{
int Target = -1;
int Target = pChat->m_WhisperTarget; // default to ID of last target
if(pResult->NumArguments() == 2)
Target = pResult->GetInteger(1);
else
{
// pick next player as target
// pick next valid player as target
for(int i = 0; i < MAX_CLIENTS; i++)
{
int ClientID = (pChat->m_pClient->m_LocalClientID + i) % MAX_CLIENTS;
int ClientID = (Target + i) % MAX_CLIENTS;
if(pChat->m_pClient->m_aClients[ClientID].m_Active && pChat->m_pClient->m_LocalClientID != ClientID)
{
Target = ClientID;
@ -161,7 +161,7 @@ bool CChat::OnInput(IInput::CEvent Event)
{
bool AddEntry = false;
if(m_LastChatSend+time_freq() < time_get())
if(m_PendingChatCounter == 0 && m_LastChatSend+time_freq() < time_get())
{
Say(m_Mode, m_Input.GetString());
AddEntry = true;
@ -187,10 +187,14 @@ bool CChat::OnInput(IInput::CEvent Event)
{
if (m_Mode == CHAT_WHISPER)
{
// pick next player as target
// change target
for(int i = 0; i < MAX_CLIENTS; i++)
{
int ClientID = (m_WhisperTarget + i) % MAX_CLIENTS;
int ClientID;
if(Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL))
ClientID = (m_WhisperTarget + MAX_CLIENTS - i) % MAX_CLIENTS; // pick previous player as target
else
ClientID = (m_WhisperTarget + i) % MAX_CLIENTS; // pick next player as target
if (m_pClient->m_aClients[ClientID].m_Active && m_WhisperTarget != ClientID && m_pClient->m_LocalClientID != ClientID)
{
m_WhisperTarget = ClientID;
@ -299,7 +303,7 @@ bool CChat::OnInput(IInput::CEvent Event)
if(m_Input.ProcessInput(Event))
{
m_InputUpdate = true;
// reset name completion process
m_CompletionChosen = -1;
}
@ -359,11 +363,11 @@ void CChat::OnMessage(int MsgType, void *pRawMsg)
if(MsgType == NETMSGTYPE_SV_CHAT)
{
CNetMsg_Sv_Chat *pMsg = (CNetMsg_Sv_Chat *)pRawMsg;
AddLine(pMsg->m_ClientID, pMsg->m_Mode, pMsg->m_pMessage);
AddLine(pMsg->m_ClientID, pMsg->m_Mode, pMsg->m_pMessage, pMsg->m_TargetID);
}
}
void CChat::AddLine(int ClientID, int Mode, const char *pLine)
void CChat::AddLine(int ClientID, int Mode, const char *pLine, int TargetID)
{
if(*pLine == 0 || (ClientID != -1 && (!g_Config.m_ClShowsocial || m_pClient->m_aClients[ClientID].m_aName[0] == '\0' || // unknown client
m_pClient->m_aClients[ClientID].m_ChatIgnore ||
@ -376,7 +380,7 @@ void CChat::AddLine(int ClientID, int Mode, const char *pLine)
const char *pStr = pLine;
const char *pEnd = 0;
while(*pStr)
{
{
const char *pStrOld = pStr;
int Code = str_utf8_decode(&pStr);
@ -395,7 +399,7 @@ void CChat::AddLine(int ClientID, int Mode, const char *pLine)
*(const_cast<char *>(pStr)) = 0;
break;
}
}
}
if(pEnd != 0)
*(const_cast<char *>(pEnd)) = 0;
@ -416,15 +420,17 @@ void CChat::AddLine(int ClientID, int Mode, const char *pLine)
m_CurrentLine = (m_CurrentLine+1)%MAX_LINES;
m_aLines[m_CurrentLine].m_Time = time_get();
m_aLines[m_CurrentLine].m_YOffset[0] = -1.0f;
m_aLines[m_CurrentLine].m_YOffset[1] = -1.0f;
m_aLines[m_CurrentLine].m_Size[0].y = -1.0f;
m_aLines[m_CurrentLine].m_Size[1].y = -1.0f;
m_aLines[m_CurrentLine].m_ClientID = ClientID;
m_aLines[m_CurrentLine].m_TargetID = TargetID;
m_aLines[m_CurrentLine].m_Mode = Mode;
m_aLines[m_CurrentLine].m_NameColor = -2;
// check for highlighted name
Highlighted = false;
if(ClientID != m_pClient->m_LocalClientID) // do not highlight our own messages
// do not highlight our own messages, whispers and system messages
if(Mode != CHAT_WHISPER && ClientID != -1 && ClientID != m_pClient->m_LocalClientID)
{
const char *pHL = str_find_nocase(pLine, m_pClient->m_aClients[m_pClient->m_LocalClientID].m_aName);
if(pHL)
@ -441,12 +447,16 @@ void CChat::AddLine(int ClientID, int Mode, const char *pLine)
}
}
m_aLines[m_CurrentLine].m_Highlighted = Highlighted || Mode == CHAT_WHISPER;
m_aLines[m_CurrentLine].m_Highlighted = Highlighted;
int NameCID = ClientID;
if(Mode == CHAT_WHISPER && ClientID == m_pClient->m_LocalClientID && TargetID >= 0)
NameCID = TargetID;
if(ClientID == -1) // server message
{
str_copy(m_aLines[m_CurrentLine].m_aName, "*** ", sizeof(m_aLines[m_CurrentLine].m_aName));
str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), "%s", pLine);
m_aLines[m_CurrentLine].m_aName[0] = 0;
str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), "*** %s", pLine);
}
else
{
@ -461,8 +471,8 @@ void CChat::AddLine(int ClientID, int Mode, const char *pLine)
m_aLines[m_CurrentLine].m_NameColor = TEAM_BLUE;
}
str_format(m_aLines[m_CurrentLine].m_aName, sizeof(m_aLines[m_CurrentLine].m_aName), "%2d: %s", ClientID, m_pClient->m_aClients[ClientID].m_aName);
str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), ": %s", pLine);
str_format(m_aLines[m_CurrentLine].m_aName, sizeof(m_aLines[m_CurrentLine].m_aName), "%s", m_pClient->m_aClients[NameCID].m_aName);
str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), "%s", pLine);
}
char aBuf[1024];
@ -473,8 +483,9 @@ void CChat::AddLine(int ClientID, int Mode, const char *pLine)
str_copy(aBufMode, "teamchat", sizeof(aBufMode));
else
str_copy(aBufMode, "chat", sizeof(aBufMode));
str_format(aBuf, sizeof(aBuf), "%s%s", m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, aBufMode, aBuf, Highlighted);
str_format(aBuf, sizeof(aBuf), "%2d: %s: %s", NameCID, m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, aBufMode, aBuf, Highlighted || Mode == CHAT_WHISPER);
}
// play sound
@ -487,7 +498,7 @@ void CChat::AddLine(int ClientID, int Mode, const char *pLine)
m_aLastSoundPlayed[CHAT_SERVER] = Now;
}
}
else if(Highlighted)
else if(Highlighted || Mode == CHAT_WHISPER)
{
if(Now-m_aLastSoundPlayed[CHAT_HIGHLIGHT] >= time_freq()*3/10)
{
@ -528,28 +539,107 @@ void CChat::OnRender()
float Width = 300.0f*Graphics()->ScreenAspect();
Graphics()->MapScreen(0.0f, 0.0f, Width, 300.0f);
float x = 5.0f;
float x = 12.0f;
float y = 300.0f-20.0f;
const int LocalCID = m_pClient->m_LocalClientID;
const CGameClient::CClientData& LocalClient = m_pClient->m_aClients[LocalCID];
const int LocalTteam = LocalClient.m_Team;
if(m_Mode != CHAT_NONE)
{
// calculate category text size
// TODO: rework TextRender. Writing the same code twice to calculate a simple thing as width is ridiculus
float CategoryWidth = 0;
float CategoryHeight;
const float CategoryFontSize = 8.0f;
const float InputFontSize = 8.0f;
char aCatText[48];
{
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, x, y, CategoryFontSize, 0);
if(m_Mode == CHAT_ALL)
str_copy(aCatText, Localize("All"), sizeof(aCatText));
else if(m_Mode == CHAT_TEAM)
{
if(LocalTteam == TEAM_SPECTATORS)
str_copy(aCatText, Localize("Spectators"), sizeof(aCatText));
else
str_copy(aCatText, Localize("Team"), sizeof(aCatText));
}
else if(m_Mode == CHAT_WHISPER)
{
CategoryWidth += RenderTools()->GetClientIdRectSize(CategoryFontSize);
str_format(aCatText, sizeof(aCatText), "%s",m_pClient->m_aClients[m_WhisperTarget].m_aName);
}
else
str_copy(aCatText, Localize("Chat"), sizeof(aCatText));
TextRender()->TextEx(&Cursor, aCatText, -1);
CategoryWidth += Cursor.m_X - Cursor.m_StartX;
CategoryHeight = Cursor.m_FontSize;
}
// draw a background box
const vec4 CRCWhite(1, 1, 1, 0.25);
const vec4 CRCTeam(0.4, 1, 0.4, 0.4);
const vec4 CRCWhisper(0, 0.5, 1, 0.5);
vec4 CatRectColor = CRCWhite;
if(m_Mode == CHAT_TEAM)
CatRectColor = CRCTeam;
else if(m_Mode == CHAT_WHISPER)
CatRectColor = CRCWhisper;
const float IconOffsetX = m_Mode == CHAT_WHISPER ? 6.0f : 0.0f;
CUIRect CatRect;
CatRect.x = 0;
CatRect.y = y;
CatRect.w = CategoryWidth + x + 2.0f + IconOffsetX;
CatRect.h = CategoryHeight + 4.0f;
RenderTools()->DrawUIRect(&CatRect, CatRectColor, CUI::CORNER_R, 2.0f);
// draw chat icon
Graphics()->WrapClamp();
IGraphics::CQuadItem QuadIcon;
if(m_Mode == CHAT_WHISPER)
{
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CHATWHISPER].m_Id);
Graphics()->QuadsBegin();
Graphics()->QuadsSetSubset(1, 0, 0, 1);
QuadIcon = IGraphics::CQuadItem(1.5f, y + (CatRect.h - 8.0f) * 0.5f, 16.f, 8.0f);
}
else
{
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_EMOTICONS].m_Id);
Graphics()->QuadsBegin();
RenderTools()->SelectSprite(SPRITE_DOTDOT);
QuadIcon = IGraphics::CQuadItem(1.0f, y, 10.f, 10.0f);
}
Graphics()->SetColor(1, 1, 1, 1);
Graphics()->QuadsDrawTL(&QuadIcon, 1);
Graphics()->QuadsEnd();
Graphics()->WrapNormal();
// render chat input
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, x, y, 8.0f, TEXTFLAG_RENDER);
TextRender()->SetCursor(&Cursor, x + IconOffsetX, y, CategoryFontSize, TEXTFLAG_RENDER);
Cursor.m_LineWidth = Width-190.0f;
Cursor.m_MaxLines = 2;
char aBuf[32];
if(m_Mode == CHAT_ALL)
str_copy(aBuf, Localize("All"), sizeof(aBuf));
else if(m_Mode == CHAT_TEAM)
str_copy(aBuf, Localize("Team"), sizeof(aBuf));
else if(m_Mode == CHAT_WHISPER)
str_format(aBuf, sizeof(aBuf), "%s %2d: %s", Localize("To"), m_WhisperTarget, m_pClient->m_aClients[m_WhisperTarget].m_aName);
else
str_copy(aBuf, Localize("Chat"), sizeof(aBuf));
TextRender()->TextEx(&Cursor, aBuf, -1);
TextRender()->TextEx(&Cursor, ": ", -1);
if(m_Mode == CHAT_WHISPER)
RenderTools()->DrawClientID(TextRender(), &Cursor, m_WhisperTarget);
TextRender()->TextEx(&Cursor, aCatText, -1);
Cursor.m_X += 4.0f;
Cursor.m_Y -= (InputFontSize-CategoryFontSize) * 0.5f;
Cursor.m_StartX = Cursor.m_X;
Cursor.m_FontSize = InputFontSize;
// check if the visible text has to be moved
if(m_InputUpdate)
@ -587,70 +677,242 @@ void CChat::OnRender()
y -= 8.0f;
// show all chat when typing
m_Show |= m_Mode != CHAT_NONE;
int64 Now = time_get();
const int64 TimeFreq = time_freq();
float LineWidth = m_pClient->m_pScoreboard->Active() ? 90.0f : 200.0f;
float HeightLimit = m_pClient->m_pScoreboard->Active() ? 230.0f : m_Show ? 50.0f : 200.0f;
float HeightLimit = m_pClient->m_pScoreboard->Active() ? 230.0f : m_Show ? 90.0f : 200.0f;
float Begin = x;
float FontSize = 6.0f;
CTextCursor Cursor;
int OffsetType = m_pClient->m_pScoreboard->Active() ? 1 : 0;
// get the y offset (calculate it if we haven't done that yet)
for(int i = 0; i < MAX_LINES; i++)
{
int r = ((m_CurrentLine-i)+MAX_LINES)%MAX_LINES;
if(Now > m_aLines[r].m_Time+16*time_freq() && !m_Show)
break;
CLine& Line = m_aLines[r];
// get the y offset (calculate it if we haven't done that yet)
if(m_aLines[r].m_YOffset[OffsetType] < 0.0f)
if(m_aLines[r].m_aText[0] == 0) break;
if(Line.m_Size[OffsetType].y < 0.0f)
{
TextRender()->SetCursor(&Cursor, Begin, 0.0f, FontSize, 0);
Cursor.m_LineWidth = LineWidth;
TextRender()->TextEx(&Cursor, m_aLines[r].m_aName, -1);
TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1);
m_aLines[r].m_YOffset[OffsetType] = Cursor.m_Y + Cursor.m_FontSize;
char aBuf[768] = {0};
if(Line.m_Mode == CHAT_TEAM)
str_format(aBuf, sizeof(aBuf), "[%s] ", Localize("Team"));
else if(Line.m_Mode == CHAT_WHISPER)
str_format(aBuf, sizeof(aBuf), "[%s] ", Localize("Whisper"));
if(Line.m_ClientID != -1)
{
Cursor.m_X += RenderTools()->GetClientIdRectSize(Cursor.m_FontSize);
str_append(aBuf, Line.m_aName, sizeof(aBuf));
str_append(aBuf, ": ", sizeof(aBuf));
}
str_append(aBuf, Line.m_aText, sizeof(aBuf));
TextRender()->TextEx(&Cursor, aBuf, -1);
// FIXME: sometimes an empty line will pop here when the cursor reaches the end of line
Line.m_Size[OffsetType].y = Cursor.m_LineCount * Cursor.m_FontSize;
Line.m_Size[OffsetType].x = Cursor.m_LineCount == 1 ? Cursor.m_X - Cursor.m_StartX : LineWidth;
}
y -= m_aLines[r].m_YOffset[OffsetType];
}
if(m_Show)
{
CUIRect Rect;
Rect.x = 0;
Rect.y = HeightLimit - 2.0f;
Rect.w = LineWidth + x;
Rect.h = 300 - HeightLimit - 22.f;
const float LeftAlpha = 0.85f;
const float RightAlpha = 0.05f;
RenderTools()->DrawUIRect4(&Rect,
vec4(0, 0, 0, LeftAlpha),
vec4(0, 0, 0, RightAlpha),
vec4(0, 0, 0, LeftAlpha),
vec4(0, 0, 0, RightAlpha),
CUI::CORNER_R, 3.0f);
}
for(int i = 0; i < MAX_LINES; i++)
{
int r = ((m_CurrentLine-i)+MAX_LINES)%MAX_LINES;
CLine& Line = m_aLines[r];
if(m_aLines[r].m_aText[0] == 0) break;
if(Now > Line.m_Time+16*TimeFreq && !m_Show)
break;
y -= Line.m_Size[OffsetType].y;
// cut off if msgs waste too much space
if(y < HeightLimit)
break;
float Blend = Now > m_aLines[r].m_Time+14*time_freq() && !m_Show ? 1.0f-(Now-m_aLines[r].m_Time-14*time_freq())/(2.0f*time_freq()) : 1.0f;
float Blend = Now > Line.m_Time+14*TimeFreq && !m_Show ? 1.0f-(Now-Line.m_Time-14*TimeFreq)/(2.0f*TimeFreq) : 1.0f;
const float HlTimeFull = 1.0f;
const float HlTimeFade = 1.0f;
float Delta = (Now - Line.m_Time) / (float)TimeFreq;
const float HighlightBlend = 1.0f - clamp(Delta - HlTimeFull, 0.0f, HlTimeFade) / HlTimeFade;
// reset the cursor
TextRender()->SetCursor(&Cursor, Begin, y, FontSize, TEXTFLAG_RENDER);
Cursor.m_LineWidth = LineWidth;
// render name
if(m_aLines[r].m_ClientID == -1)
TextRender()->TextColor(1.0f, 1.0f, 0.5f, Blend); // system
else if(m_aLines[r].m_Mode == CHAT_TEAM)
TextRender()->TextColor(0.45f, 0.9f, 0.45f, Blend); // team message
else if(m_aLines[r].m_NameColor == TEAM_RED)
TextRender()->TextColor(1.0f, 0.5f, 0.5f, Blend); // red
else if(m_aLines[r].m_NameColor == TEAM_BLUE)
TextRender()->TextColor(0.7f, 0.7f, 1.0f, Blend); // blue
else if(m_aLines[r].m_NameColor == TEAM_SPECTATORS)
TextRender()->TextColor(0.75f, 0.5f, 0.75f, Blend); // spectator
else
TextRender()->TextColor(0.8f, 0.8f, 0.8f, Blend);
const vec2 ShadowOffset(0.8f, 1.5f);
const vec4 ShadowWhisper(0.09f, 0.f, 0.26f, Blend * 0.9f);
const vec4 ShadowBlack(0, 0, 0, Blend * 0.9f);
vec4 ShadowColor = ShadowBlack;
TextRender()->TextEx(&Cursor, m_aLines[r].m_aName, -1);
if(Line.m_Mode == CHAT_WHISPER)
ShadowColor = ShadowWhisper;
const vec4 ColorSystem(1.0f, 1.0f, 0.5f, Blend);
const vec4 ColorWhisper(0.4f, 1.0f, 1.0f, Blend);
const vec4 ColorRed(1.0f, 0.5f, 0.5f, Blend);
const vec4 ColorBlue(0.7f, 0.7f, 1.0f, Blend);
const vec4 ColorSpec(0.75f, 0.5f, 0.75f, Blend);
const vec4 ColorAllPre(0.8f, 0.8f, 0.8f, Blend);
const vec4 ColorAllText(1.0f, 1.0f, 1.0f, Blend);
const vec4 ColorTeamPre(0.45f, 0.9f, 0.45f, Blend);
const vec4 ColorTeamText(0.6f, 1.0f, 0.6f, Blend);
const vec4 ColorHighlightBg(0.0f, 0.27f, 0.9f, 0.5f * HighlightBlend);
const vec4 ColorHighlightOutline(0.0f, 0.4f, 1.0f,
mix(Line.m_Mode == CHAT_TEAM ? 0.6f : 0.5f, 1.0f, HighlightBlend));
vec4 TextColor = ColorAllText;
if(Line.m_Highlighted && ColorHighlightBg.a > 0.001f)
{
CUIRect BgRect;
BgRect.x = Cursor.m_X;
BgRect.y = Cursor.m_Y + 2.0f;
BgRect.w = Line.m_Size[OffsetType].x - 2.0f;
BgRect.h = Line.m_Size[OffsetType].y;
vec4 LeftColor = ColorHighlightBg * ColorHighlightBg.a;
LeftColor.a = ColorHighlightBg.a;
vec4 RightColor = ColorHighlightBg;
RightColor *= 0.1f;
RenderTools()->DrawUIRect4(&BgRect,
LeftColor,
RightColor,
LeftColor,
RightColor,
CUI::CORNER_R, 2.0f);
}
char aBuf[48];
if(Line.m_Mode == CHAT_WHISPER)
{
const float LineBaseY = TextRender()->TextGetLineBaseY(&Cursor);
const float qw = 10.0f;
const float qh = 5.0f;
const float qx = Cursor.m_X + 2.0f;
const float qy = LineBaseY - qh - 0.5f;
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CHATWHISPER].m_Id);
Graphics()->WrapClamp();
Graphics()->QuadsBegin();
// image orientation
const int LocalCID = m_pClient->m_LocalClientID;
if(Line.m_ClientID == LocalCID && Line.m_TargetID >= 0)
Graphics()->QuadsSetSubset(1, 0, 0, 1); // To
else if(Line.m_TargetID == LocalCID)
Graphics()->QuadsSetSubset(0, 0, 1, 1); // From
else
dbg_break();
// shadow pass
Graphics()->SetColor(ShadowWhisper.r*ShadowWhisper.a*Blend, ShadowWhisper.g*ShadowWhisper.a*Blend,
ShadowWhisper.b*ShadowWhisper.a*Blend, ShadowWhisper.a*Blend);
IGraphics::CQuadItem Quad(qx + 0.2f, qy + 0.5f, qw, qh);
Graphics()->QuadsDrawTL(&Quad, 1);
// color pass
Graphics()->SetColor(ColorWhisper.r*Blend, ColorWhisper.g*Blend, ColorWhisper.b*Blend, Blend);
Quad = IGraphics::CQuadItem(qx, qy, qw, qh);
Graphics()->QuadsDrawTL(&Quad, 1);
Graphics()->QuadsEnd();
Graphics()->WrapNormal();
Cursor.m_X += 12.5f;
}
// render name
if(Line.m_ClientID == -1)
TextColor = ColorSystem;
else if(Line.m_Mode == CHAT_WHISPER)
TextColor = ColorWhisper;
else if(Line.m_Mode == CHAT_TEAM)
TextColor = ColorTeamPre;
else if(Line.m_NameColor == TEAM_RED)
TextColor = ColorRed;
else if(Line.m_NameColor == TEAM_BLUE)
TextColor = ColorBlue;
else if(Line.m_NameColor == TEAM_SPECTATORS)
TextColor = ColorSpec;
else
TextColor = ColorAllPre;
if(Line.m_ClientID != -1)
{
int NameCID = Line.m_ClientID;
if(Line.m_Mode == CHAT_WHISPER && Line.m_ClientID == m_pClient->m_LocalClientID && Line.m_TargetID >= 0)
NameCID = Line.m_TargetID;
vec4 BgIdColor = TextColor;
BgIdColor.a = 0.5f;
RenderTools()->DrawClientID(TextRender(), &Cursor, NameCID, BgIdColor);
str_format(aBuf, sizeof(aBuf), "%s: ", Line.m_aName);
TextRender()->TextShadowed(&Cursor, aBuf, -1, ShadowOffset, ShadowColor, TextColor);
}
// render line
if(m_aLines[r].m_ClientID == -1)
TextRender()->TextColor(1.0f, 1.0f, 0.5f, Blend); // system
else if(m_aLines[r].m_Highlighted)
TextRender()->TextColor(1.0f, 0.5f, 0.5f, Blend); // highlighted
else if(m_aLines[r].m_Mode == CHAT_TEAM)
TextRender()->TextColor(0.65f, 1.0f, 0.65f, Blend); // team message
if(Line.m_ClientID == -1)
TextColor = ColorSystem;
else if(Line.m_Mode == CHAT_WHISPER)
TextColor = ColorWhisper;
else if(Line.m_Mode == CHAT_TEAM)
TextColor = ColorTeamText;
else
TextRender()->TextColor(1.0f, 1.0f, 1.0f, Blend);
TextColor = ColorAllText;
TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1);
if(Line.m_Highlighted)
{
TextRender()->TextColor(TextColor.r, TextColor.g, TextColor.b, TextColor.a);
TextRender()->TextOutlineColor(ColorHighlightOutline.r,
ColorHighlightOutline.g,
ColorHighlightOutline.b,
ColorHighlightOutline.a);
TextRender()->TextEx(&Cursor, Line.m_aText, -1);
}
else
TextRender()->TextShadowed(&Cursor, Line.m_aText, -1, ShadowOffset, ShadowColor, TextColor);
}
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f);
}
void CChat::Say(int Mode, const char *pLine)

View file

@ -12,14 +12,15 @@ class CChat : public CComponent
enum
{
MAX_LINES = 25,
MAX_LINES = 50,
};
struct CLine
{
int64 m_Time;
float m_YOffset[2];
vec2 m_Size[2];
int m_ClientID;
int m_TargetID;
int m_Mode;
int m_NameColor;
char m_aName[64];
@ -74,7 +75,7 @@ public:
bool IsActive() const { return m_Mode != CHAT_NONE; }
void AddLine(int ClientID, int Team, const char *pLine);
void AddLine(int ClientID, int Team, const char *pLine, int TargetID = -1);
void EnableMode(int Team);

View file

@ -227,9 +227,15 @@ void CControls::ClampMousePos()
}
else
{
float CameraMaxDistance = 200.0f;
float FollowFactor = g_Config.m_ClMouseFollowfactor/100.0f;
float MouseMax = min(CameraMaxDistance/FollowFactor + g_Config.m_ClMouseDeadzone, (float)g_Config.m_ClMouseMaxDistance);
float MouseMax;
if(g_Config.m_ClDynamicCamera)
{
float CameraMaxDistance = 200.0f;
float FollowFactor = g_Config.m_ClMouseFollowfactor/100.0f;
MouseMax = min(CameraMaxDistance/FollowFactor + g_Config.m_ClMouseDeadzone, (float)g_Config.m_ClMouseMaxDistanceDynamic);
}
else
MouseMax = (float)g_Config.m_ClMouseMaxDistanceStatic;
if(length(m_MousePos) > MouseMax)
m_MousePos = normalize(m_MousePos)*MouseMax;

View file

@ -24,20 +24,20 @@ void CCountryFlags::LoadCountryflagsIndexfile()
return;
}
int FileSize = (int)io_length(File);
char *pFileData = (char *)mem_alloc(FileSize+1, 1);
char *pFileData = (char *)mem_alloc(FileSize, 1);
io_read(File, pFileData, FileSize);
pFileData[FileSize] = 0;
io_close(File);
// parse json data
json_settings JsonSettings;
mem_zero(&JsonSettings, sizeof(JsonSettings));
char aError[256];
json_value *pJsonData = json_parse_ex(&JsonSettings, pFileData, aError);
json_value *pJsonData = json_parse_ex(&JsonSettings, pFileData, FileSize, aError);
mem_free(pFileData);
if(pJsonData == 0)
{
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, pFilename, aError);
mem_free(pFileData);
return;
}
@ -60,14 +60,14 @@ void CCountryFlags::LoadCountryflagsIndexfile()
char aBuf[64];
// validate country code
int CountryCode = (long)rStart[i]["code"];
int CountryCode = (json_int_t)rStart[i]["code"];
if(CountryCode < CODE_LB || CountryCode > CODE_UB)
{
str_format(aBuf, sizeof(aBuf), "country code '%i' not within valid code range [%i..%i]", CountryCode, CODE_LB, CODE_UB);
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "countryflags", aBuf);
continue;
}
// add entry
const char *pCountryName = rStart[i]["id"];
CCountryFlag CountryFlag;
@ -89,7 +89,7 @@ void CCountryFlags::LoadCountryflagsIndexfile()
mem_free(Info.m_pData);
}
m_aCountryFlags.add_unsorted(CountryFlag);
// print message
if(g_Config.m_Debug)
{
@ -103,7 +103,6 @@ void CCountryFlags::LoadCountryflagsIndexfile()
// clean up
json_value_free(pJsonData);
mem_free(pFileData);
m_aCountryFlags.sort_range();
// find index of default item
@ -114,7 +113,7 @@ void CCountryFlags::LoadCountryflagsIndexfile()
DefaultIndex = Index;
break;
}
// init LUT
if(DefaultIndex != 0)
for(int i = 0; i < CODE_RANGE; ++i)
@ -162,7 +161,7 @@ void CCountryFlags::Render(int CountryCode, const vec4 *pColor, float x, float y
{
Graphics()->TextureSet(pFlag->m_Texture);
Graphics()->QuadsBegin();
Graphics()->SetColor(pColor->r, pColor->g, pColor->b, pColor->a);
Graphics()->SetColor(pColor->r*pColor->a, pColor->g*pColor->a, pColor->b*pColor->a, pColor->a);
IGraphics::CQuadItem QuadItem(x, y, w, h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();

View file

@ -70,7 +70,8 @@ void CDamageInd::OnRender()
else
{
vec2 Pos = mix(m_aItems[i].m_Pos+m_aItems[i].m_Dir*75.0f, m_aItems[i].m_Pos, clamp((Life-0.60f)/0.15f, 0.0f, 1.0f));
Graphics()->SetColor(1.0f,1.0f,1.0f, Life/0.1f);
const float Alpha = clamp(Life * 10.0f, 0.0f, 1.0f); // 0.1 -> 0.0 == 1.0 -> 0.0
Graphics()->SetColor(1.0f*Alpha, 1.0f*Alpha, 1.0f*Alpha, Alpha);
Graphics()->QuadsSetRotation(m_aItems[i].m_StartAngle + Life * 2.0f);
RenderTools()->SelectSprite(SPRITE_STAR1);
RenderTools()->DrawSprite(Pos.x, Pos.y, 48.0f);

View file

@ -155,11 +155,13 @@ void CEmoticon::OnRender()
Graphics()->QuadsEnd();
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CURSOR].m_Id);
Graphics()->WrapClamp();
Graphics()->QuadsBegin();
Graphics()->SetColor(1,1,1,1);
IGraphics::CQuadItem QuadItem(m_SelectorMouse.x+Screen.w/2,m_SelectorMouse.y+Screen.h/2,24,24);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
Graphics()->WrapNormal();
}
void CEmoticon::Emote(int Emoticon)

View file

@ -22,7 +22,7 @@ CHud::CHud()
{
// won't work if zero
m_AverageFPS = 1.0f;
m_WarmupHideTick = 0;
}
@ -109,7 +109,7 @@ void CHud::RenderStartCountdown()
if(m_pClient->m_Snap.m_pGameData->m_GameStateEndTick == 0)
return;
FontSize = 16.0f;
char aBuf[32];
int Seconds = (m_pClient->m_Snap.m_pGameData->m_GameStateEndTick-Client()->GameTick()+SERVER_TICK_SPEED-1)/SERVER_TICK_SPEED;
@ -209,9 +209,16 @@ void CHud::RenderScoreHud()
// draw name of the flag holder
int ID = FlagCarrier[t]%MAX_CLIENTS;
char aName[64];
str_format(aName, sizeof(aName), "%2d: %s", ID, g_Config.m_ClShowsocial ? m_pClient->m_aClients[ID].m_aName : "");
float w = TextRender()->TextWidth(0, 8.0f, aName, -1);
TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split), StartY+(t+1)*20.0f-3.0f, 8.0f, aName, -1);
str_format(aName, sizeof(aName), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[ID].m_aName : "");
float w = TextRender()->TextWidth(0, 8.0f, aName, -1) + RenderTools()->GetClientIdRectSize(8.0f);
CTextCursor Cursor;
float x = min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split);
float y = StartY+(t+1)*20.0f-3.0f;
TextRender()->SetCursor(&Cursor, x, y, 8.0f, TEXTFLAG_RENDER);
RenderTools()->DrawClientID(TextRender(), &Cursor, ID);
TextRender()->TextEx(&Cursor, aName, -1);
// draw tee of the flag holder
CTeeRenderInfo Info = m_pClient->m_aClients[ID].m_RenderInfo;
@ -279,19 +286,26 @@ void CHud::RenderScoreHud()
TextRender()->Text(0, Whole-ScoreWidthMax+(ScoreWidthMax-aScoreWidth[t])/2-Split, StartY+t*20, 14.0f, aScore[t], -1);
if(aPlayerInfo[t].m_pPlayerInfo)
{
{
// draw name
int ID = aPlayerInfo[t].m_ClientID;
char aName[64];
str_format(aName, sizeof(aName), "%2d: %s", ID, g_Config.m_ClShowsocial ? m_pClient->m_aClients[ID].m_aName : "");
str_format(aName, sizeof(aName), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[ID].m_aName : "");
float w = TextRender()->TextWidth(0, 8.0f, aName, -1);
TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split-PosSize), StartY+(t+1)*20.0f-3.0f, 8.0f, aName, -1);
CTextCursor Cursor;
float x = min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split-PosSize);
float y = StartY+(t+1)*20.0f-3.0f;
TextRender()->SetCursor(&Cursor, x, y, 8.0f, TEXTFLAG_RENDER);
RenderTools()->DrawClientID(TextRender(), &Cursor, ID);
TextRender()->TextEx(&Cursor, aName, -1);
// draw tee
CTeeRenderInfo Info = m_pClient->m_aClients[ID].m_RenderInfo;
Info.m_Size = 18.0f;
RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1,0),
vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, StartY+1.0f+Info.m_Size/2+t*20));
Info.m_Size = 18.0f;
RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1,0),
vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, StartY+1.0f+Info.m_Size/2+t*20));
}
// draw position
@ -314,7 +328,7 @@ void CHud::RenderWarmupTimer()
float FontSize = 20.0f;
float w = 0.0f;
const char *pText = Localize("Warmup");
if(m_WarmupHideTick == 0 || (time_get() - m_WarmupHideTick) / time_freq() < 10)
{
w = TextRender()->TextWidth(0, FontSize, pText, -1);
@ -325,7 +339,7 @@ void CHud::RenderWarmupTimer()
TextRender()->TextColor(1, 1, 0.5f, 1);
TextRender()->Text(0x0, 10, 45, 8, pText, -1);
}
FontSize = 16.0f;
if(m_pClient->m_Snap.m_pGameData->m_GameStateEndTick == 0)
{
@ -348,7 +362,7 @@ void CHud::RenderWarmupTimer()
else
str_format(aBuf, sizeof(aBuf), "%d", round_to_int(Seconds));
}
if(m_WarmupHideTick == 0 || (time_get() - m_WarmupHideTick) / time_freq() < 10)
{
w = TextRender()->TextWidth(0, FontSize, aBuf, -1);
@ -452,7 +466,8 @@ void CHud::RenderCursor()
if(!m_pClient->m_Snap.m_pLocalCharacter || Client()->State() == IClient::STATE_DEMOPLAYBACK)
return;
RenderTools()->MapScreenToGroup(m_pClient->m_pCamera->m_Center.x, m_pClient->m_pCamera->m_Center.y, Layers()->GameGroup(), m_pClient->m_pCamera->m_Zoom);
vec2 Pos = *m_pClient->m_pCamera->GetCenter();
RenderTools()->MapScreenToGroup(Pos.x, Pos.y, Layers()->GameGroup(), m_pClient->m_pCamera->GetZoom());
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->QuadsBegin();
@ -463,6 +478,75 @@ void CHud::RenderCursor()
Graphics()->QuadsEnd();
}
void CHud::RenderNinjaBar(float x, float y, float Progress)
{
Progress = clamp(Progress, 0.0f, 1.0f);
const float EndWidth = 6.0f;
const float BarHeight = 12.0f;
const float WholeBarWidth = 120.f;
const float MiddleBarWidth = WholeBarWidth - (EndWidth * 2.0f);
IGraphics::CQuadItem QuadStartFull(x, y, EndWidth, BarHeight);
RenderTools()->SelectSprite(&g_pData->m_aSprites[SPRITE_NINJA_BAR_FULL_LEFT]);
Graphics()->QuadsDrawTL(&QuadStartFull, 1);
x += EndWidth;
const float FullBarWidth = MiddleBarWidth * Progress;
const float EmptyBarWidth = MiddleBarWidth - FullBarWidth;
// full bar
IGraphics::CQuadItem QuadFull(x, y, FullBarWidth, BarHeight);
CDataSprite SpriteBarFull = g_pData->m_aSprites[SPRITE_NINJA_BAR_FULL];
// prevent pixel puree, select only a small slice
if(Progress < 0.1f)
{
int spx = SpriteBarFull.m_X;
int spy = SpriteBarFull.m_Y;
float w = SpriteBarFull.m_W * 0.1f; // magic here
int h = SpriteBarFull.m_H;
int cx = SpriteBarFull.m_pSet->m_Gridx;
int cy = SpriteBarFull.m_pSet->m_Gridy;
float x1 = spx/(float)cx;
float x2 = (spx+w-1/32.0f)/(float)cx;
float y1 = spy/(float)cy;
float y2 = (spy+h-1/32.0f)/(float)cy;
Graphics()->QuadsSetSubset(x1, y1, x2, y2);
}
else
RenderTools()->SelectSprite(&SpriteBarFull);
Graphics()->QuadsDrawTL(&QuadFull, 1);
// empty bar
// select the middle portion of the sprite so we don't get edge bleeding
const CDataSprite SpriteBarEmpty = g_pData->m_aSprites[SPRITE_NINJA_BAR_EMPTY];
{
float spx = SpriteBarEmpty.m_X + 0.1f;
float spy = SpriteBarEmpty.m_Y;
float w = SpriteBarEmpty.m_W * 0.5f;
int h = SpriteBarEmpty.m_H;
int cx = SpriteBarEmpty.m_pSet->m_Gridx;
int cy = SpriteBarEmpty.m_pSet->m_Gridy;
float x1 = spx/(float)cx;
float x2 = (spx+w-1/32.0f)/(float)cx;
float y1 = spy/(float)cy;
float y2 = (spy+h-1/32.0f)/(float)cy;
Graphics()->QuadsSetSubset(x1, y1, x2, y2);
}
IGraphics::CQuadItem QuadEmpty(x + FullBarWidth, y, EmptyBarWidth, BarHeight);
Graphics()->QuadsDrawTL(&QuadEmpty, 1);
x += MiddleBarWidth;
IGraphics::CQuadItem QuadEndEmpty(x, y, EndWidth, BarHeight);
RenderTools()->SelectSprite(&g_pData->m_aSprites[SPRITE_NINJA_BAR_EMPTY_RIGHT]);
Graphics()->QuadsDrawTL(&QuadEndEmpty, 1);
}
void CHud::RenderHealthAndAmmo(const CNetObj_Character *pCharacter)
{
if(!pCharacter)
@ -473,33 +557,32 @@ void CHud::RenderHealthAndAmmo(const CNetObj_Character *pCharacter)
int i;
IGraphics::CQuadItem Array[10];
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->WrapClamp();
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
// render ammo
if(pCharacter->m_Weapon == WEAPON_NINJA)
{
CUIRect Rect = {x, y+24.0f, 118.0f, 10.0f};
RenderTools()->DrawUIRect(&Rect, vec4(0.8f, 0.8f, 0.8f, 0.5f), 0, 0.0f);
int Max = g_pData->m_Weapons.m_Ninja.m_Duration * Client()->GameTickSpeed() / 1000;
Rect.x = x+1.0f;
Rect.y = y+25.0f;
Rect.w = 116.0f * clamp(pCharacter->m_AmmoCount-Client()->GameTick(), 0, Max) / Max;
Rect.h = 8.0f;
RenderTools()->DrawUIRect(&Rect, vec4(0.9f, 0.2f, 0.2f, 0.85f), 0, 0.0f);
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[WEAPON_NINJA].m_pSpriteBody);
Array[0] = IGraphics::CQuadItem(x+40.0f,y+25, 32.0f, 8.0f);
Graphics()->QuadsDrawTL(Array, 1);
const int Max = g_pData->m_Weapons.m_Ninja.m_Duration * Client()->GameTickSpeed() / 1000;
float NinjaProgress = clamp(pCharacter->m_AmmoCount-Client()->GameTick(), 0, Max) / (float)Max;
RenderNinjaBar(x, y+24.f, NinjaProgress);
}
else
{
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->QuadsBegin();
RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[pCharacter->m_Weapon%NUM_WEAPONS].m_pSpriteProj);
for(i = 0; i < min(pCharacter->m_AmmoCount, 10); i++)
Array[i] = IGraphics::CQuadItem(x+i*12,y+24,10,10);
if(pCharacter->m_Weapon == WEAPON_GRENADE)
{
for(i = 0; i < min(pCharacter->m_AmmoCount, 10); i++)
Array[i] = IGraphics::CQuadItem(x+1+i*12, y+24, 10, 10);
}
else
{
for(i = 0; i < min(pCharacter->m_AmmoCount, 10); i++)
Array[i] = IGraphics::CQuadItem(x+i*12, y+24, 12, 12);
}
Graphics()->QuadsDrawTL(Array, i);
}
@ -508,28 +591,29 @@ void CHud::RenderHealthAndAmmo(const CNetObj_Character *pCharacter)
// render health
RenderTools()->SelectSprite(SPRITE_HEALTH_FULL);
for(; h < min(pCharacter->m_Health, 10); h++)
Array[h] = IGraphics::CQuadItem(x+h*12,y,10,10);
Array[h] = IGraphics::CQuadItem(x+h*12,y,12,12);
Graphics()->QuadsDrawTL(Array, h);
i = 0;
RenderTools()->SelectSprite(SPRITE_HEALTH_EMPTY);
for(; h < 10; h++)
Array[i++] = IGraphics::CQuadItem(x+h*12,y,10,10);
Array[i++] = IGraphics::CQuadItem(x+h*12,y,12,12);
Graphics()->QuadsDrawTL(Array, i);
// render armor meter
h = 0;
RenderTools()->SelectSprite(SPRITE_ARMOR_FULL);
for(; h < min(pCharacter->m_Armor, 10); h++)
Array[h] = IGraphics::CQuadItem(x+h*12,y+12,10,10);
Array[h] = IGraphics::CQuadItem(x+h*12,y+12,12,12);
Graphics()->QuadsDrawTL(Array, h);
i = 0;
RenderTools()->SelectSprite(SPRITE_ARMOR_EMPTY);
for(; h < 10; h++)
Array[i++] = IGraphics::CQuadItem(x+h*12,y+12,10,10);
Array[i++] = IGraphics::CQuadItem(x+h*12,y+12,12,12);
Graphics()->QuadsDrawTL(Array, i);
Graphics()->QuadsEnd();
Graphics()->WrapNormal();
}
void CHud::RenderSpectatorHud()
@ -540,28 +624,41 @@ void CHud::RenderSpectatorHud()
// draw the text
char aName[64];
str_format(aName, sizeof(aName), "%2d: %s", m_pClient->m_Snap.m_SpecInfo.m_SpectatorID, g_Config.m_ClShowsocial ? m_pClient->m_aClients[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID].m_aName : "");
const int SpecID = m_pClient->m_Snap.m_SpecInfo.m_SpectatorID;
const int SpecMode = m_pClient->m_Snap.m_SpecInfo.m_SpecMode;
str_format(aName, sizeof(aName), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID].m_aName : "");
char aBuf[128];
switch(m_pClient->m_Snap.m_SpecInfo.m_SpecMode)
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, m_Width-174.0f, m_Height-13.0f, 8.0f, TEXTFLAG_RENDER);
str_format(aBuf, sizeof(aBuf), "%s: ", Localize("Spectate"));
TextRender()->TextEx(&Cursor, aBuf, -1);
switch(SpecMode)
{
case SPEC_FREEVIEW:
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), Localize("Free-View"));
str_format(aBuf, sizeof(aBuf), "%s", Localize("Free-View"));
break;
case SPEC_PLAYER:
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), aName);
str_format(aBuf, sizeof(aBuf), "%s", aName);
break;
case SPEC_FLAGRED:
case SPEC_FLAGBLUE:
char aFlag[64];
str_format(aFlag, sizeof(aFlag), m_pClient->m_Snap.m_SpecInfo.m_SpecMode == SPEC_FLAGRED ? Localize("red flag") : Localize("blue flag"));
str_format(aFlag, sizeof(aFlag), SpecMode == SPEC_FLAGRED ? Localize("red flag") : Localize("blue flag"));
if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != -1)
str_format(aBuf, sizeof(aBuf), "%s: %s (%s)", Localize("Spectate"), aFlag, aName);
if(SpecID != -1)
str_format(aBuf, sizeof(aBuf), "%s (%s)", aFlag, aName);
else
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), aFlag);
str_format(aBuf, sizeof(aBuf), "%s", aFlag);
break;
}
TextRender()->Text(0, m_Width-174.0f, m_Height-13.0f, 8.0f, aBuf, -1);
if(SpecMode == SPEC_PLAYER || SpecID != -1)
RenderTools()->DrawClientID(TextRender(), &Cursor, SpecID);
TextRender()->TextEx(&Cursor, aBuf, -1);
}
void CHud::OnRender()

View file

@ -16,6 +16,7 @@ class CHud : public CComponent
void RenderConnectionWarning();
void RenderTeambalanceWarning();
void RenderVoting();
void RenderNinjaBar(float x, float y, float Progress);
void RenderHealthAndAmmo(const CNetObj_Character *pCharacter);
void RenderGameTimer();
void RenderPauseTimer();

View file

@ -27,11 +27,11 @@ void CKillMessages::OnMessage(int MsgType, void *pRawMsg)
CKillMsg Kill;
Kill.m_VictimID = pMsg->m_Victim;
Kill.m_VictimTeam = m_pClient->m_aClients[Kill.m_VictimID].m_Team;
str_format(Kill.m_aVictimName, sizeof(Kill.m_aVictimName), "%2d: %s", pMsg->m_Victim, g_Config.m_ClShowsocial ? m_pClient->m_aClients[Kill.m_VictimID].m_aName : "");
str_format(Kill.m_aVictimName, sizeof(Kill.m_aVictimName), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[Kill.m_VictimID].m_aName : "");
Kill.m_VictimRenderInfo = m_pClient->m_aClients[Kill.m_VictimID].m_RenderInfo;
Kill.m_KillerID = pMsg->m_Killer;
Kill.m_KillerTeam = m_pClient->m_aClients[Kill.m_KillerID].m_Team;
str_format(Kill.m_aKillerName, sizeof(Kill.m_aKillerName), "%2d: %s", pMsg->m_Killer, g_Config.m_ClShowsocial ? m_pClient->m_aClients[Kill.m_KillerID].m_aName : "");
str_format(Kill.m_aKillerName, sizeof(Kill.m_aKillerName), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[Kill.m_KillerID].m_aName : "");
Kill.m_KillerRenderInfo = m_pClient->m_aClients[Kill.m_KillerID].m_RenderInfo;
Kill.m_Weapon = pMsg->m_Weapon;
Kill.m_ModeSpecial = pMsg->m_ModeSpecial;
@ -59,14 +59,18 @@ void CKillMessages::OnRender()
continue;
float FontSize = 36.0f;
float KillerNameW = TextRender()->TextWidth(0, FontSize, m_aKillmsgs[r].m_aKillerName, -1);
float VictimNameW = TextRender()->TextWidth(0, FontSize, m_aKillmsgs[r].m_aVictimName, -1);
float KillerNameW = TextRender()->TextWidth(0, FontSize, m_aKillmsgs[r].m_aKillerName, -1) + RenderTools()->GetClientIdRectSize(FontSize);
float VictimNameW = TextRender()->TextWidth(0, FontSize, m_aKillmsgs[r].m_aVictimName, -1) + RenderTools()->GetClientIdRectSize(FontSize);
float x = StartX;
// render victim name
x -= VictimNameW;
TextRender()->Text(0, x, y, FontSize, m_aKillmsgs[r].m_aVictimName, -1);
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER);
RenderTools()->DrawClientID(TextRender(), &Cursor, m_aKillmsgs[r].m_VictimID);
TextRender()->TextEx(&Cursor, m_aKillmsgs[r].m_aVictimName, -1);
// render victim tee
x -= 24.0f;
@ -135,7 +139,10 @@ void CKillMessages::OnRender()
// render killer name
x -= KillerNameW;
TextRender()->Text(0, x, y, FontSize, m_aKillmsgs[r].m_aKillerName, -1);
TextRender()->SetCursor(&Cursor, x, y, FontSize, TEXTFLAG_RENDER);
RenderTools()->DrawClientID(TextRender(), &Cursor, m_aKillmsgs[r].m_KillerID);
TextRender()->TextEx(&Cursor, m_aKillmsgs[r].m_aKillerName, -1);
}
y += 46.0f;

View file

@ -28,18 +28,39 @@ CMapLayers::CMapLayers(int t)
m_EnvelopeUpdate = false;
m_pMenuMap = 0;
m_pMenuLayers = 0;
m_OnlineStartTime = 0;
}
void CMapLayers::OnStateChange(int NewState, int OldState)
{
if(NewState == IClient::STATE_ONLINE)
m_OnlineStartTime = Client()->LocalTime(); // reset time for non-scynchronized envelopes
}
void CMapLayers::LoadBackgroundMap()
{
if(!g_Config.m_ClShowMenuMap)
return;
int HourOfTheDay = time_houroftheday();
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "ui/%s_%s.map", g_Config.m_ClMenuMap, (HourOfTheDay >= 6 && HourOfTheDay < 18) ? "day" : "night");
// check for the appropriate day/night map
str_format(aBuf, sizeof(aBuf), "ui/themes/%s_%s.map", g_Config.m_ClMenuMap, (HourOfTheDay >= 6 && HourOfTheDay < 18) ? "day" : "night");
if(!m_pMenuMap->Load(aBuf, m_pClient->Storage()))
{
str_format(aBuf, sizeof(aBuf), "map '%s' not found", g_Config.m_ClMenuMap);
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf);
return;
// fall back on generic map
str_format(aBuf, sizeof(aBuf), "ui/themes/%s.map", g_Config.m_ClMenuMap);
if(!m_pMenuMap->Load(aBuf, m_pClient->Storage()))
{
// fall back on day/night alternative map
str_format(aBuf, sizeof(aBuf), "ui/themes/%s_%s.map", g_Config.m_ClMenuMap, (HourOfTheDay >= 6 && HourOfTheDay < 18) ? "night" : "day");
if(!m_pMenuMap->Load(aBuf, m_pClient->Storage()))
{
str_format(aBuf, sizeof(aBuf), "map '%s' not found", g_Config.m_ClMenuMap);
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf);
return;
}
}
}
str_format(aBuf, sizeof(aBuf), "loaded map '%s'", g_Config.m_ClMenuMap);
@ -89,7 +110,7 @@ void CMapLayers::LoadEnvPoints(const CLayers *pLayers, array<CEnvPoint>& lEnvPoi
pLayers->Map()->GetType(MAPITEMTYPE_ENVELOPE, &Start, &Num);
if(!Num)
return;
for(int env = 0; env < Num; env++)
{
@ -167,14 +188,13 @@ void CMapLayers::EnvelopeEval(float TimeOffset, int Env, float *pChannels, void
if(Env >= Num)
return;
CMapItemEnvelope *pItem = (CMapItemEnvelope *)pLayers->Map()->GetItem(Start+Env, 0, 0);
CMapItemEnvelope *pItem = (CMapItemEnvelope *)pLayers->Map()->GetItem(Start+Env, 0, 0);
static float s_Time = 0.0f;
static float s_LastLocalTime = pThis->Client()->LocalTime();
float Time = 0.0f;
if(pThis->Client()->State() == IClient::STATE_DEMOPLAYBACK)
{
const IDemoPlayer::CInfo *pInfo = pThis->DemoPlayer()->BaseInfo();
if(!pInfo->m_Paused || pThis->m_EnvelopeUpdate)
{
if(pThis->m_CurrentLocalTick != pInfo->m_CurrentTick)
@ -183,12 +203,12 @@ void CMapLayers::EnvelopeEval(float TimeOffset, int Env, float *pChannels, void
pThis->m_CurrentLocalTick = pInfo->m_CurrentTick;
}
s_Time = mix(pThis->m_LastLocalTick / (float)pThis->Client()->GameTickSpeed(),
Time = mix(pThis->m_LastLocalTick / (float)pThis->Client()->GameTickSpeed(),
pThis->m_CurrentLocalTick / (float)pThis->Client()->GameTickSpeed(),
pThis->Client()->IntraGameTick());
}
pThis->RenderTools()->RenderEvalEnvelope(pPoints + pItem->m_StartPoint, pItem->m_NumPoints, 4, s_Time+TimeOffset, pChannels);
pThis->RenderTools()->RenderEvalEnvelope(pPoints + pItem->m_StartPoint, pItem->m_NumPoints, 4, Time+TimeOffset, pChannels);
}
else if(pThis->Client()->State() != IClient::STATE_OFFLINE)
{
@ -196,20 +216,20 @@ void CMapLayers::EnvelopeEval(float TimeOffset, int Env, float *pChannels, void
{
if(pItem->m_Version < 2 || pItem->m_Synchronized)
{
s_Time = mix((pThis->Client()->PrevGameTick()-pThis->m_pClient->m_Snap.m_pGameData->m_GameStartTick) / (float)pThis->Client()->GameTickSpeed(),
Time = mix((pThis->Client()->PrevGameTick()-pThis->m_pClient->m_Snap.m_pGameData->m_GameStartTick) / (float)pThis->Client()->GameTickSpeed(),
(pThis->Client()->GameTick()-pThis->m_pClient->m_Snap.m_pGameData->m_GameStartTick) / (float)pThis->Client()->GameTickSpeed(),
pThis->Client()->IntraGameTick());
}
else
s_Time += pThis->Client()->LocalTime()-s_LastLocalTime;
Time = pThis->Client()->LocalTime()-pThis->m_OnlineStartTime;
}
pThis->RenderTools()->RenderEvalEnvelope(pPoints + pItem->m_StartPoint, pItem->m_NumPoints, 4, s_Time+TimeOffset, pChannels);
s_LastLocalTime = pThis->Client()->LocalTime();
pThis->RenderTools()->RenderEvalEnvelope(pPoints + pItem->m_StartPoint, pItem->m_NumPoints, 4, Time+TimeOffset, pChannels);
}
else
{
s_Time = pThis->Client()->LocalTime();
pThis->RenderTools()->RenderEvalEnvelope(pPoints + pItem->m_StartPoint, pItem->m_NumPoints, 4, s_Time+TimeOffset, pChannels);
Time = pThis->Client()->LocalTime();
pThis->RenderTools()->RenderEvalEnvelope(pPoints + pItem->m_StartPoint, pItem->m_NumPoints, 4, Time+TimeOffset, pChannels);
}
}
@ -230,7 +250,7 @@ void CMapLayers::OnRender()
CUIRect Screen;
Graphics()->GetScreen(&Screen.x, &Screen.y, &Screen.w, &Screen.h);
vec2 Center = m_pClient->m_pCamera->m_Center;
vec2 Center = *m_pClient->m_pCamera->GetCenter();
bool PassedGameLayer = false;
@ -242,13 +262,13 @@ void CMapLayers::OnRender()
{
// set clipping
float Points[4];
RenderTools()->MapScreenToGroup(Center.x, Center.y, pLayers->GameGroup(), m_pClient->m_pCamera->m_Zoom);
RenderTools()->MapScreenToGroup(Center.x, Center.y, pLayers->GameGroup(), m_pClient->m_pCamera->GetZoom());
Graphics()->GetScreen(&Points[0], &Points[1], &Points[2], &Points[3]);
float x0 = (pGroup->m_ClipX - Points[0]) / (Points[2]-Points[0]);
float y0 = (pGroup->m_ClipY - Points[1]) / (Points[3]-Points[1]);
float x1 = ((pGroup->m_ClipX+pGroup->m_ClipW) - Points[0]) / (Points[2]-Points[0]);
float y1 = ((pGroup->m_ClipY+pGroup->m_ClipH) - Points[1]) / (Points[3]-Points[1]);
if(x1 < 0.0f || x0 > 1.0f || y1 < 0.0f || y0 > 1.0f)
continue;
@ -256,7 +276,7 @@ void CMapLayers::OnRender()
(int)((x1-x0)*Graphics()->ScreenWidth()), (int)((y1-y0)*Graphics()->ScreenHeight()));
}
RenderTools()->MapScreenToGroup(Center.x, Center.y, pGroup, m_pClient->m_pCamera->m_Zoom);
RenderTools()->MapScreenToGroup(Center.x, Center.y, pGroup, m_pClient->m_pCamera->GetZoom());
for(int l = 0; l < pGroup->m_NumLayers; l++)
{
@ -366,6 +386,7 @@ void CMapLayers::ConchainBackgroundMap(IConsole::IResult *pResult, void *pUserDa
void CMapLayers::OnConsoleInit()
{
Console()->Chain("cl_menu_map", ConchainBackgroundMap, this);
Console()->Chain("cl_show_menu_map", ConchainBackgroundMap, this);
}
void CMapLayers::BackgroundMapUpdate()

View file

@ -13,6 +13,7 @@ class CMapLayers : public CComponent
int m_Type;
int m_CurrentLocalTick;
int m_LastLocalTick;
float m_OnlineStartTime;
bool m_EnvelopeUpdate;
array<CEnvPoint> m_lEnvPoints;
@ -20,8 +21,8 @@ class CMapLayers : public CComponent
static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser);
void LoadBackgroundMap();
void LoadEnvPoints(const CLayers *pLayers, array<CEnvPoint>& lEnvPoints);
void LoadBackgroundMap();
public:
enum
@ -31,6 +32,7 @@ public:
};
CMapLayers(int Type);
virtual void OnStateChange(int NewState, int OldState);
virtual void OnInit();
virtual void OnRender();
virtual void OnMapLoad();

View file

@ -34,8 +34,9 @@
#include "skins.h"
float CMenus::ms_ButtonHeight = 25.0f;
float CMenus::ms_ListheaderHeight = 20.0f;
float CMenus::ms_ListheaderHeight = 17.0f;
float CMenus::ms_FontmodHeight = 0.8f;
float CMenus::ms_BackgroundAlpha = 0.25f;
CMenus::CMenus()
@ -44,6 +45,9 @@ CMenus::CMenus()
m_NextPopup = POPUP_NONE;
m_ActivePage = PAGE_INTERNET;
m_GamePage = PAGE_GAME;
m_SidebarTab = 0;
m_SidebarActive = true;
m_ShowServerDetails = true;
m_NeedRestartGraphics = false;
m_NeedRestartSound = false;
@ -58,38 +62,36 @@ CMenus::CMenus()
SetMenuPage(PAGE_START);
m_InfoMode = false;
m_PopupActive = false;
m_EscapePressed = false;
m_EnterPressed = false;
m_TabPressed = false;
m_DeletePressed = false;
m_UpArrowPressed = false;
m_DownArrowPressed = false;
m_LastInput = time_get();
str_copy(m_aCurrentDemoFolder, "demos", sizeof(m_aCurrentDemoFolder));
m_aCallvoteReason[0] = 0;
m_FriendlistSelectedIndex = -1;
m_SelectedFilter = 0;
m_SelectedServer.m_Filter = -1;
m_SelectedServer.m_Index = -1;
m_ActiveListBox = ACTLB_THEME;
}
float CMenus::ButtonFade(CButtonContainer *pBC, float Seconds, int Checked)
{
if (UI()->HotItem() == pBC->GetID() || Checked)
if(UI()->HotItem() == pBC->GetID() || Checked)
{
pBC->m_FadeStartTime = Client()->LocalTime();
return Seconds;
}
else if (pBC->m_FadeStartTime + Seconds > Client()->LocalTime())
{
return pBC->m_FadeStartTime + Seconds - Client()->LocalTime();
}
return 0.0f;
return max(0.0f, pBC->m_FadeStartTime - Client()->LocalTime() + Seconds);
}
int CMenus::DoIcon(int ImageId, int SpriteId, const CUIRect *pRect)
@ -216,24 +218,38 @@ int CMenus::DoButton_MenuTab(const void *pID, const char *pText, int Checked, co
return UI()->DoButtonLogic(pID, pText, Checked, pRect);
}
int CMenus::DoButton_MenuTabTop(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, int Corners, float r, float FontFactor)
int CMenus::DoButton_MenuTabTop(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, float Alpha, float FontAlpha, int Corners, float r, float FontFactor)
{
if(UI()->MouseInside(pRect))
Alpha = 1.0f;
float Seconds = 0.6f; // 0.6 seconds for fade
float Fade = ButtonFade(pBC, Seconds, Checked);
float FadeVal = Fade/Seconds;
float FadeVal = (Fade/Seconds)*FontAlpha;
RenderTools()->DrawUIRect(pRect, vec4(0.0f+FadeVal, 0.0f+FadeVal, 0.0f+FadeVal, 0.25f+FadeVal*0.5f), Corners, r);
RenderTools()->DrawUIRect(pRect, vec4(0.0f+FadeVal, 0.0f+FadeVal, 0.0f+FadeVal, 0.25f*Alpha+FadeVal*0.5f), Corners, r);
CUIRect Temp;
pRect->HMargin(pRect->h>=20.0f?2.0f:1.0f, &Temp);
Temp.HMargin((Temp.h*FontFactor)/2.0f, &Temp);
TextRender()->TextColor(1.0f-FadeVal, 1.0f-FadeVal, 1.0f-FadeVal, 1.0f);
TextRender()->TextOutlineColor(0.0f+FadeVal, 0.0f+FadeVal, 0.0f+FadeVal, 0.25f);
TextRender()->TextColor(1.0f-FadeVal, 1.0f-FadeVal, 1.0f-FadeVal, FontAlpha);
TextRender()->TextOutlineColor(0.0f+FadeVal, 0.0f+FadeVal, 0.0f+FadeVal, 0.25f*FontAlpha);
UI()->DoLabel(&Temp, pText, Temp.h*ms_FontmodHeight, CUI::ALIGN_CENTER);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f);
return UI()->DoButtonLogic(pBC->GetID(), pText, Checked, pRect);
}
void CMenus::DoButton_MenuTabTop_Dummy(const char *pText, int Checked, const CUIRect *pRect, float Alpha)
{
RenderTools()->DrawUIRect(pRect, vec4(0.0f, 0.0f, 0.0f, 0.25f*Alpha), CUI::CORNER_ALL, 5.0f);
CUIRect Temp;
pRect->HMargin(pRect->h >= 20.0f ? 2.0f : 1.0f, &Temp);
TextRender()->TextColor(0.15f, 0.15f, 0.15f, Alpha);
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.25f*Alpha);
UI()->DoLabel(&Temp, pText, Temp.h*ms_FontmodHeight, CUI::ALIGN_CENTER);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f);
}
int CMenus::DoButton_GridHeader(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
//void CMenus::ui_draw_grid_header(const void *id, const char *text, int checked, const CUIRect *r, const void *extra)
{
@ -304,7 +320,7 @@ int CMenus::DoButton_CheckBox_Common(const void *pID, const char *pText, const c
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
t.y += 2.0f; // lame fix
t.y += 1.0f; // lame fix
UI()->DoLabel(&c, pBoxText, pRect->h*ms_FontmodHeight*0.6f, CUI::ALIGN_CENTER);
UI()->DoLabel(&t, pText, pRect->h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
return UI()->DoButtonLogic(pID, pText, 0, pRect);
@ -322,18 +338,19 @@ int CMenus::DoButton_CheckBox_Number(const void *pID, const char *pText, int Che
return DoButton_CheckBox_Common(pID, pText, aBuf, pRect);
}
int CMenus::DoButton_SpriteID(CButtonContainer *pBC, int ImageID, int SpriteID, const CUIRect *pRect, int Corners, float r, bool Fade)
int CMenus::DoButton_SpriteID(CButtonContainer *pBC, int ImageID, int SpriteID, bool Checked, const CUIRect *pRect, int Corners, float r, bool Fade)
{
float Seconds = 0.6f; // 0.6 seconds for fade
float FadeVal = ButtonFade(pBC, Seconds)/Seconds;
float FadeVal = Fade ? ButtonFade(pBC, Seconds, Checked) / Seconds : 0.0f;
RenderTools()->DrawUIRect(pRect, vec4(0.0f + FadeVal, 0.0f + FadeVal, 0.0f + FadeVal, 0.25f + FadeVal * 0.5f), Corners, r);
CUIRect Icon = *pRect;
if(Icon.w > Icon.h)
Icon.VMargin((Icon.w - Icon.h) / 2, &Icon);
else if(Icon.w < Icon.h)
Icon.HMargin((Icon.h - Icon.w) / 2, &Icon);
Icon.Margin(2.0f, &Icon);
if(Fade)
RenderTools()->DrawUIRect(pRect, vec4(0.0f+FadeVal, 0.0f+FadeVal, 0.0f+FadeVal, 0.25f+FadeVal*0.5f), Corners, r);
else
RenderTools()->DrawUIRect(pRect, vec4(0.0f, 0.0f, 0.0f, 0.25f), Corners, r);
Graphics()->TextureSet(g_pData->m_aImages[ImageID].m_Id);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
@ -634,6 +651,50 @@ float CMenus::DoDropdownMenu(void *pID, const CUIRect *pRect, const char *pStr,
return HeaderHeight;
}
float CMenus::DoIndependentDropdownMenu(void *pID, const CUIRect *pRect, const char *pStr, float HeaderHeight, FDropdownCallback pfnCallback, bool* pActive)
{
CUIRect View = *pRect;
CUIRect Header, Label;
bool Active = *pActive;
int Corners = Active ? CUI::CORNER_T : CUI::CORNER_ALL;
View.HSplitTop(HeaderHeight, &Header, &View);
// background
RenderTools()->DrawUIRect(&Header, vec4(0.0f, 0.0f, 0.0f, 0.25f), Corners, 5.0f);
// render icon
CUIRect Button;
Header.VSplitLeft(Header.h, &Button, 0);
Button.Margin(2.0f, &Button);
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_MENUICONS].m_Id);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 1.0f, 1.0f, UI()->HotItem() == pID ? 1.0f : 0.6f);
if(Active)
RenderTools()->SelectSprite(SPRITE_MENU_EXPANDED);
else
RenderTools()->SelectSprite(SPRITE_MENU_COLLAPSED);
IGraphics::CQuadItem QuadItem(Button.x, Button.y, Button.w, Button.h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
Graphics()->QuadsEnd();
// label
Label = Header;
Label.y += 2.0f;
UI()->DoLabel(&Label, pStr, Header.h*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
if(UI()->DoButtonLogic(pID, 0, 0, &Header))
*pActive ^= 1;
// render content of expanded menu
if(Active)
return HeaderHeight + pfnCallback(View, this);
return HeaderHeight;
}
void CMenus::DoInfoBox(const CUIRect *pRect, const char *pLabel, const char *pValue)
{
RenderTools()->DrawUIRect(pRect, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
@ -913,8 +974,8 @@ CMenus::CListboxItem CMenus::UiDoListboxNextItem(CListBoxState* pState, const vo
else
{
int NewIndex = -1;
if(Input()->KeyPress(KEY_DOWN)) NewIndex = pState->m_ListBoxNewSelected + 1;
if(Input()->KeyPress(KEY_UP)) NewIndex = pState->m_ListBoxNewSelected - 1;
if(m_DownArrowPressed) NewIndex = pState->m_ListBoxNewSelected + 1;
if(m_UpArrowPressed) NewIndex = pState->m_ListBoxNewSelected - 1;
if(NewIndex > -1 && NewIndex < pState->m_ListBoxNumItems)
{
// scroll
@ -967,7 +1028,7 @@ int CMenus::DoKeyReader(CButtonContainer *pBC, const CUIRect *pRect, int Key, in
static const void *pGrabbedID = 0;
static bool MouseReleased = true;
static int ButtonUsed = 0;
int Inside = UI()->MouseInside(pRect);
int Inside = UI()->MouseInside(pRect) && UI()->MouseInsideClip();
int NewKey = Key;
*NewModifier = Modifier;
@ -1037,10 +1098,12 @@ int CMenus::DoKeyReader(CButtonContainer *pBC, const CUIRect *pRect, int Key, in
return NewKey;
}
void CMenus::RenderMenubar(CUIRect r)
void CMenus::RenderMenubar(CUIRect Rect)
{
CUIRect Box = r;
CUIRect Box;
CUIRect Button;
Rect.HSplitTop(60.0f, &Box, &Rect);
const float InactiveAlpha = 0.25f;
m_ActivePage = m_MenuPage;
int NewPage = -1;
@ -1048,6 +1111,55 @@ void CMenus::RenderMenubar(CUIRect r)
if(Client()->State() != IClient::STATE_OFFLINE)
m_ActivePage = m_GamePage;
if(Client()->State() == IClient::STATE_ONLINE)
{
float Spacing = 3.0f;
float ButtonWidth = (Box.w / 6.0f) - (Spacing*5.0) / 6.0f;
float Alpha = 1.0f;
if(m_GamePage == PAGE_SETTINGS)
Alpha = InactiveAlpha;
// render header backgrounds
CUIRect Left, Right;
Box.VSplitLeft(ButtonWidth*4.0f + Spacing * 3.0f, &Left, 0);
Box.VSplitRight(ButtonWidth, 0, &Right);
RenderTools()->DrawUIRect4(&Left, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.25f), vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 5.0f);
RenderTools()->DrawUIRect4(&Right, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.25f), vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 5.0f);
Left.HSplitBottom(25.0f, 0, &Left);
Right.HSplitBottom(25.0f, 0, &Right);
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_GameButton;
if(DoButton_MenuTabTop(&s_GameButton, Localize("Game"), m_ActivePage == PAGE_GAME, &Button, Alpha, Alpha))
NewPage = PAGE_GAME;
Left.VSplitLeft(Spacing, 0, &Left); // little space
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_PlayersButton;
if(DoButton_MenuTabTop(&s_PlayersButton, Localize("Players"), m_ActivePage == PAGE_PLAYERS, &Button, Alpha, Alpha))
NewPage = PAGE_PLAYERS;
Left.VSplitLeft(Spacing, 0, &Left); // little space
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_ServerInfoButton;
if(DoButton_MenuTabTop(&s_ServerInfoButton, Localize("Server info"), m_ActivePage == PAGE_SERVER_INFO, &Button, Alpha, Alpha))
NewPage = PAGE_SERVER_INFO;
Left.VSplitLeft(Spacing, 0, &Left); // little space
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_CallVoteButton;
if(DoButton_MenuTabTop(&s_CallVoteButton, Localize("Call vote"), m_ActivePage == PAGE_CALLVOTE, &Button, Alpha, Alpha))
NewPage = PAGE_CALLVOTE;
static CButtonContainer s_SettingsButton;
if(DoButton_MenuTabTop(&s_SettingsButton, Localize("Settings"), m_GamePage == PAGE_SETTINGS, &Right))
NewPage = PAGE_SETTINGS;
Rect.HSplitTop(Spacing, 0, &Rect);
Rect.HSplitTop(25.0f, &Box, &Rect);
}
if((Client()->State() == IClient::STATE_OFFLINE && m_MenuPage == PAGE_SETTINGS) || (Client()->State() == IClient::STATE_ONLINE && m_GamePage == PAGE_SETTINGS))
{
if(Client()->State() == IClient::STATE_ONLINE && (g_Config.m_UiSettingsPage == SETTINGS_PLAYER || g_Config.m_UiSettingsPage == SETTINGS_TEE))
@ -1056,77 +1168,93 @@ void CMenus::RenderMenubar(CUIRect r)
}
float Spacing = 3.0f;
float ButtonWidth = (Box.w/6.0f)-(Spacing*5.0)/6.0f;
float NotActiveAlpha = Client()->State() == IClient::STATE_ONLINE ? 0.5f : 1.0f;
int Corners = Client()->State() == IClient::STATE_ONLINE ? CUI::CORNER_T : CUI::CORNER_ALL;
// render header background
RenderTools()->DrawUIRect4(&Box, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.25f), vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 5.0f);
if(Client()->State() == IClient::STATE_OFFLINE)
RenderTools()->DrawUIRect4(&Box, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.25f), vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 5.0f);
Box.HSplitBottom(25.0f, 0, &Box);
Box.VSplitLeft(ButtonWidth, &Button, &Box);
static CButtonContainer s_GeneralButton;
if(DoButton_MenuTabTop(&s_GeneralButton, Localize("General"), g_Config.m_UiSettingsPage==SETTINGS_GENERAL, &Button))
if(DoButton_MenuTabTop(&s_GeneralButton, Localize("General"), Client()->State() == IClient::STATE_OFFLINE && g_Config.m_UiSettingsPage==SETTINGS_GENERAL, &Button,
g_Config.m_UiSettingsPage == SETTINGS_GENERAL ? 1.0f : NotActiveAlpha, 1.0f, Corners))
{
m_pClient->m_pCamera->ChangePosition(CCamera::POS_SETTINGS_GENERAL);
g_Config.m_UiSettingsPage = SETTINGS_GENERAL;
}
Box.VSplitLeft(Spacing, 0, &Box); // little space
Box.VSplitLeft(ButtonWidth, &Button, &Box);
static CButtonContainer s_PlayerButton;
if(Client()->State() != IClient::STATE_ONLINE && DoButton_MenuTabTop(&s_PlayerButton, Localize("Player"), g_Config.m_UiSettingsPage == SETTINGS_PLAYER, &Button))
if(Client()->State() == IClient::STATE_OFFLINE)
{
g_Config.m_UiSettingsPage = SETTINGS_PLAYER;
static CButtonContainer s_PlayerButton;
if(DoButton_MenuTabTop(&s_PlayerButton, Localize("Player"), g_Config.m_UiSettingsPage == SETTINGS_PLAYER, &Button))
{
m_pClient->m_pCamera->ChangePosition(CCamera::POS_SETTINGS_PLAYER);
g_Config.m_UiSettingsPage = SETTINGS_PLAYER;
}
}
Box.VSplitLeft(Spacing, 0, &Box); // little space
Box.VSplitLeft(ButtonWidth, &Button, &Box);
static CButtonContainer s_TeeButton;
if(Client()->State() != IClient::STATE_ONLINE && DoButton_MenuTabTop(&s_TeeButton, Localize("Tee"), g_Config.m_UiSettingsPage == SETTINGS_TEE, &Button))
if(Client()->State() == IClient::STATE_OFFLINE)
{
g_Config.m_UiSettingsPage = SETTINGS_TEE;
static CButtonContainer s_TeeButton;
if(DoButton_MenuTabTop(&s_TeeButton, Localize("Tee"), g_Config.m_UiSettingsPage == SETTINGS_TEE, &Button))
{
m_pClient->m_pCamera->ChangePosition(CCamera::POS_SETTINGS_TEE);
g_Config.m_UiSettingsPage = SETTINGS_TEE;
}
}
Box.VSplitLeft(Spacing, 0, &Box); // little space
Box.VSplitLeft(ButtonWidth, &Button, &Box);
static CButtonContainer s_ControlsButton;
if(DoButton_MenuTabTop(&s_ControlsButton, Localize("Controls"), g_Config.m_UiSettingsPage==SETTINGS_CONTROLS, &Button))
if(DoButton_MenuTabTop(&s_ControlsButton, Localize("Controls"), Client()->State() == IClient::STATE_OFFLINE && g_Config.m_UiSettingsPage==SETTINGS_CONTROLS, &Button,
g_Config.m_UiSettingsPage == SETTINGS_CONTROLS ? 1.0f : NotActiveAlpha, 1.0f, Corners))
{
m_pClient->m_pCamera->ChangePosition(CCamera::POS_SETTINGS_CONTROLS);
g_Config.m_UiSettingsPage = SETTINGS_CONTROLS;
}
Box.VSplitLeft(Spacing, 0, &Box); // little space
Box.VSplitLeft(ButtonWidth, &Button, &Box);
static CButtonContainer s_GraphicsButton;
if(DoButton_MenuTabTop(&s_GraphicsButton, Localize("Graphics"), g_Config.m_UiSettingsPage==SETTINGS_GRAPHICS, &Button))
if(DoButton_MenuTabTop(&s_GraphicsButton, Localize("Graphics"), Client()->State() == IClient::STATE_OFFLINE && g_Config.m_UiSettingsPage==SETTINGS_GRAPHICS, &Button,
g_Config.m_UiSettingsPage == SETTINGS_GRAPHICS ? 1.0f : NotActiveAlpha, 1.0f, Corners))
{
m_pClient->m_pCamera->ChangePosition(CCamera::POS_SETTINGS_GRAPHICS);
g_Config.m_UiSettingsPage = SETTINGS_GRAPHICS;
}
Box.VSplitLeft(Spacing, 0, &Box); // little space
Box.VSplitLeft(ButtonWidth, &Button, &Box);
static CButtonContainer s_SoundButton;
if(DoButton_MenuTabTop(&s_SoundButton, Localize("Sound"), g_Config.m_UiSettingsPage==SETTINGS_SOUND, &Button))
if(DoButton_MenuTabTop(&s_SoundButton, Localize("Sound"), Client()->State() == IClient::STATE_OFFLINE && g_Config.m_UiSettingsPage==SETTINGS_SOUND, &Button,
g_Config.m_UiSettingsPage == SETTINGS_SOUND ? 1.0f : NotActiveAlpha, 1.0f, Corners))
{
m_pClient->m_pCamera->ChangePosition(CCamera::POS_SETTINGS_SOUND);
g_Config.m_UiSettingsPage = SETTINGS_SOUND;
}
}
else if(Client()->State() == IClient::STATE_OFFLINE)
{
// render menu tabs
if(m_MenuPage >= PAGE_INTERNET && m_MenuPage <= PAGE_FRIENDS)
if(m_MenuPage >= PAGE_INTERNET && m_MenuPage <= PAGE_LAN)
{
float Spacing = 3.0f;
float ButtonWidth = (Box.w/6.0f)-(Spacing*5.0)/6.0f;
CUIRect Left, Right;
CUIRect Left;
Box.VSplitLeft(ButtonWidth*2.0f+Spacing, &Left, 0);
Box.VSplitRight(ButtonWidth, 0, &Right);
// render header backgrounds
RenderTools()->DrawUIRect4(&Left, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.25f), vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 5.0f);
RenderTools()->DrawUIRect4(&Right, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.25f), vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 5.0f);
Left.HSplitBottom(25.0f, 0, &Left);
Right.HSplitBottom(25.0f, 0, &Right);
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_InternetButton;
@ -1148,19 +1276,6 @@ void CMenus::RenderMenubar(CUIRect r)
NewPage = PAGE_LAN;
g_Config.m_UiBrowserPage = PAGE_LAN;
}
char aBuf[32];
if(m_BorwserPage == PAGE_BROWSER_BROWSER)
str_copy(aBuf, Localize("Friends"), sizeof(aBuf));
else if(m_BorwserPage == PAGE_BROWSER_FRIENDS)
str_copy(aBuf, Localize("Browser"), sizeof(aBuf));
static CButtonContainer s_FilterButton;
if(DoButton_Menu(&s_FilterButton, aBuf, 0, &Right))
{
m_BorwserPage++;
if(m_BorwserPage >= NUM_PAGE_BROWSER)
m_BorwserPage = 0;
}
}
else if(m_MenuPage == PAGE_DEMOS)
{
@ -1179,52 +1294,8 @@ void CMenus::RenderMenubar(CUIRect r)
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f);
}
}
else
{
float Spacing = 3.0f;
float ButtonWidth = (Box.w/6.0f)-(Spacing*5.0)/6.0f;
// render header backgrounds
CUIRect Left, Right;
Box.VSplitLeft(ButtonWidth*4.0f+Spacing*3.0f, &Left, 0);
Box.VSplitRight(ButtonWidth, 0, &Right);
RenderTools()->DrawUIRect4(&Left, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.25f), vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 5.0f);
RenderTools()->DrawUIRect4(&Right, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.25f), vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 5.0f);
Left.HSplitBottom(25.0f, 0, &Left);
Right.HSplitBottom(25.0f, 0, &Right);
// online menus
if(m_GamePage != PAGE_SETTINGS) // Game stuff
{
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_GameButton;
if(DoButton_MenuTabTop(&s_GameButton, Localize("Game"), m_ActivePage==PAGE_GAME, &Button))
NewPage = PAGE_GAME;
Left.VSplitLeft(Spacing, 0, &Left); // little space
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_PlayersButton;
if(DoButton_MenuTabTop(&s_PlayersButton, Localize("Players"), m_ActivePage==PAGE_PLAYERS, &Button))
NewPage = PAGE_PLAYERS;
Left.VSplitLeft(Spacing, 0, &Left); // little space
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_ServerInfoButton;
if(DoButton_MenuTabTop(&s_ServerInfoButton, Localize("Server info"), m_ActivePage==PAGE_SERVER_INFO, &Button))
NewPage = PAGE_SERVER_INFO;
Left.VSplitLeft(Spacing, 0, &Left); // little space
Left.VSplitLeft(ButtonWidth, &Button, &Left);
static CButtonContainer s_CallVoteButton;
if(DoButton_MenuTabTop(&s_CallVoteButton, Localize("Call vote"), m_ActivePage==PAGE_CALLVOTE, &Button))
NewPage = PAGE_CALLVOTE;
static CButtonContainer s_SettingsButton;
if(DoButton_MenuTabTop(&s_SettingsButton, Localize("Settings"), 0, &Right))
NewPage = PAGE_SETTINGS;
}
}
if(NewPage != -1)
{
@ -1287,6 +1358,9 @@ void CMenus::RenderNews(CUIRect MainView)
void CMenus::RenderBackButton(CUIRect MainView)
{
if(Client()->State() != IClient::STATE_OFFLINE)
return;
// same size like tabs in top but variables not really needed
float Spacing = 3.0f;
float ButtonWidth = (MainView.w/6.0f)-(Spacing*5.0)/6.0f;
@ -1301,12 +1375,9 @@ void CMenus::RenderBackButton(CUIRect MainView)
MainView.HSplitTop(25.0f, &MainView, 0);
Button = MainView;
static CButtonContainer s_MenuButton;
if(DoButton_Menu(&s_MenuButton, Localize("Back"), 0, &Button) || (m_EscapePressed && Client()->State() != IClient::STATE_ONLINE))
if(DoButton_Menu(&s_MenuButton, Localize("Back"), 0, &Button) || m_EscapePressed)
{
if(Client()->State() != IClient::STATE_OFFLINE)
m_GamePage = PAGE_GAME;
else
SetMenuPage(PAGE_START);
SetMenuPage(PAGE_START);
}
}
@ -1584,8 +1655,11 @@ int CMenus::Render()
else
{
// do tab bar
float BarHeight = 60.0f;
if(Client()->State() == IClient::STATE_ONLINE && m_GamePage == PAGE_SETTINGS)
BarHeight += 3.0f + 25.0f;
Screen.VMargin(Screen.w/2-365.0f, &MainView);
MainView.HSplitTop(60.0f, &TabBar, &MainView);
MainView.HSplitTop(BarHeight, &TabBar, &MainView);
RenderMenubar(TabBar);
// news is not implemented yet
@ -1594,14 +1668,28 @@ int CMenus::Render()
ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET);
m_MenuPage = PAGE_INTERNET;
}*/
// quit button
CUIRect Button;
float TopOffset = 35.0f;
Screen.HSplitTop(TopOffset, &Button, 0);
Button.VSplitRight(TopOffset - 3.0f, 0, &Button);
static CButtonContainer s_QuitButton;
if(DoButton_Menu(&s_QuitButton, "X", 0, &Button, 0, CUI::CORNER_BL))
m_Popup = POPUP_QUIT;
{
CUIRect Button;
float TopOffset = 27.0f;
Screen.HSplitTop(TopOffset, &Button, 0);
Button.VSplitRight(TopOffset/* - 3.0f*/, 0, &Button);
static CButtonContainer s_QuitButton;
// draw red-blending button
vec4 Color = mix(vec4(0.f, 0.f, 0.f, 0.25f), vec4(1.f/0xff*0xf9, 1.f/0xff*0x2b, 1.f/0xff*0x2b, 0.75f), ButtonFade(&s_QuitButton, 0.6f, 0)/0.6f);
RenderTools()->DrawUIRect(&Button, Color, CUI::CORNER_BL, 5.0f);
// draw non-blending X
CUIRect XText = Button;
// XText.HMargin(Button.h>=20.0f?2.0f:1.0f, &XText);
UI()->DoLabel(&XText, "\xE2\x9C\x95", XText.h*ms_FontmodHeight, CUI::ALIGN_CENTER);
if(UI()->DoButtonLogic(s_QuitButton.GetID(), "\xE2\x9C\x95", 0, &Button))
// if(DoButton_SpriteCleanID(&s_QuitButton, IMAGE_FRIENDICONS, SPRITE_FRIEND_X_A, &Button, false))
m_Popup = POPUP_QUIT;
}
// render current page
if(Client()->State() != IClient::STATE_OFFLINE)
@ -1627,8 +1715,6 @@ int CMenus::Render()
RenderServerbrowser(MainView);
else if(m_MenuPage == PAGE_DEMOS)
RenderDemoList(MainView);
else if(m_MenuPage == PAGE_FRIENDS)
RenderServerbrowser(MainView);
else if(m_MenuPage == PAGE_SETTINGS)
RenderSettings(MainView);
}
@ -2077,12 +2163,12 @@ int CMenus::Render()
{
m_Popup = POPUP_NONE;
// remove friend
if(m_FriendlistSelectedIndex >= 0)
if(m_pDeleteFriend)
{
m_pClient->Friends()->RemoveFriend(m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_aName,
m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_aClan);
m_pClient->Friends()->RemoveFriend(m_pDeleteFriend->m_aName, m_pDeleteFriend->m_aClan);
FriendlistOnUpdate();
Client()->ServerBrowserUpdate();
m_pDeleteFriend = 0;
}
}
}
@ -2263,8 +2349,14 @@ bool CMenus::OnInput(IInput::CEvent e)
// special for popups
if(e.m_Key == KEY_RETURN || e.m_Key == KEY_KP_ENTER)
m_EnterPressed = true;
else if(e.m_Key == KEY_TAB && !Input()->KeyPress(KEY_LALT) && !Input()->KeyPress(KEY_RALT))
m_TabPressed = true;
else if(e.m_Key == KEY_DELETE)
m_DeletePressed = true;
else if(e.m_Key == KEY_UP)
m_UpArrowPressed = true;
else if(e.m_Key == KEY_DOWN)
m_DownArrowPressed = true;
}
return true;
}
@ -2298,14 +2390,14 @@ void CMenus::OnConsoleInit()
{
// put it on top
int Pos = m_lFilters.size();
m_lFilters.add(CBrowserFilter(CBrowserFilter::FILTER_STANDARD, "Teeworlds", ServerBrowser(), IServerBrowser::FILTER_COMPAT_VERSION | IServerBrowser::FILTER_PURE | IServerBrowser::FILTER_PURE_MAP | IServerBrowser::FILTER_PING, 999, -1, "", ""));
m_lFilters.add(CBrowserFilter(CBrowserFilter::FILTER_STANDARD, "Teeworlds", ServerBrowser()));
for(; Pos > 0; --Pos)
Move(true, Pos);
}
if(!FilterFav)
m_lFilters.add(CBrowserFilter(CBrowserFilter::FILTER_FAVORITES, Localize("Favorites"), ServerBrowser(), IServerBrowser::FILTER_FAVORITE | IServerBrowser::FILTER_PING, 999, -1, "", ""));
m_lFilters.add(CBrowserFilter(CBrowserFilter::FILTER_FAVORITES, Localize("Favorites"), ServerBrowser()));
if(!FilterAll)
m_lFilters.add(CBrowserFilter(CBrowserFilter::FILTER_ALL, Localize("All"), ServerBrowser(), IServerBrowser::FILTER_PING, 999, -1, "", ""));
m_lFilters.add(CBrowserFilter(CBrowserFilter::FILTER_ALL, Localize("All"), ServerBrowser()));
}
void CMenus::OnShutdown()
@ -2380,7 +2472,10 @@ void CMenus::OnRender()
{
m_EscapePressed = false;
m_EnterPressed = false;
m_TabPressed = false;
m_DeletePressed = false;
m_UpArrowPressed = false;
m_DownArrowPressed = false;
return;
}
@ -2405,11 +2500,13 @@ void CMenus::OnRender()
// render cursor
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CURSOR].m_Id);
Graphics()->WrapClamp();
Graphics()->QuadsBegin();
Graphics()->SetColor(1,1,1,1);
IGraphics::CQuadItem QuadItem(mx, my, 24, 24);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
Graphics()->WrapNormal();
// render debug information
if(g_Config.m_Debug)
@ -2427,7 +2524,10 @@ void CMenus::OnRender()
UI()->FinishCheck();
m_EscapePressed = false;
m_EnterPressed = false;
m_TabPressed = false;
m_DeletePressed = false;
m_UpArrowPressed = false;
m_DownArrowPressed = false;
}
void CMenus::RenderBackground()
@ -2518,9 +2618,9 @@ void CMenus::SetMenuPage(int NewPage) {
{
case PAGE_START: CameraPos = CCamera::POS_START; break;
case PAGE_DEMOS: CameraPos = CCamera::POS_DEMOS; break;
case PAGE_SETTINGS: CameraPos = CCamera::POS_SETTINGS; break;
case PAGE_INTERNET:
case PAGE_LAN: CameraPos = CCamera::POS_INTERNET;
case PAGE_SETTINGS: CameraPos = CCamera::POS_SETTINGS_GENERAL+g_Config.m_UiSettingsPage; break;
case PAGE_INTERNET: CameraPos = CCamera::POS_INTERNET; break;
case PAGE_LAN: CameraPos = CCamera::POS_LAN;
}
if(CameraPos != -1 && m_pClient && m_pClient->m_pCamera)

View file

@ -48,13 +48,14 @@ private:
int DoButton_DemoPlayer(CButtonContainer *pBC, const char *pText, const CUIRect *pRect);
int DoButton_SpriteID(CButtonContainer *pBC, int ImageID, int SpriteID, const CUIRect *pRect, int Corners=CUI::CORNER_ALL, float r=5.0f, bool Fade=true);
int DoButton_SpriteID(CButtonContainer *pBC, int ImageID, int SpriteID, bool Checked, const CUIRect *pRect, int Corners=CUI::CORNER_ALL, float r=5.0f, bool Fade=true);
int DoButton_SpriteClean(int ImageID, int SpriteID, const CUIRect *pRect);
int DoButton_SpriteCleanID(const void *pID, int ImageID, int SpriteID, const CUIRect *pRect, bool Blend=true);
int DoButton_Toggle(const void *pID, int Checked, const CUIRect *pRect, bool Active);
int DoButton_Menu(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, const char *pImageName=0, int Corners=CUI::CORNER_ALL, float r=5.0f, float FontFactor=0.0f, vec4 ColorHot=vec4(1.0f, 1.0f, 1.0f, 0.75f), bool TextFade=true);
int DoButton_MenuTab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Corners);
int DoButton_MenuTabTop(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, int Corners=CUI::CORNER_ALL, float r=5.0f, float FontFactor=0.0f);
int DoButton_MenuTabTop(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, float Alpha=1.0f, float FontAlpha=1.0f, int Corners=CUI::CORNER_ALL, float r=5.0f, float FontFactor=0.0f);
void DoButton_MenuTabTop_Dummy(const char *pText, int Checked, const CUIRect *pRect, float Alpha);
int DoButton_Customize(CButtonContainer *pBC, IGraphics::CTextureHandle Texture, int SpriteID, const CUIRect *pRect, float ImageRatio);
int DoButton_CheckBox_Common(const void *pID, const char *pText, const char *pBoxText, const CUIRect *pRect, bool Checked=false);
@ -84,6 +85,7 @@ private:
void DoEditBoxOption(void *pID, char *pOption, int OptionLength, const CUIRect *pRect, const char *pStr, float VSplitVal, float *pOffset, bool Hidden=false);
void DoScrollbarOption(void *pID, int *pOption, const CUIRect *pRect, const char *pStr, float VSplitVal, int Min, int Max, bool infinite=false);
float DoDropdownMenu(void *pID, const CUIRect *pRect, const char *pStr, float HeaderHeight, FDropdownCallback pfnCallback);
float DoIndependentDropdownMenu(void *pID, const CUIRect *pRect, const char *pStr, float HeaderHeight, FDropdownCallback pfnCallback, bool* pActive);
void DoInfoBox(const CUIRect *pRect, const char *pLable, const char *pValue);
//static int ui_do_edit_box(void *id, const CUIRect *rect, char *str, unsigned str_size, float font_size, bool hidden=false);
@ -162,35 +164,35 @@ private:
PAGE_CALLVOTE,
PAGE_INTERNET,
PAGE_LAN,
PAGE_FRIENDS,
PAGE_DEMOS,
PAGE_SETTINGS,
PAGE_SYSTEM,
PAGE_START,
PAGE_BROWSER_BROWSER=0,
PAGE_BROWSER_FRIENDS,
NUM_PAGE_BROWSER,
SETTINGS_GENERAL=0,
SETTINGS_PLAYER,
SETTINGS_TEE,
SETTINGS_CONTROLS,
SETTINGS_GRAPHICS,
SETTINGS_SOUND,
ACTLB_LANG=0,
ACTLB_THEME,
};
int m_GamePage;
int m_Popup;
int m_ActivePage;
int m_MenuPage;
int m_BorwserPage;
bool m_MenuActive;
int m_SidebarTab;
bool m_SidebarActive;
bool m_ShowServerDetails;
bool m_UseMouseButtons;
vec2 m_MousePos;
vec2 m_PrevMousePos;
bool m_InfoMode;
bool m_PopupActive;
int m_ActiveListBox;
// images
struct CMenuImage
@ -205,6 +207,24 @@ private:
const CMenuImage *FindMenuImage(const char* pName);
// themes
class CTheme
{
public:
CTheme() {}
CTheme(const char *n, bool HasDay, bool HasNight) : m_Name(n), m_HasDay(HasDay), m_HasNight(HasNight) {}
string m_Name;
bool m_HasDay;
bool m_HasNight;
IGraphics::CTextureHandle m_IconTexture;
bool operator<(const CTheme &Other) { return m_Name < Other.m_Name; }
};
sorted_array<CTheme> m_lThemes;
static int ThemeScan(const char *pName, int IsDir, int DirType, void *pUser);
static int ThemeIconScan(const char *pName, int IsDir, int DirType, void *pUser);
int64 m_LastInput;
// loading
@ -223,6 +243,7 @@ private:
static float ms_ButtonHeight;
static float ms_ListheaderHeight;
static float ms_FontmodHeight;
static float ms_BackgroundAlpha;
// for settings
bool m_NeedRestartGraphics;
@ -237,7 +258,10 @@ private:
//
bool m_EscapePressed;
bool m_EnterPressed;
bool m_TabPressed;
bool m_DeletePressed;
bool m_UpArrowPressed;
bool m_DownArrowPressed;
// for map download popup
int64 m_DownloadLastCheckTime;
@ -286,30 +310,11 @@ private:
class CFriendItem
{
public:
class CClanFriendItem
{
public:
CClanFriendItem()
{
m_lFriendInfos.clear();
m_lServerInfos.clear();
}
~CClanFriendItem()
{
m_lFriendInfos.clear();
m_lServerInfos.clear();
}
array<CFriendInfo> m_lFriendInfos;
array<const CServerInfo*> m_lServerInfos;
};
int m_NumFound;
const CFriendInfo *m_pFriendInfo;
const CServerInfo *m_pServerInfo;
CClanFriendItem m_ClanFriend;
char m_aName[MAX_NAME_LENGTH];
char m_aClan[MAX_CLAN_LENGTH];
bool m_IsPlayer;
CFriendItem()
{
@ -317,48 +322,31 @@ private:
m_pServerInfo = 0;
}
bool IsClanFriend()
bool operator<(const CFriendItem &Other)
{
return m_pFriendInfo->m_aClan[0] && !m_pFriendInfo->m_aName[0];
if(m_aName[0] && !Other.m_aName[0])
return true;
if(!m_aName[0] && Other.m_aName[0])
return false;
int Result = str_comp_nocase(m_aName, Other.m_aName);
if(Result < 0 || (Result == 0 && str_comp_nocase(m_aClan, Other.m_aClan) < 0))
return true;
return false;
}
void Reset()
{
m_NumFound = 0;
m_ClanFriend.m_lFriendInfos.clear();
m_ClanFriend.m_lServerInfos.clear();
}
};
struct CSelectedFriend
{
bool m_ClanFriend;
bool m_FakeFriend;
unsigned m_NameHash;
unsigned m_ClanHash;
};
enum
{
FRIENDS_SORT_TYPE = 0,
FRIENDS_SORT_SERVER,
FRIENDS_SORT_NAME,
FRIENDS_SORT_CLAN,
FRIEND_PLAYER_ON = 0,
FRIEND_CLAN_ON,
FRIEND_OFF,
NUM_FRIEND_TYPES
};
int *m_pFriendIndexes;
array<CFriendItem> m_lFriends;
int m_FriendlistSelectedIndex;
const CFriendInfo *m_pDeleteFriendInfo;
CSelectedFriend m_SelectedFriend;
bool SortCompareName(int Index1, int Index2) const;
bool SortCompareClan(int Index1, int Index2) const;
bool SortCompareServer(int Index1, int Index2) const;
bool SortCompareType(int Index1, int Index2) const;
sorted_array<CFriendItem> m_lFriendList[NUM_FRIEND_TYPES];
const CFriendItem *m_pDeleteFriend;
void FriendlistOnUpdate();
void SortFriends();
class CBrowserFilter
{
@ -368,6 +356,10 @@ private:
int m_Filter;
class IServerBrowser *m_pServerBrowser;
static class CServerFilterInfo ms_FilterStandard;
static class CServerFilterInfo ms_FilterFavorites;
static class CServerFilterInfo ms_FilterAll;
public:
enum
@ -379,9 +371,10 @@ private:
};
// buttons var
int m_SwitchButton;
int m_aButtonID[3];
CBrowserFilter() {}
CBrowserFilter(int Custom, const char* pName, IServerBrowser *pServerBrowser, int Filter, int Ping, int Country, const char* pGametype, const char* pServerAddress);
CBrowserFilter(int Custom, const char* pName, IServerBrowser *pServerBrowser);
void Switch();
bool Extended() const;
int Custom() const;
@ -395,6 +388,7 @@ private:
const CServerInfo *SortedGet(int Index) const;
const void *ID(int Index) const;
void Reset();
void GetFilter(class CServerFilterInfo *pFilterInfo) const;
void SetFilter(const class CServerFilterInfo *pFilterInfo);
};
@ -448,16 +442,7 @@ private:
COL_BROWSER_MAP,
COL_BROWSER_PLAYERS,
COL_BROWSER_PING,
COL_BROWSER_FAVORITE,
COL_BROWSER_INFO,
NUM_BROWSER_COLS,
COL_FRIEND_TYPE = 0,
COL_FRIEND_SERVER,
COL_FRIEND_NAME,
COL_FRIEND_CLAN,
COL_FRIEND_DELETE,
NUM_FRIEND_COLS,
};
struct CColumn
@ -473,7 +458,6 @@ private:
};
static CColumn ms_aBrowserCols[NUM_BROWSER_COLS];
static CColumn ms_aFriendCols[NUM_FRIEND_COLS];
enum
{
@ -524,15 +508,21 @@ private:
void RenderServerControlServer(CUIRect MainView);
// found in menus_browser.cpp
int m_ScrollOffset;
// int m_ScrollOffset;
void RenderServerbrowserServerList(CUIRect View);
void RenderServerbrowserSidebar(CUIRect View);
void RenderServerbrowserFriendTab(CUIRect View);
void RenderServerbrowserFilterTab(CUIRect View);
void RenderServerbrowserInfoTab(CUIRect View);
void RenderServerbrowserFriendList(CUIRect View);
void RenderDetailInfo(CUIRect View, const CServerInfo *pInfo);
void RenderDetailScoreboard(CUIRect View, const CServerInfo *pInfo, int Column);
void RenderServerbrowserServerDetail(CUIRect View, const CServerInfo *pInfo);
//void RenderServerbrowserFriends(CUIRect View);
void RenderServerbrowserBottomBox(CUIRect View);
void RenderServerbrowserOverlay();
bool RenderFilterHeader(CUIRect View, int FilterIndex);
int DoBrowserEntry(const void *pID, CUIRect *pRect, const CServerInfo *pEntry, const CBrowserFilter *pFilter, bool Selected);
int DoBrowserEntry(const void *pID, CUIRect View, const CServerInfo *pEntry, const CBrowserFilter *pFilter, bool Selected);
void RenderServerbrowser(CUIRect MainView);
static void ConchainFriendlistUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainServerbrowserUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
@ -544,6 +534,7 @@ private:
// found in menus_settings.cpp
void RenderLanguageSelection(CUIRect MainView, bool Header=true);
void RenderThemeSelection(CUIRect MainView, bool Header=true);
void RenderHSLPicker(CUIRect Picker);
void RenderSkinSelection(CUIRect MainView);
void RenderSkinPartSelection(CUIRect MainView);
@ -572,8 +563,6 @@ private:
void InvokePopupMenu(void *pID, int Flags, float X, float Y, float W, float H, int (*pfnFunc)(CMenus *pMenu, CUIRect Rect), void *pExtra=0);
void DoPopupMenu();
static int PopupFilter(CMenus *pMenus, CUIRect View);
IGraphics::CTextureHandle m_TextureBlob;
void ToggleMusic();

File diff suppressed because it is too large Load diff

View file

@ -181,12 +181,12 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
static CButtonContainer s_PlayPauseButton;
if(!pInfo->m_Paused)
{
if(DoButton_SpriteID(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PAUSE, &Button, CUI::CORNER_ALL))
if(DoButton_SpriteID(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PAUSE, false, &Button, CUI::CORNER_ALL))
DemoPlayer()->Pause();
}
else
{
if(DoButton_SpriteID(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PLAY, &Button, CUI::CORNER_ALL))
if(DoButton_SpriteID(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PLAY, false, &Button, CUI::CORNER_ALL))
DemoPlayer()->Unpause();
}
@ -195,7 +195,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
static CButtonContainer s_ResetButton;
if(DoButton_SpriteID(&s_ResetButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_STOP, &Button, CUI::CORNER_ALL))
if(DoButton_SpriteID(&s_ResetButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_STOP, false, &Button, CUI::CORNER_ALL))
{
m_pClient->OnReset();
DemoPlayer()->Pause();
@ -206,14 +206,14 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
static CButtonContainer s_SlowDownButton;
if(DoButton_SpriteID(&s_SlowDownButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_SLOWER, &Button, CUI::CORNER_ALL))
if(DoButton_SpriteID(&s_SlowDownButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_SLOWER, false, &Button, CUI::CORNER_ALL))
DecreaseDemoSpeed = true;
// fastforward
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
static CButtonContainer s_FastForwardButton;
if(DoButton_SpriteID(&s_FastForwardButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_FASTER, &Button, CUI::CORNER_ALL))
if(DoButton_SpriteID(&s_FastForwardButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_FASTER, false, &Button, CUI::CORNER_ALL))
IncreaseDemoSpeed = true;
// speed meter
@ -320,6 +320,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
// cut view
MainView.HSplitBottom(80.0f, &MainView, &BottomView);
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), CUI::CORNER_ALL, 5.0f);
BottomView.HSplitTop(20.f, 0, &BottomView);
static int s_Inited = 0;

View file

@ -81,8 +81,9 @@ void CMenus::RenderGame(CUIRect MainView)
{
// print notice
CUIRect Bar;
MainView.HSplitTop(20.0f, 0, &MainView);
MainView.HSplitTop(45.0f, &Bar, &MainView);
RenderTools()->DrawUIRect(&Bar, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 10.0f);
RenderTools()->DrawUIRect(&Bar, vec4(0.0f, 0.0f, 0.0f, 0.25f+ms_BackgroundAlpha), CUI::CORNER_ALL, 5.0f);
Bar.HMargin(15.0f, &Bar);
UI()->DoLabelScaled(&Bar, Info.m_aNotification, 14.0f, CUI::ALIGN_CENTER);
}
@ -191,37 +192,43 @@ void CMenus::RenderGame(CUIRect MainView)
void CMenus::RenderPlayers(CUIRect MainView)
{
CUIRect Button, ButtonBar, Options, Player;
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 10.0f);
const float ButtonHeight = 20.0f;
const float Spacing = 2.0f;
const float NameWidth = 250.0f;
const float ClanWidth = 250.0f;
CUIRect Label, Row;
MainView.HSplitBottom(80.0f, &MainView, 0);
MainView.HSplitTop(20.0f, 0, &MainView);
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f+ms_BackgroundAlpha), CUI::CORNER_ALL, 5.0f);
// player options
MainView.Margin(10.0f, &Options);
RenderTools()->DrawUIRect(&Options, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 10.0f);
Options.Margin(10.0f, &Options);
Options.HSplitTop(50.0f, &Button, &Options);
UI()->DoLabelScaled(&Button, Localize("Player options"), 34.0f, CUI::ALIGN_LEFT);
MainView.HSplitTop(ButtonHeight, &Label, &MainView);
Label.y += 2.0f;
UI()->DoLabel(&Label, Localize("Player options"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
RenderTools()->DrawUIRect(&MainView, vec4(0.0, 0.0, 0.0, 0.25f), CUI::CORNER_ALL, 5.0f);
MainView.Margin(5.0f, &MainView);
// headline
Options.HSplitTop(34.0f, &ButtonBar, &Options);
ButtonBar.VSplitRight(220.0f, &Player, &ButtonBar);
UI()->DoLabelScaled(&Player, Localize("Player"), 24.0f, CUI::ALIGN_LEFT);
MainView.HSplitTop(ButtonHeight, &Row, &MainView);
Row.VSplitLeft(ButtonHeight+Spacing, 0, &Row);
Row.VSplitLeft(NameWidth, &Label, &Row);
Label.y += 2.0f;
UI()->DoLabel(&Label, Localize("Player"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
ButtonBar.HMargin(1.0f, &ButtonBar);
float Width = ButtonBar.h*2.0f;
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
Row.VSplitRight(2*ButtonHeight, &Row, &Label);
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GUIICONS].m_Id);
Graphics()->QuadsBegin();
RenderTools()->SelectSprite(SPRITE_GUIICON_MUTE);
IGraphics::CQuadItem QuadItem(Button.x, Button.y, Button.w, Button.h);
IGraphics::CQuadItem QuadItem(Label.x, Label.y, Label.w, Label.h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
ButtonBar.VSplitLeft(20.0f, 0, &ButtonBar);
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
Row.VSplitRight(2*Spacing, &Row, 0);
Row.VSplitRight(2*ButtonHeight, &Row, &Label);
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GUIICONS].m_Id);
Graphics()->QuadsBegin();
RenderTools()->SelectSprite(SPRITE_GUIICON_FRIEND);
QuadItem = IGraphics::CQuadItem(Button.x, Button.y, Button.w, Button.h);
QuadItem = IGraphics::CQuadItem(Label.x, Label.y, Label.w, Label.h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
@ -235,47 +242,49 @@ void CMenus::RenderPlayers(CUIRect MainView)
if(i == m_pClient->m_LocalClientID || !m_pClient->m_aClients[i].m_Active || m_pClient->m_aClients[i].m_Team != Teams[Team])
continue;
Options.HSplitTop(28.0f, &ButtonBar, &Options);
if(Count++%2 == 0)
RenderTools()->DrawUIRect(&ButtonBar, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 10.0f);
ButtonBar.VSplitRight(220.0f, &Player, &ButtonBar);
MainView.HSplitTop(ButtonHeight, &Row, &MainView);
if(Count++ % 2 == 0)
RenderTools()->DrawUIRect(&Row, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
// player info
Player.VSplitLeft(28.0f, &Button, &Player);
Row.VSplitLeft(ButtonHeight, &Label, &Row);
Label.y += 2.0f;
CTeeRenderInfo Info = m_pClient->m_aClients[i].m_RenderInfo;
Info.m_Size = Button.h;
RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(Button.x+Button.h/2, Button.y+Button.h/2));
Info.m_Size = Label.h;
RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(Label.x + Label.h / 2, Label.y + Label.h / 2));
Player.HSplitTop(1.5f, 0, &Player);
Player.VSplitMid(&Player, &Button);
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, Player.x, Player.y, 14.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = Player.w;
Row.VSplitLeft(2*Spacing, 0, &Row);
Row.VSplitLeft(NameWidth, &Label, &Row);
Label.y += 2.0f;
if(g_Config.m_ClShowUserId)
{
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, Label.x, Label.y, ButtonHeight*ms_FontmodHeight*0.8f, TEXTFLAG_RENDER);
RenderTools()->DrawClientID(TextRender(), &Cursor, i);
Label.VSplitLeft(ButtonHeight, 0, &Label);
}
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%2d: %s", i, g_Config.m_ClShowsocial ? m_pClient->m_aClients[i].m_aName : "");
TextRender()->TextEx(&Cursor, aBuf, -1);
TextRender()->SetCursor(&Cursor, Button.x,Button.y, 14.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = Button.w;
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[i].m_aClan, -1);
str_format(aBuf, sizeof(aBuf), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[i].m_aName : "");
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
Row.VSplitLeft(Spacing, 0, &Row);
Row.VSplitLeft(ClanWidth, &Label, &Row);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[i].m_aClan : "");
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
// ignore button
ButtonBar.HMargin(2.0f, &ButtonBar);
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
Button.VSplitLeft((Width-Button.h)/4.0f, 0, &Button);
Button.VSplitLeft(Button.h, &Button, 0);
Row.VSplitRight(ButtonHeight/2, &Row, 0);
Row.VSplitRight(ButtonHeight, &Row, &Label);
if(g_Config.m_ClFilterchat == 2 || (g_Config.m_ClFilterchat == 1 && !m_pClient->m_aClients[i].m_Friend))
DoButton_Toggle(&s_aPlayerIDs[i][0], 1, &Button, false);
DoButton_Toggle(&s_aPlayerIDs[i][0], 1, &Label, false);
else
if(DoButton_Toggle(&s_aPlayerIDs[i][0], m_pClient->m_aClients[i].m_ChatIgnore, &Button, true))
if(DoButton_Toggle(&s_aPlayerIDs[i][0], m_pClient->m_aClients[i].m_ChatIgnore, &Label, true))
m_pClient->m_aClients[i].m_ChatIgnore ^= 1;
// friend button
ButtonBar.VSplitLeft(20.0f, &Button, &ButtonBar);
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
Button.VSplitLeft((Width-Button.h)/4.0f, 0, &Button);
Button.VSplitLeft(Button.h, &Button, 0);
if(DoButton_Toggle(&s_aPlayerIDs[i][1], m_pClient->m_aClients[i].m_Friend, &Button, true))
Row.VSplitRight(2*Spacing+ButtonHeight,&Row, 0);
Row.VSplitRight(ButtonHeight, &Row, &Label);
if(DoButton_Toggle(&s_aPlayerIDs[i][1], m_pClient->m_aClients[i].m_Friend, &Label, true))
{
if(m_pClient->m_aClients[i].m_Friend)
m_pClient->Friends()->RemoveFriend(m_pClient->m_aClients[i].m_aName, m_pClient->m_aClients[i].m_aClan);
@ -298,103 +307,108 @@ void CMenus::RenderServerInfo(CUIRect MainView)
Client()->GetServerInfo(&CurrentServerInfo);
// render background
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 10.0f);
MainView.HSplitBottom(80.0f, &MainView, 0);
MainView.HSplitTop(20.0f, 0, &MainView);
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), CUI::CORNER_ALL, 5.0f);
CUIRect View, ServerInfo, GameInfo, Motd;
CUIRect ServerInfo, GameInfo, Motd, Label;
float x = 0.0f;
float y = 0.0f;
char aBuf[1024];
// set view to use for all sub-modules
MainView.Margin(10.0f, &View);
char aBuf[128] = {0};
const float ButtonHeight = 20.0f;
// serverinfo
View.HSplitTop(View.h/2/UI()->Scale()-5.0f, &ServerInfo, &Motd);
ServerInfo.VSplitLeft(View.w/2/UI()->Scale()-5.0f, &ServerInfo, &GameInfo);
RenderTools()->DrawUIRect(&ServerInfo, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
MainView.HSplitBottom(250.0f, &ServerInfo, &Motd);
ServerInfo.VSplitMid(&ServerInfo, &GameInfo);
ServerInfo.VSplitRight(1.0f, &ServerInfo, 0);
RenderTools()->DrawUIRect(&ServerInfo, vec4(0.0, 0.0, 0.0, 0.25f), CUI::CORNER_ALL, 5.0f);
ServerInfo.HSplitTop(ButtonHeight, &Label, &ServerInfo);
Label.y += 2.0f;
UI()->DoLabel(&Label, Localize("Server info"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
RenderTools()->DrawUIRect(&ServerInfo, vec4(0.0, 0.0, 0.0, 0.25f), CUI::CORNER_ALL, 5.0f);
ServerInfo.Margin(5.0f, &ServerInfo);
ServerInfo.HSplitTop(2*ButtonHeight, &Label, &ServerInfo);
Label.y += 2.0f;
UI()->DoLabel(&Label, CurrentServerInfo.m_aName, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
x = 5.0f;
y = 0.0f;
ServerInfo.HSplitTop(ButtonHeight, &Label, &ServerInfo);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Address"), g_Config.m_UiServerAddress);
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
ServerInfo.HSplitTop(ButtonHeight, &Label, &ServerInfo);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %d", Localize("Ping"), m_pClient->m_Snap.m_pLocalInfo->m_Latency);
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
TextRender()->Text(0, ServerInfo.x+x, ServerInfo.y+y, 32, Localize("Server info"), 250);
y += 32.0f+5.0f;
mem_zero(aBuf, sizeof(aBuf));
str_format(
aBuf,
sizeof(aBuf),
"%s\n\n"
"%s: %s\n"
"%s: %d\n"
"%s: %s\n"
"%s: %s\n",
CurrentServerInfo.m_aName,
Localize("Address"), g_Config.m_UiServerAddress,
Localize("Ping"), m_pClient->m_Snap.m_pLocalInfo->m_Latency,
Localize("Version"), CurrentServerInfo.m_aVersion,
Localize("Password"), CurrentServerInfo.m_Flags&IServerBrowser::FLAG_PASSWORD ? Localize("Yes") : Localize("No")
);
TextRender()->Text(0, ServerInfo.x+x, ServerInfo.y+y, 20, aBuf, 250);
ServerInfo.HSplitTop(ButtonHeight, &Label, &ServerInfo);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Version"), CurrentServerInfo.m_aVersion);
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
ServerInfo.HSplitTop(ButtonHeight, &Label, &ServerInfo);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Password"), CurrentServerInfo.m_Flags&IServerBrowser::FLAG_PASSWORD ? Localize("Yes", "With") : Localize("No", "Without/None"));
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
const bool IsFavorite = ServerBrowser()->IsFavorite(CurrentServerInfo.m_NetAddr);
ServerInfo.HSplitBottom(ButtonHeight, &ServerInfo, &Label);
static int s_AddFavButton = 0;
if(DoButton_CheckBox(&s_AddFavButton, Localize("Favorite"), IsFavorite, &Label))
{
CUIRect Button;
bool IsFavorite = ServerBrowser()->IsFavorite(CurrentServerInfo.m_NetAddr);
ServerInfo.HSplitBottom(20.0f, &ServerInfo, &Button);
static int s_AddFavButton = 0;
if(DoButton_CheckBox(&s_AddFavButton, Localize("Favorite"), IsFavorite, &Button))
{
if(IsFavorite)
ServerBrowser()->RemoveFavorite(&CurrentServerInfo);
if(IsFavorite)
ServerBrowser()->RemoveFavorite(&CurrentServerInfo);
else
ServerBrowser()->AddFavorite(&CurrentServerInfo);
}
ServerBrowser()->AddFavorite(&CurrentServerInfo);
}
// gameinfo
GameInfo.VSplitLeft(10.0f, 0x0, &GameInfo);
RenderTools()->DrawUIRect(&GameInfo, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
GameInfo.VSplitLeft(1.0f, 0, &GameInfo);
RenderTools()->DrawUIRect(&GameInfo, vec4(0.0, 0.0, 0.0, 0.25f), CUI::CORNER_ALL, 5.0f);
GameInfo.HSplitTop(ButtonHeight, &Label, &GameInfo);
Label.y += 2.0f;
UI()->DoLabel(&Label, Localize("Game info"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
RenderTools()->DrawUIRect(&GameInfo, vec4(0.0, 0.0, 0.0, 0.25f), CUI::CORNER_ALL, 5.0f);
GameInfo.Margin(5.0f, &GameInfo);
x = 5.0f;
y = 0.0f;
GameInfo.HSplitTop(ButtonHeight, &Label, &GameInfo);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Game type"), CurrentServerInfo.m_aGameType);
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
TextRender()->Text(0, GameInfo.x+x, GameInfo.y+y, 32, Localize("Game info"), 250);
y += 32.0f+5.0f;
GameInfo.HSplitTop(ButtonHeight, &Label, &GameInfo);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Map"), CurrentServerInfo.m_aMap);
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
mem_zero(aBuf, sizeof(aBuf));
str_format(
aBuf,
sizeof(aBuf),
"\n\n"
"%s: %s\n"
"%s: %s\n"
"%s: %d\n"
"%s: %d\n"
"\n"
"%s: %d/%d\n",
Localize("Game type"), CurrentServerInfo.m_aGameType,
Localize("Map"), CurrentServerInfo.m_aMap,
Localize("Score limit"), m_pClient->m_GameInfo.m_ScoreLimit,
Localize("Time limit"), m_pClient->m_GameInfo.m_TimeLimit,
Localize("Players"), m_pClient->m_GameInfo.m_NumPlayers, CurrentServerInfo.m_MaxClients
);
TextRender()->Text(0, GameInfo.x+x, GameInfo.y+y, 20, aBuf, 250);
GameInfo.HSplitTop(ButtonHeight, &Label, &GameInfo);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %d", Localize("Score limit"), m_pClient->m_GameInfo.m_ScoreLimit);
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
GameInfo.HSplitTop(ButtonHeight, &Label, &GameInfo);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %d", Localize("Time limit"), m_pClient->m_GameInfo.m_TimeLimit);
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
GameInfo.HSplitBottom(ButtonHeight, &GameInfo, &Label);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s: %d/%d", Localize("Players"), m_pClient->m_GameInfo.m_NumPlayers, CurrentServerInfo.m_MaxClients);
UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
// motd
Motd.HSplitTop(10.0f, 0, &Motd);
RenderTools()->DrawUIRect(&Motd, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f);
Motd.HSplitTop(2.0f, 0, &Motd);
RenderTools()->DrawUIRect(&Motd, vec4(0.0, 0.0, 0.0, 0.25f), CUI::CORNER_ALL, 5.0f);
Motd.HSplitTop(ButtonHeight, &Label, &Motd);
Label.y += 2.0f;
UI()->DoLabel(&Label, Localize("MOTD"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
RenderTools()->DrawUIRect(&Motd, vec4(0.0, 0.0, 0.0, 0.25f), CUI::CORNER_ALL, 5.0f);
Motd.Margin(5.0f, &Motd);
y = 0.0f;
x = 5.0f;
TextRender()->Text(0, Motd.x+x, Motd.y+y, 32, Localize("MOTD"), -1);
y += 32.0f+5.0f;
TextRender()->Text(0, Motd.x+x, Motd.y+y, 16, m_pClient->m_pMotd->m_aServerMotd, (int)Motd.w);
TextRender()->Text(0, Motd.x, Motd.y, ButtonHeight*ms_FontmodHeight*0.8f, m_pClient->m_pMotd->m_aServerMotd, (int)Motd.w);
}
void CMenus::RenderServerControlServer(CUIRect MainView)
@ -402,15 +416,19 @@ void CMenus::RenderServerControlServer(CUIRect MainView)
static int s_VoteList = 0;
static CListBoxState s_ListBoxState;
CUIRect List = MainView;
UiDoListboxHeader(&s_ListBoxState, &List, "", 20.0f, 2.0f);
UiDoListboxStart(&s_ListBoxState, &s_VoteList, 24.0f, "", m_pClient->m_pVoting->m_NumVoteOptions, 1, m_CallvoteSelectedOption);
UiDoListboxHeader(&s_ListBoxState, &List, Localize("Option"), 20.0f, 2.0f);
UiDoListboxStart(&s_ListBoxState, &s_VoteList, 20.0f, 0, m_pClient->m_pVoting->m_NumVoteOptions, 1, m_CallvoteSelectedOption, 0, true);
for(CVoteOptionClient *pOption = m_pClient->m_pVoting->m_pFirst; pOption; pOption = pOption->m_pNext)
{
CListboxItem Item = UiDoListboxNextItem(&s_ListBoxState, pOption);
if(Item.m_Visible)
UI()->DoLabelScaled(&Item.m_Rect, pOption->m_aDescription, 16.0f, CUI::ALIGN_LEFT);
{
Item.m_Rect.VMargin(5.0f, &Item.m_Rect);
Item.m_Rect.y += 2.0f;
UI()->DoLabel(&Item.m_Rect, pOption->m_aDescription, Item.m_Rect.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
}
}
m_CallvoteSelectedOption = UiDoListboxEnd(&s_ListBoxState, 0);
@ -428,7 +446,7 @@ void CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
{
if(i == m_pClient->m_LocalClientID || !m_pClient->m_aClients[i].m_Active || m_pClient->m_aClients[i].m_Team != Teams[Team] ||
(FilterSpectators && m_pClient->m_aClients[i].m_Team == TEAM_SPECTATORS) ||
(!FilterSpectators && m_pClient->m_Snap.m_paPlayerInfos[i] && m_pClient->m_Snap.m_paPlayerInfos[i]->m_PlayerFlags&PLAYERFLAG_ADMIN))
(!FilterSpectators && m_pClient->m_Snap.m_paPlayerInfos[i] && (m_pClient->m_Snap.m_paPlayerInfos[i]->m_PlayerFlags&PLAYERFLAG_ADMIN)))
continue;
if(m_CallvoteSelectedPlayer == i)
Selected = NumOptions;
@ -436,11 +454,14 @@ void CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
}
}
const float Spacing = 2.0f;
const float NameWidth = 250.0f;
const float ClanWidth = 250.0f;
static int s_VoteList = 0;
static CListBoxState s_ListBoxState;
CUIRect List = MainView;
UiDoListboxHeader(&s_ListBoxState, &List, "", 20.0f, 2.0f);
UiDoListboxStart(&s_ListBoxState, &s_VoteList, 24.0f, "", NumOptions, 1, Selected);
UiDoListboxHeader(&s_ListBoxState, &List, Localize("Player"), 20.0f, 2.0f);
UiDoListboxStart(&s_ListBoxState, &s_VoteList, 20.0f, 0, NumOptions, 1, Selected, 0, true);
for(int i = 0; i < NumOptions; i++)
{
@ -448,14 +469,37 @@ void CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
if(Item.m_Visible)
{
CUIRect Label, Row;
Item.m_Rect.VMargin(5.0f, &Row);
// player info
Row.VSplitLeft(Row.h, &Label, &Row);
Label.y += 2.0f;
CTeeRenderInfo Info = m_pClient->m_aClients[aPlayerIDs[i]].m_RenderInfo;
Info.m_Size = Item.m_Rect.h;
Item.m_Rect.HSplitTop(5.0f, 0, &Item.m_Rect); // some margin from the top
RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1,0), vec2(Item.m_Rect.x+Item.m_Rect.h/2, Item.m_Rect.y+Item.m_Rect.h/2));
Item.m_Rect.x +=Info.m_Size;
Info.m_Size = Label.h;
RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(Label.x + Label.h / 2, Label.y + Label.h / 2));
Row.VSplitLeft(2*Spacing, 0, &Row);
if(g_Config.m_ClShowUserId)
{
Row.VSplitLeft(Row.h, &Label, &Row);
Label.y += 2.0f;
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, Label.x, Label.y, Label.h*ms_FontmodHeight*0.8f, TEXTFLAG_RENDER);
RenderTools()->DrawClientID(TextRender(), &Cursor, aPlayerIDs[i]);
}
Row.VSplitLeft(Spacing, 0, &Row);
Row.VSplitLeft(NameWidth, &Label, &Row);
Label.y += 2.0f;
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%2d: %s", aPlayerIDs[i], g_Config.m_ClShowsocial ? m_pClient->m_aClients[aPlayerIDs[i]].m_aName : "");
UI()->DoLabelScaled(&Item.m_Rect, aBuf, 16.0f, CUI::ALIGN_LEFT);
str_format(aBuf, sizeof(aBuf), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[aPlayerIDs[i]].m_aName : "");
UI()->DoLabel(&Label, aBuf, Label.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
Row.VSplitLeft(Spacing, 0, &Row);
Row.VSplitLeft(ClanWidth, &Label, &Row);
Label.y += 2.0f;
str_format(aBuf, sizeof(aBuf), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[aPlayerIDs[i]].m_aClan : "");
UI()->DoLabel(&Label, aBuf, Label.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
}
}
@ -507,37 +551,40 @@ void CMenus::RenderServerControl(CUIRect MainView)
}
bool Authed = Client()->RconAuthed();
MainView.HSplitBottom(80.0f, &MainView, 0);
if(pNotification && !Authed)
{
MainView.HSplitTop(20.0f, 0, &MainView);
// only print notice
CUIRect Bar;
MainView.HSplitTop(45.0f, &Bar, &MainView);
RenderTools()->DrawUIRect(&Bar, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 10.0f);
RenderTools()->DrawUIRect(&Bar, vec4(0.0f, 0.0f, 0.0f, 0.25f+ms_BackgroundAlpha), CUI::CORNER_ALL, 5.0f);
Bar.HMargin(15.0f, &Bar);
UI()->DoLabelScaled(&Bar, pNotification, 14.0f, CUI::ALIGN_CENTER);
return;
}
// tab bar
CUIRect Bottom, Extended, TabBar, Button;
MainView.HSplitTop(20.0f, &Bottom, &MainView);
RenderTools()->DrawUIRect(&Bottom, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_T, 10.0f);
MainView.HSplitTop(20.0f, &TabBar, &MainView);
{
TabBar.VSplitLeft(TabBar.w/3, &Button, &TabBar);
static int s_Button0 = 0;
if(DoButton_MenuTab(&s_Button0, Localize("Change settings"), s_ControlPage == 0, &Button, 0))
s_ControlPage = 0;
const float NotActiveAlpha = 0.5f;
CUIRect Bottom, Extended, Button, Row, Note;
MainView.HSplitTop(3.0f, 0, &MainView);
MainView.HSplitTop(25.0f, &Row, &MainView);
Row.VSplitLeft(Row.w/3-1.5f, &Button, &Row);
static CButtonContainer s_Button0;
if(DoButton_MenuTabTop(&s_Button0, Localize("Change settings"), false, &Button, s_ControlPage == 0 ? 1.0f : NotActiveAlpha, 1.0f, CUI::CORNER_T, 5.0f, 0.25f))
s_ControlPage = 0;
TabBar.VSplitMid(&Button, &TabBar);
static int s_Button1 = 0;
if(DoButton_MenuTab(&s_Button1, Localize("Kick player"), s_ControlPage == 1, &Button, 0))
s_ControlPage = 1;
Row.VSplitLeft(1.5f, 0, &Row);
Row.VSplitMid(&Button, &Row);
Button.VMargin(1.5f, &Button);
static CButtonContainer s_Button1;
if(DoButton_MenuTabTop(&s_Button1, Localize("Kick player"), false, &Button, s_ControlPage == 1 ? 1.0f : NotActiveAlpha, 1.0f, CUI::CORNER_T, 5.0f, 0.25f))
s_ControlPage = 1;
static int s_Button2 = 0;
if(DoButton_MenuTab(&s_Button2, Localize("Move player to spectators"), s_ControlPage == 2, &TabBar, 0))
s_ControlPage = 2;
}
Row.VSplitLeft(1.5f, 0, &Button);
static CButtonContainer s_Button2;
if(DoButton_MenuTabTop(&s_Button2, Localize("Move player to spectators"), false, &Button, s_ControlPage == 2 ? 1.0f : NotActiveAlpha, 1.0f, CUI::CORNER_T, 5.0f, 0.25f))
s_ControlPage = 2;
if(s_ControlPage == 1)
{
@ -552,26 +599,26 @@ void CMenus::RenderServerControl(CUIRect MainView)
else if(s_ControlPage == 2 && !m_pClient->m_ServerSettings.m_SpecVote)
pNotification = Localize("Server does not allow voting to move players to spectators");
if(pNotification && !Authed)
{
MainView.HSplitTop(20.0f+45.0f, &MainView, 0);
}
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), CUI::CORNER_B, 5.0f);
MainView.HSplitTop(20.0f, 0, &MainView);
if(pNotification && !Authed)
{
// only print notice
CUIRect Bar;
MainView.HSplitTop(45.0f, &Bar, &MainView);
RenderTools()->DrawUIRect(&Bar, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 10.0f);
Bar.HMargin(15.0f, &Bar);
UI()->DoLabelScaled(&Bar, pNotification, 14.0f, CUI::ALIGN_CENTER);
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
MainView.HMargin(15.0f, &MainView);
UI()->DoLabelScaled(&MainView, pNotification, 14.0f, CUI::ALIGN_CENTER);
return;
}
// render background
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 10.0f);
MainView.Margin(10.0f, &MainView);
MainView.HSplitBottom(90.0f, &MainView, &Extended);
MainView.HSplitBottom(90.0f+2*20.0f, &MainView, &Extended);
RenderTools()->DrawUIRect(&Extended, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
// render page
MainView.HSplitBottom(ms_ButtonHeight + 5*2, &MainView, &Bottom);
Bottom.HMargin(5.0f, &Bottom);
if(s_ControlPage == 0)
RenderServerControlServer(MainView);
else if(s_ControlPage == 1)
@ -580,28 +627,33 @@ void CMenus::RenderServerControl(CUIRect MainView)
RenderServerControlKick(MainView, true);
// vote menu
Extended.Margin(5.0f, &Extended);
Extended.HSplitTop(20.0f, &Note, &Extended);
Extended.HSplitTop(20.0f, &Bottom, &Extended);
{
Bottom.VSplitRight(120.0f, &Bottom, &Button);
// render kick reason
CUIRect Reason, ClearButton;
CUIRect Reason, ClearButton, Label;
Bottom.VSplitRight(40.0f, &Bottom, 0);
Bottom.VSplitRight(160.0f, &Bottom, &Reason);
Reason.HSplitTop(5.0f, 0, &Reason);
Reason.VSplitRight(Reason.h, &Reason, &ClearButton);
const char *pLabel = Localize("Reason:");
UI()->DoLabelScaled(&Reason, pLabel, 14.0f, CUI::ALIGN_LEFT);
float w = TextRender()->TextWidth(0, 14.0f, pLabel, -1);
Reason.VSplitLeft(w+10.0f, 0, &Reason);
float w = TextRender()->TextWidth(0, Reason.h*ms_FontmodHeight*0.8f, pLabel, -1);
Reason.VSplitLeft(w + 10.0f, &Label, &Reason);
Label.y += 2.0f;
UI()->DoLabel(&Label, pLabel, Reason.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
static float s_Offset = 0.0f;
DoEditBox(&m_aCallvoteReason, &Reason, m_aCallvoteReason, sizeof(m_aCallvoteReason), 14.0f, &s_Offset, false, CUI::CORNER_L);
DoEditBox(&m_aCallvoteReason, &Reason, m_aCallvoteReason, sizeof(m_aCallvoteReason), Reason.h*ms_FontmodHeight*0.8f, &s_Offset, false, CUI::CORNER_L);
// clear button
{
static CButtonContainer s_ClearButton;
float Fade = ButtonFade(&s_ClearButton, 0.6f);
RenderTools()->DrawUIRect(&ClearButton, vec4(1.0f, 1.0f, 1.0f, 0.33f+(Fade/0.6f)*0.165f), CUI::CORNER_R, 3.0f);
UI()->DoLabel(&ClearButton, "x", ClearButton.h*ms_FontmodHeight, CUI::ALIGN_CENTER);
Label = ClearButton;
Label.y += 2.0f;
UI()->DoLabel(&Label, "x", Label.h*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
if(UI()->DoButtonLogic(s_ClearButton.GetID(), "x", 0, &ClearButton))
m_aCallvoteReason[0] = 0;
}
@ -616,7 +668,7 @@ void CMenus::RenderServerControl(CUIRect MainView)
else
{
// print notice
UI()->DoLabelScaled(&Bottom, pNotification, 14.0f, CUI::ALIGN_LEFT, Bottom.w);
UI()->DoLabel(&Note, pNotification, Note.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT, Note.w);
}
// extended features (only available when authed in rcon)

View file

@ -11,6 +11,10 @@
#include <engine/keys.h>
#include <engine/storage.h>
#include <engine/serverbrowser.h>
#include <engine/textrender.h>
#include <generated/client_data.h>
#include <generated/protocol.h>
#include "countryflags.h"
#include "menus.h"
@ -85,144 +89,3 @@ void CMenus::DoPopupMenu()
}
}
int CMenus::PopupFilter(CMenus *pMenus, CUIRect View)
{
CUIRect ServerFilter = View, FilterHeader;
const float FontSize = 12.0f;
// slected filter
CBrowserFilter *pFilter = &pMenus->m_lFilters[pMenus->m_SelectedFilter];
CServerFilterInfo FilterInfo;
pFilter->GetFilter(&FilterInfo);
// server filter
ServerFilter.HSplitTop(ms_ListheaderHeight, &FilterHeader, &ServerFilter);
pMenus->RenderTools()->DrawUIRect(&FilterHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f);
pMenus->RenderTools()->DrawUIRect(&ServerFilter, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f);
pMenus->UI()->DoLabelScaled(&FilterHeader, Localize("Server filter"), FontSize+2.0f, CUI::ALIGN_CENTER);
CUIRect Button;
ServerFilter.VSplitLeft(5.0f, 0, &ServerFilter);
ServerFilter.Margin(3.0f, &ServerFilter);
ServerFilter.VMargin(5.0f, &ServerFilter);
int NewSortHash = FilterInfo.m_SortHash;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterEmpty = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterEmpty, Localize("Has people playing"), FilterInfo.m_SortHash&IServerBrowser::FILTER_EMPTY, &Button))
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_EMPTY;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterSpectators = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterSpectators, Localize("Count players only"), FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS, &Button))
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_SPECTATORS;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterFull = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterFull, Localize("Server not full"), FilterInfo.m_SortHash&IServerBrowser::FILTER_FULL, &Button))
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_FULL;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterFriends = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterFriends, Localize("Show friends only"), FilterInfo.m_SortHash&IServerBrowser::FILTER_FRIENDS, &Button))
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_FRIENDS;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterPw = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterPw, Localize("No password"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PW, &Button))
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PW;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterCompatversion = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterCompatversion, Localize("Compatible version"), FilterInfo.m_SortHash&IServerBrowser::FILTER_COMPAT_VERSION, &Button))
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_COMPAT_VERSION;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterPure = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterPure, Localize("Standard gametype"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE, &Button) && pFilter->Custom() != CBrowserFilter::FILTER_STANDARD)
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PURE;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterPureMap = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterPureMap, Localize("Standard map"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE_MAP, &Button))
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PURE_MAP;
ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
static int s_BrFilterGametypeStrict = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterGametypeStrict, Localize("Strict gametype filter"), FilterInfo.m_SortHash&IServerBrowser::FILTER_GAMETYPE_STRICT, &Button))
NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_GAMETYPE_STRICT;
if(FilterInfo.m_SortHash != NewSortHash)
{
FilterInfo.m_SortHash = NewSortHash;
pFilter->SetFilter(&FilterInfo);
}
ServerFilter.HSplitTop(5.0f, 0, &ServerFilter);
ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter);
pMenus->UI()->DoLabelScaled(&Button, Localize("Game types:"), FontSize, CUI::ALIGN_LEFT);
Button.VSplitRight(60.0f, 0, &Button);
ServerFilter.HSplitTop(3.0f, 0, &ServerFilter);
static float Offset = 0.0f;
static int s_BrFilterGametype = 0;
if(pMenus->DoEditBox(&s_BrFilterGametype, &Button, FilterInfo.m_aGametype, sizeof(FilterInfo.m_aGametype), FontSize, &Offset))
pFilter->SetFilter(&FilterInfo);
{
ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter);
CUIRect EditBox;
Button.VSplitRight(60.0f, &Button, &EditBox);
pMenus->UI()->DoLabelScaled(&Button, Localize("Maximum ping:"), FontSize, CUI::ALIGN_LEFT);
char aBuf[5];
str_format(aBuf, sizeof(aBuf), "%d", FilterInfo.m_Ping);
static float Offset = 0.0f;
static int s_BrFilterPing = 0;
pMenus->DoEditBox(&s_BrFilterPing, &EditBox, aBuf, sizeof(aBuf), FontSize, &Offset);
int NewPing = clamp(str_toint(aBuf), 0, 999);
if(NewPing != FilterInfo.m_Ping)
{
FilterInfo.m_Ping = NewPing;
pFilter->SetFilter(&FilterInfo);
}
}
// server address
ServerFilter.HSplitTop(3.0f, 0, &ServerFilter);
ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter);
pMenus->UI()->DoLabelScaled(&Button, Localize("Server address:"), FontSize, CUI::ALIGN_LEFT);
Button.VSplitRight(60.0f, 0, &Button);
static float OffsetAddr = 0.0f;
static int s_BrFilterServerAddress = 0;
if(pMenus->DoEditBox(&s_BrFilterServerAddress, &Button, FilterInfo.m_aAddress, sizeof(FilterInfo.m_aAddress), FontSize, &OffsetAddr))
pFilter->SetFilter(&FilterInfo);
// player country
{
CUIRect Rect;
ServerFilter.HSplitTop(3.0f, 0, &ServerFilter);
ServerFilter.HSplitTop(26.0f, &Button, &ServerFilter);
Button.VSplitRight(60.0f, &Button, &Rect);
Button.HMargin(3.0f, &Button);
static int s_BrFilterCountry = 0;
if(pMenus->DoButton_CheckBox(&s_BrFilterCountry, Localize("Player country:"), FilterInfo.m_SortHash&IServerBrowser::FILTER_COUNTRY, &Button))
{
FilterInfo.m_SortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY;
pFilter->SetFilter(&FilterInfo);
}
float OldWidth = Rect.w;
Rect.w = Rect.h*2;
Rect.x += (OldWidth-Rect.w)/2.0f;
vec4 Color(1.0f, 1.0f, 1.0f, FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY?1.0f: 0.5f);
pMenus->m_pClient->m_pCountryFlags->Render(FilterInfo.m_Country, &Color, Rect.x, Rect.y, Rect.w, Rect.h);
static int s_BrFilterCountryIndex = 0;
if(FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY && pMenus->UI()->DoButtonLogic(&s_BrFilterCountryIndex, "", 0, &Rect))
pMenus->m_Popup = POPUP_COUNTRY;
}
return 0;
}

View file

@ -14,6 +14,7 @@
#include <generated/protocol.h>
#include <generated/client_data.h>
#include <game/client/components/maplayers.h>
#include <game/client/components/sounds.h>
#include <game/client/ui.h>
#include <game/client/render.h>
@ -577,6 +578,93 @@ public:
bool operator<(const CLanguage &Other) { return m_Name < Other.m_Name; }
};
int CMenus::ThemeScan(const char *pName, int IsDir, int DirType, void *pUser)
{
CMenus *pSelf = (CMenus *)pUser;
int l = str_length(pName);
if(l < 5 || IsDir || str_comp(pName+l-4, ".map") != 0)
return 0;
char aFullName[128];
char aThemeName[128];
str_copy(aFullName, pName, min((int)sizeof(aFullName),l-3));
l = str_length(aFullName);
bool isDay = false;
bool isNight = false;
if(l > 4 && str_comp(aFullName+l-4, "_day") == 0)
{
str_copy(aThemeName, pName, min((int)sizeof(aThemeName),l-3));
isDay = true;
}
else if(l > 6 && str_comp(aFullName+l-6, "_night") == 0)
{
str_copy(aThemeName, pName, min((int)sizeof(aThemeName),l-5));
isNight = true;
}
else
str_copy(aThemeName, aFullName, sizeof(aThemeName));
if(str_comp(aThemeName, "none") == 0) // "none" is reserved, disallowed for maps
return 0;
// try to edit an existing theme
for(int i = 0; i < pSelf->m_lThemes.size(); i++)
{
if(str_comp(pSelf->m_lThemes[i].m_Name, aThemeName) == 0)
{
if(isDay)
pSelf->m_lThemes[i].m_HasDay = true;
if(isNight)
pSelf->m_lThemes[i].m_HasNight = true;
return 0;
}
}
// make new theme
CTheme Theme(aThemeName, isDay, isNight);
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "added theme %s from ui/themes/%s", aThemeName, pName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
pSelf->m_lThemes.add(Theme);
return 0;
}
int CMenus::ThemeIconScan(const char *pName, int IsDir, int DirType, void *pUser)
{
CMenus *pSelf = (CMenus *)pUser;
int l = str_length(pName);
if(l < 4 || IsDir || str_comp(pName+l-4, ".png") != 0)
return 0;
char aThemeName[128];
str_copy(aThemeName, pName, min((int)sizeof(aThemeName),l-3));
// save icon for an existing theme
for(sorted_array<CTheme>::range r = pSelf->m_lThemes.all(); !r.empty(); r.pop_front()) // bit slow but whatever
{
if(str_comp(r.front().m_Name, aThemeName) == 0 || (!r.front().m_Name[0] && str_comp(aThemeName, "none") == 0))
{
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "ui/themes/%s", pName);
CImageInfo Info;
if(!pSelf->Graphics()->LoadPNG(&Info, aBuf, DirType))
{
str_format(aBuf, sizeof(aBuf), "failed to load theme icon from %s", pName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
return 0;
}
str_format(aBuf, sizeof(aBuf), "loaded theme icon %s", pName);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf);
r.front().m_IconTexture = pSelf->Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
return 0;
}
}
return 0; // no existing theme
}
void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array<CLanguage> *pLanguages)
{
// read file data into buffer
@ -588,20 +676,20 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array<
return;
}
int FileSize = (int)io_length(File);
char *pFileData = (char *)mem_alloc(FileSize+1, 1);
char *pFileData = (char *)mem_alloc(FileSize, 1);
io_read(File, pFileData, FileSize);
pFileData[FileSize] = 0;
io_close(File);
// parse json data
json_settings JsonSettings;
mem_zero(&JsonSettings, sizeof(JsonSettings));
char aError[256];
json_value *pJsonData = json_parse_ex(&JsonSettings, pFileData, aError);
json_value *pJsonData = json_parse_ex(&JsonSettings, pFileData, FileSize, aError);
mem_free(pFileData);
if(pJsonData == 0)
{
pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, pFilename, aError);
mem_free(pFileData);
return;
}
@ -613,19 +701,19 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array<
{
char aFileName[128];
str_format(aFileName, sizeof(aFileName), "languages/%s.json", (const char *)rStart[i]["file"]);
pLanguages->add(CLanguage((const char *)rStart[i]["name"], aFileName, (long)rStart[i]["code"]));
pLanguages->add(CLanguage((const char *)rStart[i]["name"], aFileName, (json_int_t)rStart[i]["code"]));
}
}
// clean up
json_value_free(pJsonData);
mem_free(pFileData);
}
void CMenus::RenderLanguageSelection(CUIRect MainView, bool Header)
{
static int s_LanguageList = 0;
static int s_SelectedLanguage = 0;
static int s_SelectedLanguage = -1;
static int s_OldSelected = -1;
static sorted_array<CLanguage> s_Languages;
static CListBoxState s_ListBoxState;
@ -641,6 +729,17 @@ void CMenus::RenderLanguageSelection(CUIRect MainView, bool Header)
}
}
if(s_SelectedLanguage != -1 && m_ActiveListBox != ACTLB_LANG)
{
s_OldSelected = s_SelectedLanguage;
s_SelectedLanguage = -1;
}
static int s_LangID = 0;
if(s_SelectedLanguage == -1 && UI()->MouseInside(&MainView))
{
s_SelectedLanguage = s_OldSelected;
m_ActiveListBox = ACTLB_LANG;
}
int OldSelected = s_SelectedLanguage;
if(Header)
@ -660,7 +759,7 @@ void CMenus::RenderLanguageSelection(CUIRect MainView, bool Header)
vec4 Color(1.0f, 1.0f, 1.0f, 1.0f);
m_pClient->m_pCountryFlags->Render(r.front().m_CountryCode, &Color, Rect.x, Rect.y, Rect.w, Rect.h);
Item.m_Rect.y += 2.0f;
if(!str_comp(s_Languages[s_SelectedLanguage].m_Name, r.front().m_Name))
if(s_SelectedLanguage != -1 && !str_comp(s_Languages[s_SelectedLanguage].m_Name, r.front().m_Name))
{
TextRender()->TextColor(0.0f, 0.0f, 0.0f, 1.0f);
TextRender()->TextOutlineColor(1.0f, 1.0f, 1.0f, 0.25f);
@ -677,25 +776,133 @@ void CMenus::RenderLanguageSelection(CUIRect MainView, bool Header)
if(OldSelected != s_SelectedLanguage)
{
m_ActiveListBox = ACTLB_LANG;
str_copy(g_Config.m_ClLanguagefile, s_Languages[s_SelectedLanguage].m_FileName, sizeof(g_Config.m_ClLanguagefile));
g_Localization.Load(s_Languages[s_SelectedLanguage].m_FileName, Storage(), Console());
}
}
void CMenus::RenderThemeSelection(CUIRect MainView, bool Header)
{
static int s_ThemeList = 0;
static int s_SelectedTheme = -1;
static int s_OldSelected = -1;
static CListBoxState s_ListBoxState_Theme;
if(m_lThemes.size() == 0) // not loaded yet
{
m_lThemes.add(CTheme("", false, false)); // no theme
Storage()->ListDirectory(IStorage::TYPE_ALL, "ui/themes", ThemeScan, (CMenus*)this);
Storage()->ListDirectory(IStorage::TYPE_ALL, "ui/themes", ThemeIconScan, (CMenus*)this);
for(int i = 0; i < m_lThemes.size(); i++)
if(str_comp(m_lThemes[i].m_Name, g_Config.m_ClMenuMap) == 0)
{
s_SelectedTheme = i;
break;
}
}
if(s_SelectedTheme != -1 && m_ActiveListBox != ACTLB_THEME)
{
s_OldSelected = s_SelectedTheme;
s_SelectedTheme = -1;
}
if(s_SelectedTheme == -1 && UI()->MouseInside(&MainView))
{
s_SelectedTheme = s_OldSelected;
m_ActiveListBox = ACTLB_THEME;
}
int OldSelected = s_SelectedTheme;
if(Header)
UiDoListboxHeader(&s_ListBoxState_Theme, &MainView, Localize("Theme"), 20.0f, 2.0f);
UiDoListboxStart(&s_ListBoxState_Theme, &s_ThemeList, 20.0f, 0, m_lThemes.size(), 1, s_SelectedTheme, Header?0:&MainView, Header?true:false);
for(sorted_array<CTheme>::range r = m_lThemes.all(); !r.empty(); r.pop_front())
{
CListboxItem Item = UiDoListboxNextItem(&s_ListBoxState_Theme, &r.front());
if(Item.m_Visible)
{
CUIRect Rect;
Item.m_Rect.VSplitLeft(Item.m_Rect.h*2.0f, &Rect, &Item.m_Rect);
Rect.VMargin(6.0f, &Rect);
Rect.HMargin(3.0f, &Rect);
vec4 Color(1.0f, 1.0f, 1.0f, 1.0f);
// draw icon if it exists
if(r.front().m_IconTexture.IsValid())
{
Graphics()->TextureSet(r.front().m_IconTexture);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
IGraphics::CQuadItem QuadItem(Rect.x, Rect.y, Rect.w, Rect.h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
}
Item.m_Rect.y += 2.0f;
char aName[128];
if(r.front().m_Name[0])
{
if(r.front().m_HasDay && r.front().m_HasNight)
str_format(aName, sizeof(aName), "%s", r.front().m_Name.cstr());
else if(r.front().m_HasDay && !r.front().m_HasNight)
str_format(aName, sizeof(aName), "%s (day)", r.front().m_Name.cstr());
else if(!r.front().m_HasDay && r.front().m_HasNight)
str_format(aName, sizeof(aName), "%s (night)", r.front().m_Name.cstr());
else // generic
str_format(aName, sizeof(aName), "%s", r.front().m_Name.cstr());
}
else
str_copy(aName, "(none)", sizeof(aName));
if(s_SelectedTheme != -1 && !str_comp(m_lThemes[s_SelectedTheme].m_Name, r.front().m_Name))
{
TextRender()->TextColor(0.0f, 0.0f, 0.0f, 1.0f);
TextRender()->TextOutlineColor(1.0f, 1.0f, 1.0f, 0.25f);
UI()->DoLabelScaled(&Item.m_Rect, aName, Item.m_Rect.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f);
}
else
UI()->DoLabelScaled(&Item.m_Rect, aName, Item.m_Rect.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
}
}
s_SelectedTheme = UiDoListboxEnd(&s_ListBoxState_Theme, 0);
if(OldSelected != s_SelectedTheme)
{
m_ActiveListBox = ACTLB_THEME;
str_copy(g_Config.m_ClMenuMap, m_lThemes[s_SelectedTheme].m_Name, sizeof(g_Config.m_ClMenuMap));
if(m_lThemes[s_SelectedTheme].m_Name[0])
g_Config.m_ClShowMenuMap = 1;
else
g_Config.m_ClShowMenuMap = 0;
m_pClient->m_pMapLayersBackGround->BackgroundMapUpdate();
}
}
void CMenus::RenderSettingsGeneral(CUIRect MainView)
{
CUIRect Label, Button, Game, Client, BottomView;
CUIRect Label, Button, Game, Client, BottomView, Background;
// cut view
MainView.HSplitBottom(80.0f, &MainView, &BottomView);
BottomView.HSplitTop(20.f, 0, &BottomView);
// render game menu backgrounds
int NumOptions = g_Config.m_ClNameplates ? 9 : 6;
int NumOptions = g_Config.m_ClNameplates ? 6 : 3;
float ButtonHeight = 20.0f;
float Spacing = 2.0f;
float BackgroundHeight = (float)(NumOptions+1)*ButtonHeight+(float)NumOptions*Spacing;
if(this->Client()->State() == IClient::STATE_ONLINE)
Background = MainView;
else
MainView.HSplitTop(20.0f, 0, &Background);
RenderTools()->DrawUIRect(&Background, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), this->Client()->State() == IClient::STATE_OFFLINE ? CUI::CORNER_ALL : CUI::CORNER_B, 5.0f);
MainView.HSplitTop(20.0f, 0, &MainView);
MainView.HSplitTop(BackgroundHeight, &Game, &MainView);
RenderTools()->DrawUIRect(&Game, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
@ -710,46 +917,99 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
MainView.HSplitTop(BackgroundHeight, &Client, &MainView);
RenderTools()->DrawUIRect(&Client, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
CUIRect GameLeft, GameRight;
// render game menu
Game.HSplitTop(ButtonHeight, &Label, &Game);
Label.y += 2.0f;
UI()->DoLabel(&Label, Localize("Game"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
Game.VSplitMid(&GameLeft, &GameRight);
GameLeft.VSplitRight(Spacing * 0.5f, &GameLeft, 0);
GameRight.VSplitLeft(Spacing * 0.5f, 0, &GameRight);
// left side
GameLeft.HSplitTop(Spacing, 0, &GameLeft);
GameLeft.HSplitTop(ButtonHeight, &Button, &GameLeft);
static int s_DynamicCameraButton = 0;
if(DoButton_CheckBox(&s_DynamicCameraButton, Localize("Dynamic Camera"), g_Config.m_ClMouseDeadzone != 0, &Button))
if(DoButton_CheckBox(&s_DynamicCameraButton, Localize("Dynamic Camera"), g_Config.m_ClDynamicCamera, &Button))
{
if(g_Config.m_ClMouseDeadzone)
if(g_Config.m_ClDynamicCamera)
{
g_Config.m_ClMouseFollowfactor = 0;
g_Config.m_ClMouseMaxDistance = 400;
g_Config.m_ClMouseDeadzone = 0;
g_Config.m_ClDynamicCamera = 0;
// force to defaults when using the GUI
g_Config.m_ClMouseMaxDistanceStatic = 400;
// g_Config.m_ClMouseFollowfactor = 0;
// g_Config.m_ClMouseDeadzone = 0;
}
else
{
g_Config.m_ClDynamicCamera = 1;
// force to defaults when using the GUI
g_Config.m_ClMouseMaxDistanceDynamic = 1000;
g_Config.m_ClMouseFollowfactor = 60;
g_Config.m_ClMouseMaxDistance = 1000;
g_Config.m_ClMouseDeadzone = 300;
}
}
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
GameLeft.HSplitTop(Spacing, 0, &GameLeft);
GameLeft.HSplitTop(ButtonHeight, &Button, &GameLeft);
static int s_AutoswitchWeapons = 0;
if(DoButton_CheckBox(&s_AutoswitchWeapons, Localize("Switch weapon on pickup"), g_Config.m_ClAutoswitchWeapons, &Button))
g_Config.m_ClAutoswitchWeapons ^= 1;
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
GameLeft.HSplitTop(Spacing, 0, &GameLeft);
GameLeft.HSplitTop(ButtonHeight, &Button, &GameLeft);
static int s_Nameplates = 0;
if(DoButton_CheckBox(&s_Nameplates, Localize("Show name plates"), g_Config.m_ClNameplates, &Button))
g_Config.m_ClNameplates ^= 1;
if(g_Config.m_ClNameplates)
{
GameLeft.HSplitTop(Spacing, 0, &GameLeft);
GameLeft.HSplitTop(ButtonHeight, &Button, &GameLeft);
Button.VSplitLeft(ButtonHeight, 0, &Button);
static int s_NameplatesAlways = 0;
if(DoButton_CheckBox(&s_NameplatesAlways, Localize("Always show name plates"), g_Config.m_ClNameplatesAlways, &Button))
g_Config.m_ClNameplatesAlways ^= 1;
GameLeft.HSplitTop(Spacing, 0, &GameLeft);
GameLeft.HSplitTop(ButtonHeight, &Button, &GameLeft);
Button.VSplitLeft(ButtonHeight, 0, &Button);
DoScrollbarOption(&g_Config.m_ClNameplatesSize, &g_Config.m_ClNameplatesSize, &Button, Localize("Size"), 100.0f, 0, 100);
GameLeft.HSplitTop(Spacing, 0, &GameLeft);
GameLeft.HSplitTop(ButtonHeight, &Button, &GameLeft);
Button.VSplitLeft(ButtonHeight, 0, &Button);
static int s_NameplatesTeamcolors = 0;
if(DoButton_CheckBox(&s_NameplatesTeamcolors, Localize("Use team colors for name plates"), g_Config.m_ClNameplatesTeamcolors, &Button))
g_Config.m_ClNameplatesTeamcolors ^= 1;
}
// right side
GameRight.HSplitTop(Spacing, 0, &GameRight);
GameRight.HSplitTop(ButtonHeight, &Button, &GameRight);
static int s_Showhud = 0;
if(DoButton_CheckBox(&s_Showhud, Localize("Show ingame HUD"), g_Config.m_ClShowhud, &Button))
g_Config.m_ClShowhud ^= 1;
GameRight.HSplitTop(Spacing, 0, &GameRight);
GameRight.HSplitTop(ButtonHeight, &Button, &GameRight);
static int s_Showsocial = 0;
if(DoButton_CheckBox(&s_Showsocial, Localize("Show social"), g_Config.m_ClShowsocial, &Button))
g_Config.m_ClShowsocial ^= 1;
GameRight.HSplitTop(Spacing, 0, &GameRight);
GameRight.HSplitTop(ButtonHeight, &Button, &GameRight);
static int s_ShowUserId = 0;
if(DoButton_CheckBox(&s_ShowUserId, Localize("Show user IDs"), g_Config.m_ClShowUserId, &Button))
g_Config.m_ClShowUserId ^= 1;
// show chat messages button
if(g_Config.m_ClShowsocial)
{
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
GameRight.HSplitTop(Spacing, 0, &GameRight);
GameRight.HSplitTop(ButtonHeight, &Button, &GameRight);
Button.VSplitLeft(ButtonHeight, 0, &Button);
RenderTools()->DrawUIRect(&Button, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
CUIRect Text;
Button.VSplitLeft(ButtonHeight+5.0f, 0, &Button);
@ -760,52 +1020,18 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
Text.y += 2.0f;
UI()->DoLabel(&Text, aBuf, Text.h*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT);
Button.VSplitLeft(100.0f, &Button, 0);
Button.VSplitLeft(119.0f, &Button, 0);
if(g_Config.m_ClFilterchat == 0)
str_format(aBuf, sizeof(aBuf), "everyone");
str_format(aBuf, sizeof(aBuf), Localize("everyone"));
else if(g_Config.m_ClFilterchat == 1)
str_format(aBuf, sizeof(aBuf), "friends only");
str_format(aBuf, sizeof(aBuf), Localize("friends only"));
else if(g_Config.m_ClFilterchat == 2)
str_format(aBuf, sizeof(aBuf), "no one");
str_format(aBuf, sizeof(aBuf), Localize("no one"));
static CButtonContainer s_ButtonFilterchat;
if(DoButton_Menu(&s_ButtonFilterchat, aBuf, 0, &Button))
g_Config.m_ClFilterchat = (g_Config.m_ClFilterchat + 1) % 3;
}
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
static int s_Showsocial = 0;
if(DoButton_CheckBox(&s_Showsocial, Localize("Show social"), g_Config.m_ClShowsocial, &Button))
g_Config.m_ClShowsocial ^= 1;
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
static int s_Nameplates = 0;
if(DoButton_CheckBox(&s_Nameplates, Localize("Show name plates"), g_Config.m_ClNameplates, &Button))
g_Config.m_ClNameplates ^= 1;
if(g_Config.m_ClNameplates)
{
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
Button.VSplitLeft(ButtonHeight, 0, &Button);
static int s_NameplatesAlways = 0;
if(DoButton_CheckBox(&s_NameplatesAlways, Localize("Always show name plates"), g_Config.m_ClNameplatesAlways, &Button))
g_Config.m_ClNameplatesAlways ^= 1;
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
Button.VSplitLeft(ButtonHeight, 0, &Button);
DoScrollbarOption(&g_Config.m_ClNameplatesSize, &g_Config.m_ClNameplatesSize, &Button, Localize("Size"), 100.0f, 0, 100);
Game.HSplitTop(Spacing, 0, &Game);
Game.HSplitTop(ButtonHeight, &Button, &Game);
Button.VSplitLeft(ButtonHeight, 0, &Button);
static int s_NameplatesTeamcolors = 0;
if(DoButton_CheckBox(&s_NameplatesTeamcolors, Localize("Use team colors for name plates"), g_Config.m_ClNameplatesTeamcolors, &Button))
g_Config.m_ClNameplatesTeamcolors ^= 1;
}
// render client menu
Client.HSplitTop(ButtonHeight, &Label, &Client);
Label.y += 2.0f;
@ -847,8 +1073,13 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
MainView.HSplitTop(10.0f, 0, &MainView);
// render language selection
RenderLanguageSelection(MainView);
// render language and theme selection
CUIRect LanguageView, ThemeView;
MainView.VSplitMid(&LanguageView, &ThemeView);
LanguageView.VSplitRight(1, &LanguageView, 0);
ThemeView.VSplitLeft(1, 0, &ThemeView);
RenderLanguageSelection(LanguageView);
RenderThemeSelection(ThemeView);
// reset button
Spacing = 3.0f;
@ -862,8 +1093,9 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
static CButtonContainer s_ResetButton;
if(DoButton_Menu(&s_ResetButton, Localize("Reset"), 0, &Button))
{
g_Config.m_ClDynamicCamera = 1;
g_Config.m_ClMouseMaxDistanceDynamic = 1000;
g_Config.m_ClMouseFollowfactor = 60;
g_Config.m_ClMouseMaxDistance = 1000;
g_Config.m_ClMouseDeadzone = 300;
g_Config.m_ClAutoswitchWeapons = 1;
g_Config.m_ClShowhud = 1;
@ -881,15 +1113,20 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView)
void CMenus::RenderSettingsPlayer(CUIRect MainView)
{
CUIRect Button, Left, Right, TopView, Label;
CUIRect Button, Left, Right, TopView, Label, Background;
// render game menu backgrounds
float ButtonHeight = 20.0f;
float Spacing = 2.0f;
float BackgroundHeight = 2.0f*ButtonHeight+Spacing;
MainView.HSplitBottom(80.0f, &MainView, 0); // now we have the total rect for the settings#
if(this->Client()->State() == IClient::STATE_ONLINE)
Background = MainView;
else
MainView.HSplitTop(20.0f, 0, &Background);
RenderTools()->DrawUIRect(&Background, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), Client()->State() == IClient::STATE_OFFLINE ? CUI::CORNER_ALL : CUI::CORNER_B, 5.0f);
MainView.HSplitTop(20.0f, 0, &MainView);
MainView.HSplitBottom(80.0f, &MainView, 0); // now we have the total rect for the settings
MainView.HSplitTop(BackgroundHeight, &TopView, &MainView);
RenderTools()->DrawUIRect(&TopView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
@ -975,10 +1212,7 @@ void CMenus::RenderSettingsTeeCustom(CUIRect MainView)
float SpacingH = 2.0f;
float SpacingW = 3.0f;
float ButtonHeight = 20.0f;
float BoxSize = 297.0f;
float BackgroundHeight = (ButtonHeight+SpacingH)*3.0f+BoxSize;
MainView.HSplitTop(BackgroundHeight, &MainView, 0);
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
MainView.HSplitTop(ButtonHeight, &Label, &MainView);
@ -1019,7 +1253,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
{
static bool s_CustomSkinMenu = false;
CUIRect Button, Label, BottomView, Preview;
CUIRect Button, Label, BottomView, Preview, Background;
// cut view
MainView.HSplitBottom(80.0f, &MainView, &BottomView);
@ -1034,6 +1268,11 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
if(!s_CustomSkinMenu)
BackgroundHeight = (ButtonHeight+SpacingH)*2.0f+SkinHeight;
if(this->Client()->State() == IClient::STATE_ONLINE)
Background = MainView;
else
MainView.HSplitTop(20.0f, 0, &Background);
RenderTools()->DrawUIRect(&Background, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), Client()->State() == IClient::STATE_OFFLINE ? CUI::CORNER_ALL : CUI::CORNER_B, 5.0f);
MainView.HSplitTop(20.0f, 0, &MainView);
MainView.HSplitTop(BackgroundHeight, &Preview, &MainView);
RenderTools()->DrawUIRect(&Preview, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
@ -1167,33 +1406,81 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
void CMenus::RenderSettingsControls(CUIRect MainView)
{
MainView.HSplitTop(20.0f, 0, &MainView);
// cut view
CUIRect BottomView, Button;
CUIRect BottomView, Button, Background;
MainView.HSplitBottom(80.0f, &MainView, &BottomView);
if(this->Client()->State() == IClient::STATE_ONLINE)
Background = MainView;
else
MainView.HSplitTop(20.0f, 0, &Background);
RenderTools()->DrawUIRect(&Background, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), Client()->State() == IClient::STATE_OFFLINE ? CUI::CORNER_ALL : CUI::CORNER_B, 5.0f);
MainView.HSplitTop(20.0f, 0, &MainView);
BottomView.HSplitTop(20.f, 0, &BottomView);
float HeaderHeight = 20.0f;
// split scrollbar from main view
CUIRect Scroll;
MainView.VSplitRight(20.0f, &MainView, &Scroll);
RenderTools()->DrawUIRect(&Scroll, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
const float HeaderHeight = 20.0f;
const float ItemHeight = 20.0f+2.0f;
const float MainViewH = MainView.h;
// make scrollbar
static int s_ScrollBar = 0;
static int s_ScrollNum = 0;
static float s_ScrollValue = 0.f;
static float TotalHeight = 0.f;
Scroll.HMargin(5.0f, &Scroll);
s_ScrollValue = DoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue);
UI()->ClipEnable(&MainView);
if(TotalHeight - MainView.h > 0)
MainView.y -= s_ScrollValue*(TotalHeight - MainView.h);
TotalHeight = 0.f;
static int s_MovementDropdown = 0;
float Split = DoDropdownMenu(&s_MovementDropdown, &MainView, Localize("Movement"), HeaderHeight, RenderSettingsControlsMovement);
static bool s_MovementActive = true;
float Split = DoIndependentDropdownMenu(&s_MovementDropdown, &MainView, Localize("Movement"), HeaderHeight, RenderSettingsControlsMovement, &s_MovementActive);
TotalHeight += Split+10.0f;
MainView.HSplitTop(Split+10.0f, 0, &MainView);
static int s_WeaponDropdown = 0;
Split = DoDropdownMenu(&s_WeaponDropdown, &MainView, Localize("Weapon"), HeaderHeight, RenderSettingsControlsWeapon);
static bool s_WeaponActive = true;
Split = DoIndependentDropdownMenu(&s_WeaponDropdown, &MainView, Localize("Weapon"), HeaderHeight, RenderSettingsControlsWeapon, &s_WeaponActive);
TotalHeight += Split+10.0f;
MainView.HSplitTop(Split+10.0f, 0, &MainView);
static int s_VotingDropdown = 0;
Split = DoDropdownMenu(&s_VotingDropdown, &MainView, Localize("Voting"), HeaderHeight, RenderSettingsControlsVoting);
static bool s_VotingActive = true;
Split = DoIndependentDropdownMenu(&s_VotingDropdown, &MainView, Localize("Voting"), HeaderHeight, RenderSettingsControlsVoting, &s_VotingActive);
TotalHeight += Split+10.0f;
MainView.HSplitTop(Split+10.0f, 0, &MainView);
static int s_ChatDropdown = 0;
Split = DoDropdownMenu(&s_ChatDropdown, &MainView, Localize("Chat"), HeaderHeight, RenderSettingsControlsChat);
static bool s_ChatActive = true;
Split = DoIndependentDropdownMenu(&s_ChatDropdown, &MainView, Localize("Chat"), HeaderHeight, RenderSettingsControlsChat, &s_ChatActive);
TotalHeight += Split+10.0f;
MainView.HSplitTop(Split+10.0f, 0, &MainView);
static int s_MiscDropdown = 0;
Split = DoDropdownMenu(&s_MiscDropdown, &MainView, Localize("Misc"), HeaderHeight, RenderSettingsControlsMisc);
static bool s_MiscActive = true;
Split = DoIndependentDropdownMenu(&s_MiscDropdown, &MainView, Localize("Misc"), HeaderHeight, RenderSettingsControlsMisc, &s_MiscActive);
TotalHeight += Split;
UI()->ClipDisable();
// handle scrolling
float ProperHeight = (TotalHeight-5*HeaderHeight-40.0f);
s_ScrollNum = /*ceil*/((ProperHeight-MainViewH)/ItemHeight);
if(s_ScrollNum <= 0)
s_ScrollNum = 1;
// We could && UI()->MouseInside(&MainView)), but that does not work well because the controls settings menu got holes
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP))
s_ScrollValue -= 3.0f/s_ScrollNum; // will be set to 0 by clamp if scrollnum is too small
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN))
s_ScrollValue += 3.0f/s_ScrollNum; // will be set to 1 by clamp if scrollnum is too small
s_ScrollValue = clamp(s_ScrollValue, 0.f, 1.f);
// reset button
float Spacing = 3.0f;
@ -1276,20 +1563,25 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
static int s_GfxTextureQuality = g_Config.m_GfxTextureQuality;
static int s_GfxTextureCompression = g_Config.m_GfxTextureCompression;
CUIRect Label, Button, ScreenLeft, ScreenRight, Texture, BottomView;
CUIRect Label, Button, ScreenLeft, ScreenRight, Texture, BottomView, Background;
// cut view
MainView.HSplitBottom(80.0f, &MainView, &BottomView);
BottomView.HSplitTop(20.f, 0, &BottomView);
// render screen menu background
int NumOptions = 3 + (!g_Config.m_GfxFullscreen);
int NumOptions = 3;// + (!g_Config.m_GfxFullscreen);
if(Graphics()->GetNumScreens() > 1)
++NumOptions;
float ButtonHeight = 20.0f;
float Spacing = 2.0f;
float BackgroundHeight = (float)(NumOptions+1)*ButtonHeight+(float)NumOptions*Spacing;
if(this->Client()->State() == IClient::STATE_ONLINE)
Background = MainView;
else
MainView.HSplitTop(20.0f, 0, &Background);
RenderTools()->DrawUIRect(&Background, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), Client()->State() == IClient::STATE_OFFLINE ? CUI::CORNER_ALL : CUI::CORNER_B, 5.0f);
MainView.HSplitTop(20.0f, 0, &MainView);
MainView.HSplitTop(BackgroundHeight, &ScreenLeft, &MainView);
RenderTools()->DrawUIRect(&ScreenLeft, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
@ -1327,12 +1619,6 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
Client()->ToggleWindowBordered();
}
ScreenLeft.HSplitTop(Spacing, 0, &ScreenLeft);
ScreenLeft.HSplitTop(ButtonHeight, &Button, &ScreenLeft);
static int s_ButtonGfxVsync = 0;
if(DoButton_CheckBox(&s_ButtonGfxVsync, Localize("V-Sync"), g_Config.m_GfxVsync, &Button))
Client()->ToggleWindowVSync();
// FSAA button
{
ScreenLeft.HSplitTop(Spacing, 0, &ScreenLeft);
@ -1362,6 +1648,12 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
}
}
ScreenRight.HSplitTop(Spacing, 0, &ScreenRight);
ScreenRight.HSplitTop(ButtonHeight, &Button, &ScreenRight);
static int s_ButtonGfxVsync = 0;
if(DoButton_CheckBox(&s_ButtonGfxVsync, Localize("V-Sync"), g_Config.m_GfxVsync, &Button))
Client()->ToggleWindowVSync();
ScreenRight.HSplitTop(Spacing, 0, &ScreenRight);
ScreenRight.HSplitTop(ButtonHeight, &Button, &ScreenRight);
@ -1449,7 +1741,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
RenderTools()->DrawUIRect(&HeaderLeft, vec4(0.30f, 0.4f, 1.0f, 0.5f), CUI::CORNER_T, 5.0f);
RenderTools()->DrawUIRect(&HeaderRight, vec4(0.0f, 0.0f, 0.0f, 0.5f), CUI::CORNER_T, 5.0f);
char aBuf[32];
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%s", Localize("Recommended"));
HeaderLeft.y += 2;
UI()->DoLabel(&HeaderLeft, aBuf, HeaderLeft.h*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
@ -1462,6 +1754,15 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
MainView.HSplitTop(Spacing, 0, &MainView);
CUIRect ListRec, ListOth;
MainView.VSplitMid(&ListRec, &ListOth);
ListRec.HSplitBottom(ButtonHeight, &ListRec, &Button);
ListRec.HSplitBottom(Spacing, &ListRec, 0);
RenderTools()->DrawUIRect(&Button, vec4(0.0f, 0.0f, 0.0f, 0.5f), CUI::CORNER_B, 5.0f);
int g = gcd(s_GfxScreenWidth, s_GfxScreenHeight);
str_format(aBuf, sizeof(aBuf), Localize("Current: %dx%d (%d:%d)"), s_GfxScreenWidth, s_GfxScreenHeight, s_GfxScreenWidth/g, s_GfxScreenHeight/g);
Button.y += 2;
UI()->DoLabel(&Button, aBuf, Button.h*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
ListRec.VSplitRight(1.5f, &ListRec, 0);
ListOth.VSplitLeft(1.5f, 0, &ListOth);
@ -1518,14 +1819,23 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
void CMenus::RenderSettingsSound(CUIRect MainView)
{
CUIRect Label, Button, Sound, Detail, BottomView;
CUIRect Label, Button, Sound, Detail, BottomView, Background;
// render sound menu background
int NumOptions = g_Config.m_SndEnable ? 3 : 1;
int NumOptions = g_Config.m_SndEnable ? 3 : 2;
float ButtonHeight = 20.0f;
float Spacing = 2.0f;
float BackgroundHeight = (float)(NumOptions+1)*ButtonHeight+(float)NumOptions*Spacing;
float TotalHeight = BackgroundHeight;
if(g_Config.m_SndEnable)
TotalHeight += 10.0f+2.0f*ButtonHeight+Spacing;
MainView.HSplitBottom(MainView.h-TotalHeight-20.0f, &MainView, &BottomView);
if(this->Client()->State() == IClient::STATE_ONLINE)
Background = MainView;
else
MainView.HSplitTop(20.0f, 0, &Background);
RenderTools()->DrawUIRect(&Background, vec4(0.0f, 0.0f, 0.0f, ms_BackgroundAlpha), Client()->State() == IClient::STATE_OFFLINE ? CUI::CORNER_ALL : CUI::CORNER_B, 5.0f);
MainView.HSplitTop(20.0f, 0, &MainView);
MainView.HSplitTop(BackgroundHeight, &Sound, &MainView);
RenderTools()->DrawUIRect(&Sound, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
@ -1540,7 +1850,7 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
RenderTools()->DrawUIRect(&Detail, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f);
}
static int s_SndEnable = g_Config.m_SndEnable;
static int s_SndInit = g_Config.m_SndInit;
static int s_SndRate = g_Config.m_SndRate;
// render sound menu
@ -1549,20 +1859,8 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
UI()->DoLabel(&Label, Localize("Sound"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER);
Sound.HSplitTop(Spacing, 0, &Sound);
Sound.HSplitTop(ButtonHeight, &Button, &Sound);
static int s_ButtonSndEnable = 0;
if(DoButton_CheckBox(&s_ButtonSndEnable, Localize("Use sounds"), g_Config.m_SndEnable, &Button))
{
g_Config.m_SndEnable ^= 1;
if(g_Config.m_SndEnable)
{
if(g_Config.m_SndMusic)
m_pClient->m_pSounds->Play(CSounds::CHN_MUSIC, SOUND_MENU, 1.0f);
}
else
m_pClient->m_pSounds->Stop(SOUND_MENU);
m_NeedRestartSound = g_Config.m_SndEnable && (!s_SndEnable || s_SndRate != g_Config.m_SndRate);
}
CUIRect UseSoundButton;
Sound.HSplitTop(ButtonHeight, &UseSoundButton, &Sound);
if(g_Config.m_SndEnable)
{
@ -1627,15 +1925,41 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
g_Config.m_SndRate = 48000;
}
m_NeedRestartSound = !s_SndEnable || s_SndRate != g_Config.m_SndRate;
m_NeedRestartSound = g_Config.m_SndInit && (!s_SndInit || s_SndRate != g_Config.m_SndRate);
}
Right.HSplitTop(ButtonHeight, &Button, &Right);
DoScrollbarOption(&g_Config.m_SndVolume, &g_Config.m_SndVolume, &Button, Localize("Volume"), 110.0f, 0, 100);
}
else
{
Sound.HSplitTop(Spacing, 0, &Sound);
Sound.HSplitTop(ButtonHeight, &Button, &Sound);
Button.VSplitLeft(ButtonHeight, 0, &Button);
static int s_ButtonInitSounds = 0;
if(DoButton_CheckBox(&s_ButtonInitSounds, Localize("Load the sound system"), g_Config.m_SndInit, &Button))
{
g_Config.m_SndInit ^= 1;
m_NeedRestartSound = g_Config.m_SndInit && (!s_SndInit || s_SndRate != g_Config.m_SndRate);
}
}
static int s_ButtonSndEnable = 0;
if(DoButton_CheckBox(&s_ButtonSndEnable, Localize("Use sounds"), g_Config.m_SndEnable, &UseSoundButton))
{
g_Config.m_SndEnable ^= 1;
if(g_Config.m_SndEnable)
{
g_Config.m_SndInit = 1;
if(g_Config.m_SndMusic)
m_pClient->m_pSounds->Play(CSounds::CHN_MUSIC, SOUND_MENU, 1.0f);
}
else
m_pClient->m_pSounds->Stop(SOUND_MENU);
}
// reset button
MainView.HSplitBottom(60.0f, 0, &BottomView);
BottomView.HSplitBottom(60.0f, 0, &BottomView);
Spacing = 3.0f;
float ButtonWidth = (BottomView.w/6.0f)-(Spacing*5.0)/6.0f;
@ -1649,6 +1973,7 @@ void CMenus::RenderSettingsSound(CUIRect MainView)
if(DoButton_Menu(&s_ResetButton, Localize("Reset"), 0, &Button))
{
g_Config.m_SndEnable = 1;
g_Config.m_SndInit = 1;
if(!g_Config.m_SndMusic)
{
g_Config.m_SndMusic = 1;

View file

@ -9,6 +9,7 @@
#include <generated/client_data.h>
#include <game/client/gameclient.h>
#include "menus.h"
#include "motd.h"
void CMotd::Clear()
@ -18,6 +19,9 @@ void CMotd::Clear()
bool CMotd::IsActive()
{
// dont render modt if the menu is active
if(m_pClient->m_pMenus->IsActive())
return false;
return time_get() < m_ServerMotdTime;
}

View file

@ -32,8 +32,11 @@ void CNamePlates::RenderNameplate(
char aName[64];
str_format(aName, sizeof(aName), "%2d: %s", ClientID, g_Config.m_ClShowsocial ? m_pClient->m_aClients[ClientID].m_aName: "");
float tw = TextRender()->TextWidth(0, FontSize, aName, -1);
str_format(aName, sizeof(aName), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[ClientID].m_aName: "");
CTextCursor Cursor;
float tw = TextRender()->TextWidth(0, FontSize, aName, -1) + RenderTools()->GetClientIdRectSize(FontSize);
TextRender()->SetCursor(&Cursor, Position.x-tw/2.0f, Position.y-FontSize-38.0f, FontSize, TEXTFLAG_RENDER);
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.5f*a);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, a);
@ -45,7 +48,16 @@ void CNamePlates::RenderNameplate(
TextRender()->TextColor(0.7f, 0.7f, 1.0f, a);
}
TextRender()->Text(0, Position.x-tw/2.0f, Position.y-FontSize-38.0f, FontSize, aName, -1);
const vec4 IdTextColor(0.1f, 0.1f, 0.1f, a);
vec4 BgIdColor(1.0f, 0.5f, 0.5f, a * 0.5f);
if(m_pClient->m_aClients[ClientID].m_Team == TEAM_BLUE)
BgIdColor = vec4(0.7f, 0.7f, 1.0f, a * 0.5f);
if(a > 0.001f)
{
RenderTools()->DrawClientID(TextRender(), &Cursor, ClientID, BgIdColor, IdTextColor);
TextRender()->TextEx(&Cursor, aName, -1);
}
TextRender()->TextColor(1,1,1,1);
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f);

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