/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
/* Modifications
Copyright 2003-2004 Bytonic Software
Copyright 2010 Google Inc.
*/
package com.googlecode.gwtquake.shared.server;
import com.googlecode.gwtquake.shared.common.*;
import com.googlecode.gwtquake.shared.game.*;
import com.googlecode.gwtquake.shared.util.Math3D;
public class ServerGame {
/**
* PF_Unicast
*
* Sends the contents of the mutlicast buffer to a single client.
*/
public static void PF_Unicast(Entity ent, boolean reliable) {
int p;
ClientData client;
if (ent == null)
return;
p = ent.index;
if (p < 1 || p > ServerMain.maxclients.value)
return;
client = ServerInit.svs.clients[p - 1];
if (reliable)
Buffers.Write(client.netchan.message, ServerInit.sv.multicast.data,
ServerInit.sv.multicast.cursize);
else
Buffers.Write(client.datagram, ServerInit.sv.multicast.data,
ServerInit.sv.multicast.cursize);
ServerInit.sv.multicast.clear();
}
/**
* PF_dprintf
*
* Debug print to server console.
*/
public static void PF_dprintf(String fmt) {
Com.Printf(fmt);
}
/**
* Centerprintf for critical messages.
*/
public static void PF_cprintfhigh(Entity ent, String fmt) {
PF_cprintf(ent, Constants.PRINT_HIGH, fmt);
}
/**
* PF_cprintf
*
* Print to a single client.
*/
public static void PF_cprintf(Entity ent, int level, String fmt) {
int n = 0;
if (ent != null) {
n = ent.index;
if (n < 1 || n > ServerMain.maxclients.value)
Com.Error(Constants.ERR_DROP, "cprintf to a non-client");
}
if (ent != null)
ServerSend.SV_ClientPrintf(ServerInit.svs.clients[n - 1], level, fmt);
else
Com.Printf(fmt);
}
/**
* PF_centerprintf
*
* centerprint to a single client.
*/
public static void PF_centerprintf(Entity ent, String fmt) {
int n;
n = ent.index;
if (n < 1 || n > ServerMain.maxclients.value)
return; // Com_Error (ERR_DROP, "centerprintf to a non-client");
Buffers.writeByte(ServerInit.sv.multicast, Constants.svc_centerprint);
Buffers.WriteString(ServerInit.sv.multicast, fmt);
PF_Unicast(ent, true);
}
/**
* PF_error
*
* Abort the server with a game error.
*/
public static void PF_error(String fmt) {
Com.Error(Constants.ERR_DROP, "Game Error: " + fmt);
}
public static void PF_error(int level, String fmt) {
Com.Error(level, fmt);
}
/**
* PF_setmodel
*
* Also sets mins and maxs for inline bmodels.
*/
public static void PF_setmodel(Entity ent, String name) {
int i;
Model mod;
if (name == null)
Com.Error(Constants.ERR_DROP, "PF_setmodel: NULL");
i = ServerInit.SV_ModelIndex(name);
ent.s.modelindex = i;
// if it is an inline model, get the size information for it
if (name.startsWith("*")) {
mod = CM.InlineModel(name);
Math3D.VectorCopy(mod.mins, ent.mins);
Math3D.VectorCopy(mod.maxs, ent.maxs);
World.SV_LinkEdict(ent);
}
}
/**
* PF_Configstring
*/
public static void PF_Configstring(int index, String val) {
if (index < 0 || index >= Constants.MAX_CONFIGSTRINGS)
Com.Error(Constants.ERR_DROP, "configstring: bad index " + index
+ "\n");
if (val == null)
val = "";
// change the string in sv
ServerInit.sv.configstrings[index] = val;
if (ServerInit.sv.state != Constants.ss_loading) { // send the update to
// everyone
ServerInit.sv.multicast.clear();
Buffers.writeByte(ServerInit.sv.multicast, Constants.svc_configstring);
ServerInit.sv.multicast.WriteShort(index);
Buffers.WriteString(ServerInit.sv.multicast, val);
ServerSend.SV_Multicast(Globals.vec3_origin, Constants.MULTICAST_ALL_R);
}
}
public static void PF_WriteChar(int c) {
Buffers.writeByte(ServerInit.sv.multicast, c);
}
public static void PF_WriteByte(int c) {
Buffers.writeByte(ServerInit.sv.multicast, c);
}
public static void PF_WriteShort(int c) {
ServerInit.sv.multicast.WriteShort(c);
}
public static void PF_WriteLong(int c) {
ServerInit.sv.multicast.putInt(c);
}
public static void PF_WriteFloat(float f) {
ServerInit.sv.multicast.putFloat(f);
}
public static void PF_WriteString(String s) {
Buffers.WriteString(ServerInit.sv.multicast, s);
}
public static void PF_WritePos(float[] pos) {
Buffers.WritePos(ServerInit.sv.multicast, pos);
}
public static void PF_WriteDir(float[] dir) {
ServerGame.WriteDir(ServerInit.sv.multicast, dir);
}
public static void PF_WriteAngle(float f) {
Buffers.WriteAngle(ServerInit.sv.multicast, f);
}
/**
* PF_inPVS
*
* Also checks portalareas so that doors block sight.
*/
public static boolean PF_inPVS(float[] p1, float[] p2) {
int leafnum;
int cluster;
int area1, area2;
byte mask[];
leafnum = CM.CM_PointLeafnum(p1);
cluster = CM.CM_LeafCluster(leafnum);
area1 = CM.CM_LeafArea(leafnum);
mask = CM.CM_ClusterPVS(cluster);
leafnum = CM.CM_PointLeafnum(p2);
cluster = CM.CM_LeafCluster(leafnum);
area2 = CM.CM_LeafArea(leafnum);
// quake2 bugfix
if (cluster == -1)
return false;
if (mask != null && (0 == (mask[cluster >>> 3] & (1 << (cluster & 7)))))
return false;
if (!CM.CM_AreasConnected(area1, area2))
return false; // a door blocks sight
return true;
}
/**
* PF_inPHS.
*
* Also checks portalareas so that doors block sound.
*/
public static boolean PF_inPHS(float[] p1, float[] p2) {
int leafnum;
int cluster;
int area1, area2;
byte mask[];
leafnum = CM.CM_PointLeafnum(p1);
cluster = CM.CM_LeafCluster(leafnum);
area1 = CM.CM_LeafArea(leafnum);
mask = CM.CM_ClusterPHS(cluster);
leafnum = CM.CM_PointLeafnum(p2);
cluster = CM.CM_LeafCluster(leafnum);
area2 = CM.CM_LeafArea(leafnum);
// quake2 bugfix
if (cluster == -1)
return false;
if (mask != null && (0 == (mask[cluster >> 3] & (1 << (cluster & 7)))))
return false; // more than one bounce away
if (!CM.CM_AreasConnected(area1, area2))
return false; // a door blocks hearing
return true;
}
public static void PF_StartSound(Entity entity, int channel,
int sound_num, float volume, float attenuation, float timeofs) {
if (null == entity)
return;
ServerSend.SV_StartSound(null, entity, channel, sound_num, volume,
attenuation, timeofs);
}
/**
* SV_ShutdownGameProgs
*
* Called when either the entire server is being killed, or it is changing
* to a different game directory.
*/
public static void SV_ShutdownGameProgs() {
GameBase.ShutdownGame();
}
/**
* SV_InitGameProgs
*
* Init the game subsystem for a new map.
*/
public static void SV_InitGameProgs() {
// unload anything we have now
SV_ShutdownGameProgs();
GameBase.pointcontents = new PlayerMove.PointContentsAdapter() {
public int pointcontents(float[] o) {
return World.SV_PointContents(o);
}
};
GameSave.InitGame();
}
//should be ok.
public static void WriteDir(Buffer sb, float[] dir) {
int i, best;
float d, bestd;
if (dir == null) {
Buffers.writeByte(sb, 0);
return;
}
bestd = 0;
best = 0;
for (i = 0; i < Constants.NUMVERTEXNORMALS; i++) {
d = Math3D.DotProduct(dir, Globals.bytedirs[i]);
if (d > bestd) {
bestd = d;
best = i;
}
}
Buffers.writeByte(sb, best);
}
}