diff --git a/Templates/Full/game/art/art.module.taml b/Templates/Full/game/art/art.module.taml
new file mode 100644
index 000000000..73855c09e
--- /dev/null
+++ b/Templates/Full/game/art/art.module.taml
@@ -0,0 +1,13 @@
+
+
+
\ No newline at end of file
diff --git a/Templates/Full/game/art/shapes/actors/Soldier/soldier.asset.taml b/Templates/Full/game/art/shapes/actors/Soldier/soldier.asset.taml
new file mode 100644
index 000000000..4ba732205
--- /dev/null
+++ b/Templates/Full/game/art/shapes/actors/Soldier/soldier.asset.taml
@@ -0,0 +1,3 @@
+
diff --git a/Templates/Full/game/main.cs b/Templates/Full/game/main.cs
index 955f5aa6c..2a261201d 100644
--- a/Templates/Full/game/main.cs
+++ b/Templates/Full/game/main.cs
@@ -254,6 +254,7 @@ else {
//You can also explicitly decalre some modules here to be loaded by default if they are part of your game
//Ex: ModuleDatabase.LoadExplicit( "AppCore" );
+ ModuleDatabase.LoadGroup( "Game" );
if( !$isDedicated )
{
diff --git a/Templates/Full/game/scripts/scripts.module.taml b/Templates/Full/game/scripts/scripts.module.taml
new file mode 100644
index 000000000..e1a6b57be
--- /dev/null
+++ b/Templates/Full/game/scripts/scripts.module.taml
@@ -0,0 +1,13 @@
+
+
+
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/components/animationComponent.asset.taml b/Templates/Full/game/scripts/server/components/animationComponent.asset.taml
new file mode 100644
index 000000000..62f15cdf9
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/animationComponent.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/cameraOrbiterComponent.asset.taml b/Templates/Full/game/scripts/server/components/cameraOrbiterComponent.asset.taml
new file mode 100644
index 000000000..e03081564
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/cameraOrbiterComponent.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/collisionComponent.asset.taml b/Templates/Full/game/scripts/server/components/collisionComponent.asset.taml
new file mode 100644
index 000000000..9796df18d
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/collisionComponent.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/game/camera.asset.taml b/Templates/Full/game/scripts/server/components/game/camera.asset.taml
new file mode 100644
index 000000000..5d00d1170
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/game/camera.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/game/camera.cs b/Templates/Full/game/scripts/server/components/game/camera.cs
new file mode 100644
index 000000000..e0b6bc41e
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/game/camera.cs
@@ -0,0 +1,198 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+function CameraComponent::onAdd(%this)
+{
+ Parent::onBehaviorAdd(%this);
+
+ %this.addComponentField(clientOwner, "The client that views this camera", "int", "1", "");
+
+ %test = %this.clientOwner;
+
+ %barf = ClientGroup.getCount();
+
+ %clientID = %this.getClientID();
+ if(%clientID && !isObject(%clientID.camera))
+ {
+ %this.scopeToClient(%clientID);
+ %this.setDirty();
+
+ %clientID.setCameraObject(%this.owner);
+ %clientID.setControlCameraFov(%this.FOV);
+
+ %clientID.camera = %this.owner;
+ }
+
+ %res = $pref::Video::mode;
+ %derp = 0;
+}
+
+function CameraComponent::onRemove(%this)
+{
+ %clientID = %this.getClientID();
+ if(%clientID)
+ %clientID.clearCameraObject();
+}
+
+function CameraComponent::onInspectorUpdate(%this)
+{
+ //if(%this.clientOwner)
+ //%this.clientOwner.setCameraObject(%this.owner);
+}
+
+function CameraComponent::getClientID(%this)
+{
+ return ClientGroup.getObject(%this.clientOwner-1);
+}
+
+function CameraComponent::isClientCamera(%this, %client)
+{
+ %clientID = ClientGroup.getObject(%this.clientOwner-1);
+
+ if(%client.getID() == %clientID)
+ return true;
+ else
+ return false;
+}
+
+function CameraComponent::onClientConnect(%this, %client)
+{
+ //if(%this.isClientCamera(%client) && !isObject(%client.camera))
+ //{
+ %this.scopeToClient(%client);
+ %this.setDirty();
+
+ %client.setCameraObject(%this.owner);
+ %client.setControlCameraFov(%this.FOV);
+
+ %client.camera = %this.owner;
+ //}
+ //else
+ //{
+ // echo("CONNECTED CLIENT IS NOT CAMERA OWNER!");
+ //}
+}
+
+function CameraComponent::onClientDisconnect(%this, %client)
+{
+ Parent::onClientDisconnect(%this, %client);
+
+ if(isClientCamera(%client)){
+ %this.clearScopeToClient(%client);
+ %client.clearCameraObject();
+ }
+}
+
+//move to the editor later
+GlobalActionMap.bind("keyboard", "alt c", "toggleEditorCam");
+
+function switchCamera(%client, %newCamEntity)
+{
+ if(!isObject(%client) || !isObject(%newCamEntity))
+ return error("SwitchCamera: No client or target camera!");
+
+ %cam = %newCamEntity.getComponent(CameraComponent);
+
+ if(!isObject(%cam))
+ return error("SwitchCamera: Target camera doesn't have a camera behavior!");
+
+ //TODO: Cleanup clientOwner for previous camera!
+ if(%cam.clientOwner == 0 || %cam.clientOwner $= "")
+ %cam.clientOwner = 0;
+
+ %cam.scopeToClient(%client);
+ %cam.setDirty();
+
+ %client.setCameraObject(%newCamEntity);
+ %client.setControlCameraFov(%cam.FOV);
+
+ %client.camera = %newCamEntity;
+}
+
+function buildEditorCamera()
+{
+ if(isObject("EditorCamera"))
+ return EditorCamera;
+
+ %camObj = SGOManager.spawn("SpectatorObject", false);
+
+ %camObj.name = "EditorCamera";
+
+ %client = ClientGroup.getObject(0);
+
+ %camObj.getComponent(SpectatorControls).setupControls(%client);
+
+ MissionCleanup.add(%camObj);
+
+ return %camObj;
+}
+
+//TODO: Move this somewhere else!
+function toggleEditorCam(%val)
+{
+ if(!%val)
+ return;
+
+ %client = ClientGroup.getObject(0);
+
+ if(!isObject(%client.camera))
+ return error("ToggleEditorCam: no existing camera!");
+
+ %editorCam = buildEditorCamera();
+
+ //if this is our first switch, just go to the editor camera
+ if(%client.lastCam $= "" || %client.camera.getId() != %editorCam.getId())
+ {
+ if(%client.lastCam $= "")
+ {
+ //set up the position
+ %editorCam.position = %client.camera.position;
+ %editorCam.rotation = %client.camera.rotation;
+ }
+
+ %client.lastCam = %client.camera;
+ %client.lastController = %client.getControlObject();
+ switchCamera(%client, %editorCam);
+ switchControlObject(%client, %editorCam);
+ }
+ else
+ {
+ switchCamera(%client, %client.lastCam);
+ switchControlObject(%client, %client.lastController);
+ %client.lastCam = %editorCam;
+ %client.lastController = %editorCam;
+ }
+}
+
+function serverCmdSetClientAspectRatio(%client, %width, %height)
+{
+ echo("Client: " @ %client SPC "changing screen res to: " @ %width SPC %height);
+ %client.screenExtent = %width SPC %height;
+ %cam = %client.getCameraObject();
+
+ if(!isObject(%cam))
+ return;
+
+ %cameraComp = %cam.getComponent(CameraComponent);
+
+ %cameraComp.ScreenAspect = %width SPC %height;
+}
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/components/game/controlObject.asset.taml b/Templates/Full/game/scripts/server/components/game/controlObject.asset.taml
new file mode 100644
index 000000000..2c9d48e1c
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/game/controlObject.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/game/controlObject.cs b/Templates/Full/game/scripts/server/components/game/controlObject.cs
new file mode 100644
index 000000000..5b67f394b
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/game/controlObject.cs
@@ -0,0 +1,91 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+//registerComponent("ControlObjectComponent", "Component", "Control Object", "Game", false, "Allows the behavior owner to operate as a camera.");
+
+function ControlObjectComponent::onAdd(%this)
+{
+ Parent::onBehaviorAdd(%this);
+
+ %this.addComponentField(clientOwner, "The shape to use for rendering", "int", "1", "");
+
+ %clientID = %this.getClientID();
+
+ if(%clientID && !isObject(%clientID.getControlObject()))
+ %clientID.setControlObject(%this.owner);
+}
+
+function ControlObjectComponent::onRemove(%this)
+{
+ %clientID = %this.getClientID();
+
+ if(%clientID)
+ %clientID.setControlObject(0);
+}
+
+function ControlObjectComponent::onClientConnect(%this, %client)
+{
+ if(%this.isControlClient(%client) && !isObject(%client.getControlObject()))
+ %client.setControlObject(%this.owner);
+}
+
+function ControlObjectComponent::onClientDisconnect(%this, %client)
+{
+ if(%this.isControlClient(%client))
+ %client.setControlObject(0);
+}
+
+function ControlObjectComponent::getClientID(%this)
+{
+ return ClientGroup.getObject(%this.clientOwner-1);
+}
+
+function ControlObjectComponent::isControlClient(%this, %client)
+{
+ %clientID = ClientGroup.getObject(%this.clientOwner-1);
+
+ if(%client.getID() == %clientID)
+ return true;
+ else
+ return false;
+}
+
+function ControlObjectComponent::onInspectorUpdate(%this, %field)
+{
+ %clientID = %this.getClientID();
+
+ if(%clientID && !isObject(%clientID.getControlObject()))
+ %clientID.setControlObject(%this.owner);
+}
+
+function switchControlObject(%client, %newControlEntity)
+{
+ if(!isObject(%client) || !isObject(%newControlEntity))
+ return error("SwitchControlObject: No client or target controller!");
+
+ %control = %newControlEntity.getComponent(ControlObjectComponent);
+
+ if(!isObject(%control))
+ return error("SwitchControlObject: Target controller has no conrol object behavior!");
+
+ %client.setControlObject(%newControlEntity);
+}
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/components/game/itemRotate.asset.taml b/Templates/Full/game/scripts/server/components/game/itemRotate.asset.taml
new file mode 100644
index 000000000..8068b49f3
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/game/itemRotate.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/game/itemRotate.cs b/Templates/Full/game/scripts/server/components/game/itemRotate.cs
new file mode 100644
index 000000000..259b44111
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/game/itemRotate.cs
@@ -0,0 +1,49 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+//registerComponent("ItemRotationComponent", "Component", "Item Rotation", "Game", false, "Rotates the entity around the z axis, like an item pickup.");
+
+function ItemRotationComponent::onAdd(%this)
+{
+ %this.addComponentField(rotationsPerMinute, "Number of rotations per minute", "float", "5", "");
+ %this.addComponentField(forward, "Rotate forward or backwards", "bool", "1", "");
+ %this.addComponentField(horizontal, "Rotate horizontal or verticle, true for horizontal", "bool", "1", "");
+}
+
+function ItemRotateBehavior::Update(%this)
+{
+ %tickRate = 0.032;
+
+ //Rotations per second is calculated based on a standard update tick being 32ms. So we scale by the tick speed, then add that to our rotation to
+ //get a nice rotation speed.
+ if(%this.horizontal)
+ {
+ if(%this.forward)
+ %this.owner.rotation.z += ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate;
+ else
+ %this.owner.rotation.z -= ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate;
+ }
+ else
+ {
+ %this.owner.rotation.x += ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate;
+ }
+}
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/components/game/playerSpawner.asset.taml b/Templates/Full/game/scripts/server/components/game/playerSpawner.asset.taml
new file mode 100644
index 000000000..d181a86b4
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/game/playerSpawner.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/game/playerSpawner.cs b/Templates/Full/game/scripts/server/components/game/playerSpawner.cs
new file mode 100644
index 000000000..fb6507d08
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/game/playerSpawner.cs
@@ -0,0 +1,70 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+//registerComponent("PlayerSpawner", "Component",
+// "Player Spawner", "Game", false, "When a client connects, it spawns a player object for them and attaches them to it");
+
+function PlayerSpawner::onAdd(%this)
+{
+ %this.clientCount = 1;
+ %this.friendlyName = "Player Spawner";
+ %this.componentType = "Spawner";
+
+ %this.addComponentField("GameObjectName", "The name of the game object we spawn for the players", string, "PlayerObject");
+}
+
+function PlayerSpawner::onClientConnect(%this, %client)
+{
+ %playerObj = SGOManager.spawn(%this.GameObjectName);
+
+ if(!isObject(%playerObj))
+ return;
+
+ %playerObj.position = %this.owner.position;
+
+ MissionCleanup.add(%playerObj);
+
+ for(%b = 0; %b < %playerObj.getComponentCount(); %b++)
+ {
+ %comp = %playerObj.getComponentByIndex(%b);
+
+ if(%comp.isMethod("onClientConnect"))
+ %comp.onClientConnect(%client);
+ }
+
+ switchControlObject(%client, %playerObj);
+ switchCamera(%client, %playerObj);
+
+ //%playerObj.getComponent(FPSControls).setupControls(%client);
+
+ %this.clientCount++;
+}
+
+function PlayerSpawner::onClientDisConnect(%this, %client)
+{
+
+}
+
+function PlayerSpawner::getClientID(%this)
+{
+ return ClientGroup.getObject(%this.clientOwner-1);
+}
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/components/input/fpsControls.asset.taml b/Templates/Full/game/scripts/server/components/input/fpsControls.asset.taml
new file mode 100644
index 000000000..34f31f181
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/input/fpsControls.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/input/fpsControls.cs b/Templates/Full/game/scripts/server/components/input/fpsControls.cs
new file mode 100644
index 000000000..3e7f571bd
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/input/fpsControls.cs
@@ -0,0 +1,249 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+//registerComponent("FPSControls", "Component", "FPS Controls", "Input", false, "First Person Shooter-type controls");
+
+function FPSControls::onAdd(%this)
+{
+ Parent::onBehaviorAdd(%this);
+
+ //
+ %this.beginGroup("Keys");
+ %this.addComponentField(forwardKey, "Key to bind to vertical thrust", keybind, "keyboard w");
+ %this.addComponentField(backKey, "Key to bind to vertical thrust", keybind, "keyboard s");
+ %this.addComponentField(leftKey, "Key to bind to horizontal thrust", keybind, "keyboard a");
+ %this.addComponentField(rightKey, "Key to bind to horizontal thrust", keybind, "keyboard d");
+
+ %this.addComponentField(jump, "Key to bind to horizontal thrust", keybind, "keyboard space");
+ %this.endGroup();
+
+ %this.beginGroup("Mouse");
+ %this.addComponentField(pitchAxis, "Key to bind to horizontal thrust", keybind, "mouse yaxis");
+ %this.addComponentField(yawAxis, "Key to bind to horizontal thrust", keybind, "mouse xaxis");
+ %this.endGroup();
+
+ %this.addComponentField(moveSpeed, "Horizontal thrust force", float, 300.0);
+ %this.addComponentField(jumpStrength, "Vertical thrust force", float, 3.0);
+ //
+
+ %control = %this.owner.getComponent( ControlObjectComponent );
+ if(!%control)
+ return echo("SPECTATOR CONTROLS: No Control Object behavior!");
+
+ //%this.Physics = %this.owner.getComponent( PlayerPhysicsComponent );
+
+ //%this.Animation = %this.owner.getComponent( AnimationComponent );
+
+ //%this.Camera = %this.owner.getComponent( MountedCameraComponent );
+
+ //%this.Animation.playThread(0, "look");
+
+ %this.setupControls(%control.getClientID());
+}
+
+function FPSControls::onRemove(%this)
+{
+ Parent::onBehaviorRemove(%this);
+
+ commandToClient(%control.clientOwnerID, 'removeInput', %this.forwardKey);
+ commandToClient(%control.clientOwnerID, 'removeInput', %this.backKey);
+ commandToClient(%control.clientOwnerID, 'removeInput', %this.leftKey);
+ commandToClient(%control.clientOwnerID, 'removeInput', %this.rightKey);
+
+ commandToClient(%control.clientOwnerID, 'removeInput', %this.pitchAxis);
+ commandToClient(%control.clientOwnerID, 'removeInput', %this.yawAxis);
+}
+
+function FPSControls::onBehaviorFieldUpdate(%this, %field)
+{
+ %controller = %this.owner.getBehavior( ControlObjectBehavior );
+ commandToClient(%controller.clientOwnerID, 'updateInput', %this.getFieldValue(%field), %field);
+}
+
+function FPSControls::onClientConnect(%this, %client)
+{
+ %this.setupControls(%client);
+}
+
+
+function FPSControls::setupControls(%this, %client)
+{
+ %control = %this.owner.getComponent( ControlObjectComponent );
+ if(!%control.isControlClient(%client))
+ {
+ echo("FPS CONTROLS: Client Did Not Match");
+ return;
+ }
+
+ %inputCommand = "FPSControls";
+
+ %test = %this.forwardKey;
+
+ /*SetInput(%client, %this.forwardKey.x, %this.forwardKey.y, %inputCommand@"_forwardKey");
+ SetInput(%client, %this.backKey.x, %this.backKey.y, %inputCommand@"_backKey");
+ SetInput(%client, %this.leftKey.x, %this.leftKey.y, %inputCommand@"_leftKey");
+ SetInput(%client, %this.rightKey.x, %this.rightKey.y, %inputCommand@"_rightKey");
+
+ SetInput(%client, %this.jump.x, %this.jump.y, %inputCommand@"_jump");
+
+ SetInput(%client, %this.pitchAxis.x, %this.pitchAxis.y, %inputCommand@"_pitchAxis");
+ SetInput(%client, %this.yawAxis.x, %this.yawAxis.y, %inputCommand@"_yawAxis");*/
+
+ SetInput(%client, "keyboard", "w", %inputCommand@"_forwardKey");
+ SetInput(%client, "keyboard", "s", %inputCommand@"_backKey");
+ SetInput(%client, "keyboard", "a", %inputCommand@"_leftKey");
+ SetInput(%client, "keyboard", "d", %inputCommand@"_rightKey");
+
+ SetInput(%client, "keyboard", "space", %inputCommand@"_jump");
+
+ SetInput(%client, "mouse", "yaxis", %inputCommand@"_pitchAxis");
+ SetInput(%client, "mouse", "xaxis", %inputCommand@"_yawAxis");
+
+ SetInput(%client, "keyboard", "f", %inputCommand@"_flashlight");
+
+}
+
+function FPSControls::onMoveTrigger(%this, %triggerID)
+{
+ //check if our jump trigger was pressed!
+ if(%triggerID == 2)
+ {
+ %this.owner.applyImpulse("0 0 0", "0 0 " @ %this.jumpStrength);
+ }
+}
+
+function FPSControls::Update(%this)
+{
+ return;
+
+ %moveVector = %this.owner.getMoveVector();
+ %moveRotation = %this.owner.getMoveRotation();
+
+ %this.Physics.moveVector = "0 0 0";
+
+ if(%moveVector.x != 0)
+ {
+ %fv = VectorNormalize(%this.owner.getRightVector());
+
+ %forMove = VectorScale(%fv, (%moveVector.x));// * (%this.moveSpeed * 0.032)));
+
+ //%this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove);
+
+ %this.Physics.moveVector = VectorAdd(%this.Physics.moveVector, %forMove);
+
+ //if(%forMove > 0)
+ // %this.Animation.playThread(1, "run");
+ }
+ /*else
+ {
+ %fv = VectorNormalize(%this.owner.getRightVector());
+
+ %forMove = VectorScale(%fv, (%moveVector.x * (%this.moveSpeed * 0.032)));
+
+ if(%forMove <= 0)
+ %this.Animation.stopThread(1);
+
+ }*/
+
+ if(%moveVector.y != 0)
+ {
+ %fv = VectorNormalize(%this.owner.getForwardVector());
+
+ %forMove = VectorScale(%fv, (%moveVector.y));// * (%this.moveSpeed * 0.032)));
+
+ //%this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove);
+
+ %this.Physics.moveVector = VectorAdd(%this.Physics.moveVector, %forMove);
+
+ //if(VectorLen(%this.Physics.velocity) < 2)
+ // %this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove);
+ }
+
+ /*if(%moveVector.z)
+ {
+ %fv = VectorNormalize(%this.owner.getUpVector());
+
+ %forMove = VectorScale(%fv, (%moveVector.z * (%this.moveSpeed * 0.032)));
+
+ %this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove);
+ }*/
+
+ if(%moveRotation.x != 0)
+ {
+ %look = mRadToDeg(%moveRotation.x) / 180;
+
+ //%this.Animation.setThreadPos(0, %look);
+
+ %this.owner.getComponent( MountedCameraComponent ).rotationOffset.x += mRadToDeg(%moveRotation.x);
+
+ //%this.Camera.rotationOffset.x += mRadToDeg(%moveRotation.x);
+ }
+ // %this.owner.rotation.x += mRadToDeg(%moveRotation.x);
+
+ if(%moveRotation.z != 0)
+ {
+ %zrot = mRadToDeg(%moveRotation.z);
+ %this.owner.getComponent( MountedCameraComponent ).rotationOffset.z += %zrot;
+ //%this.owner.rotation.z += %zrot;
+ }
+}
+
+//
+function FPSControls_forwardKey(%val)
+{
+ $mvForwardAction = %val;
+}
+
+function FPSControls_backKey(%val)
+{
+ $mvBackwardAction = %val;
+}
+
+function FPSControls_leftKey(%val)
+{
+ $mvLeftAction = %val;
+}
+
+function FPSControls_rightKey(%val)
+{
+ $mvRightAction = %val;
+}
+
+function FPSControls_yawAxis(%val)
+{
+ $mvYaw += getMouseAdjustAmount(%val);
+}
+
+function FPSControls_pitchAxis(%val)
+{
+ $mvPitch += getMouseAdjustAmount(%val);
+}
+
+function FPSControls_jump(%val)
+{
+ $mvTriggerCount2++;
+}
+
+function FPSControls_flashLight(%val)
+{
+ $mvTriggerCount3++;
+}
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/components/input/inputManager.cs b/Templates/Full/game/scripts/server/components/input/inputManager.cs
new file mode 100644
index 000000000..c8123d1e3
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/input/inputManager.cs
@@ -0,0 +1,82 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+function SetInput(%client, %device, %key, %command, %bindMap, %behav)
+{
+ commandToClient(%client, 'SetInput', %device, %key, %command, %bindMap, %behav);
+}
+
+function RemoveInput(%client, %device, %key, %command, %bindMap)
+{
+ commandToClient(%client, 'removeInput', %device, %key, %command, %bindMap);
+}
+
+function clientCmdSetInput(%device, %key, %command, %bindMap, %behav)
+{
+ //if we're requesting a custom bind map, set that up
+ if(%bindMap $= "")
+ %bindMap = moveMap;
+
+ if (!isObject(%bindMap)){
+ new ActionMap(moveMap);
+ moveMap.push();
+ }
+
+ //get our local
+ //%localID = ServerConnection.resolveGhostID(%behav);
+
+ //%tmpl = %localID.getTemplate();
+ //%tmpl.insantiateNamespace(%tmpl.getName());
+
+ //first, check if we have an existing command
+ %oldBind = %bindMap.getBinding(%command);
+ if(%oldBind !$= "")
+ %bindMap.unbind(getField(%oldBind, 0), getField(%oldBind, 1));
+
+ //now, set the requested bind
+ %bindMap.bind(%device, %key, %command);
+}
+
+function clientCmdRemoveSpecCtrlInput(%device, %key, %bindMap)
+{
+ //if we're requesting a custom bind map, set that up
+ if(%bindMap $= "")
+ %bindMap = moveMap;
+
+ if (!isObject(%bindMap))
+ return;
+
+ %bindMap.unbind(%device, %key);
+}
+
+function clientCmdSetupClientBehavior(%bhvrGstID)
+{
+ %localID = ServerConnection.resolveGhostID(%bhvrGstID);
+ %tmpl = %localID.getTemplate();
+ %tmpl.insantiateNamespace(%tmpl.getName());
+}
+
+function getMouseAdjustAmount(%val)
+{
+ // based on a default camera FOV of 90'
+ return(%val * ($cameraFov / 90) * 0.01) * $pref::Input::LinkMouseSensitivity;
+}
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/components/meshComponent.asset.taml b/Templates/Full/game/scripts/server/components/meshComponent.asset.taml
new file mode 100644
index 000000000..d019cd893
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/meshComponent.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/playerControllerComponent.asset.taml b/Templates/Full/game/scripts/server/components/playerControllerComponent.asset.taml
new file mode 100644
index 000000000..d5174644b
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/playerControllerComponent.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/components/stateMachineComponent.asset.taml b/Templates/Full/game/scripts/server/components/stateMachineComponent.asset.taml
new file mode 100644
index 000000000..a261bb194
--- /dev/null
+++ b/Templates/Full/game/scripts/server/components/stateMachineComponent.asset.taml
@@ -0,0 +1,7 @@
+
diff --git a/Templates/Full/game/scripts/server/gameCore.cs b/Templates/Full/game/scripts/server/gameCore.cs
index abff15c0a..bb7aed714 100644
--- a/Templates/Full/game/scripts/server/gameCore.cs
+++ b/Templates/Full/game/scripts/server/gameCore.cs
@@ -573,6 +573,31 @@ function GameCore::onClientEnterGame(%game, %client)
%client.isAiControlled(),
%client.isAdmin,
%client.isSuperAdmin);
+
+ %entityIds = parseMissionGroupForIds("Entity", "");
+ %entityCount = getWordCount(%entityIds);
+
+ for(%i=0; %i < %entityCount; %i++)
+ {
+ %entity = getWord(%entityIds, %i);
+
+ for(%e=0; %e < %entity.getCount(); %e++)
+ {
+ %child = %entity.getObject(%e);
+ if(%child.getCLassName() $= "Entity")
+ %entityIds = %entityIds SPC %child.getID();
+ }
+
+ for(%c=0; %c < %entity.getComponentCount(); %c++)
+ {
+ %comp = %entity.getComponentByIndex(%c);
+
+ if(%comp.isMethod("onClientConnect"))
+ {
+ %comp.onClientConnect(%client);
+ }
+ }
+ }
}
function GameCore::onClientLeaveGame(%game, %client)
diff --git a/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml b/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml
new file mode 100644
index 000000000..e9cc73c89
--- /dev/null
+++ b/Templates/Full/game/scripts/server/gameObjects/GameObjectList.xml
@@ -0,0 +1,28 @@
+
+
+
+ ScriptedTriggerObject
+ data/EC/scripts/gameObjects/ScriptedTriggerObject.taml
+ data/EC/scripts/gameObjects/ScriptedTriggerObject.cs
+
+
+ PlayerObject
+ data/EC/scripts/gameObjects/playerObject.taml
+ data/EC/scripts/gameObjects/playerObject.cs
+
+
+ spectatorObject
+ data/EC/scripts/gameObjects/spectatorObject.taml
+ data/EC/scripts/gameObjects/spectatorObject.cs
+
+
+ ThirdPersonPlayerObject
+ data/EC/scripts/gameObjects/ThirdPersonPlayerObject.taml
+ data/EC/scripts/gameObjects/ThirdPersonPlayerObject.cs
+
+
+ FirstPersonArms
+ data/EC/scripts/gameObjects/FirstPersonArms.taml
+ data/EC/scripts/gameObjects/FirstPersonArms.cs
+
+
diff --git a/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs b/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs
new file mode 100644
index 000000000..138bcb8be
--- /dev/null
+++ b/Templates/Full/game/scripts/server/gameObjects/GameObjectManager.cs
@@ -0,0 +1,75 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+function execGameObjects()
+{
+ //find all GameObjectAssets
+ %assetQuery = new AssetQuery();
+ if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset"))
+ return; //if we didn't find ANY, just exit
+
+ %count = %assetQuery.getCount();
+
+ for(%i=0; %i < %count; %i++)
+ {
+ %assetId = %assetQuery.getAsset(%i);
+
+ %gameObjectAsset = AssetDatabase.acquireAsset(%assetId);
+
+ if(isFile(%gameObjectAsset.scriptFilePath))
+ exec(%gameObjectAsset.scriptFilePath);
+ }
+}
+
+function spawnGameObject(%name, %addToMissionGroup)
+{
+ if(%addToMissionGroup $= "")
+ %addToMissionGroup = true;
+
+ //find all GameObjectAssets
+ %assetQuery = new AssetQuery();
+ if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset"))
+ return; //if we didn't find ANY, just exit
+
+ %count = %assetQuery.getCount();
+
+ for(%i=0; %i < %count; %i++)
+ {
+ %assetId = %assetQuery.getAsset(%i);
+
+ %gameObjectAsset = AssetDatabase.acquireAsset(%assetId);
+
+ if(%gameObjectAsset.gameObjectName $= %name)
+ {
+ if(isFile(%gameObjectAsset.TAMLFilePath))
+ {
+ %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath);
+
+ if(%addToMissionGroup == true)
+ MissionGroup.add(%newSGOObject);
+
+ return %newSGOObject;
+ }
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.asset.taml b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.asset.taml
new file mode 100644
index 000000000..2d593a50b
--- /dev/null
+++ b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.asset.taml
@@ -0,0 +1,5 @@
+
diff --git a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs
new file mode 100644
index 000000000..bc92db12d
--- /dev/null
+++ b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.cs
@@ -0,0 +1,253 @@
+function ThirdPersonPlayerObject::onAdd(%this)
+{
+ %this.turnRate = 0.3;
+
+ %this.phys = %this.getComponent("PlayerControllerComponent");
+ %this.collision = %this.getComponent("CollisionComponent");
+ %this.cam = %this.getComponent("CameraComponent");
+ %this.camArm = %this.getComponent("CameraOrbiterComponent");
+ %this.animation = %this.getComponent("AnimationComponent");
+ %this.stateMachine = %this.getComponent("StateMachineComponent");
+ %this.mesh = %this.getComponent("MeshComponent");
+
+ %this.stateMachine.forwardVector = 0;
+
+ %this.crouch = false;
+
+ %this.firstPerson = false;
+
+ %this.crouchSpeedMod = 0.5;
+
+ %this.aimOrbitDist = 1.5;
+ %this.regularOrbitDist = 5;
+
+ %this.regularOrbitMaxPitch = 70;
+ %this.regularOrbitMinPitch = -10;
+
+ %this.aimedMaxPitch = 90;
+ %this.aimedMinPitch = -90;
+
+ %this.arms = SGOManager.spawn("FirstPersonArms", true);
+
+ %this.add(arms);
+
+ //%this.mesh.mountObject(%this.arms, "Eye");
+}
+
+function ThirdPersonPlayerObject::onRemove(%this)
+{
+
+}
+
+function ThirdPersonPlayerObject::moveVectorEvent(%this)
+{
+ %moveVector = %this.getMoveVector();
+
+ // forward of the camera on the x-z plane
+ %cameraForward = %this.cam.getForwardVector();
+
+ %cameraRight = %this.cam.getRightVector();
+
+ %moveVec = VectorAdd(VectorScale(%cameraRight, %moveVector.x), VectorScale(%cameraForward, %moveVector.y));
+
+ if(%this.aiming || %this.firstPerson)
+ {
+ %forMove = "0 0 0";
+
+ if(%moveVector.x != 0)
+ {
+ %this.phys.inputVelocity.x = %moveVector.x * 10;
+ }
+ else
+ {
+ %this.phys.inputVelocity.x = 0;
+ }
+
+ if(%moveVector.y != 0)
+ {
+
+ %this.phys.inputVelocity.y = %moveVector.y * 10;
+ }
+ else
+ {
+ %this.phys.inputVelocity.y = 0;
+ }
+ }
+ else
+ {
+ if(%moveVec.x == 0 && %moveVec.y == 0)
+ {
+ %this.phys.inputVelocity = "0 0 0";
+ %this.stateMachine.forwardVector = 0;
+ }
+ else
+ {
+ %moveVec.z = 0;
+
+ %curForVec = %this.getForwardVector();
+
+ %newForVec = VectorLerp(%curForVec, %moveVec, %this.turnRate);
+
+ %this.setForwardVector(%newForVec);
+
+ %this.phys.inputVelocity.y = 10;
+
+ %this.stateMachine.forwardVector = 1;
+ }
+ }
+
+ if(%this.crouch)
+ %this.phys.inputVelocity = VectorScale(%this.phys.inputVelocity, %this.crouchSpeedMod);
+}
+
+function ThirdPersonPlayerObject::moveYawEvent(%this)
+{
+ %moveRotation = %this.getMoveRotation();
+
+ %camOrb = %this.getComponent("CameraOrbiterComponent");
+
+ if(%this.aiming || %this.firstPerson)
+ {
+ %this.rotation.z += %moveRotation.z * 10;
+ }
+
+ %camOrb.rotation.z += %moveRotation.z * 10;
+}
+
+function ThirdPersonPlayerObject::movePitchEvent(%this)
+{
+ %moveRotation = %this.getMoveRotation();
+
+ %camOrb = %this.getComponent("CameraOrbiterComponent");
+
+ %camOrb.rotation.x += %moveRotation.x * 10;
+}
+
+function ThirdPersonPlayerObject::moveRollEvent(%this){}
+
+function ThirdPersonPlayerObject::moveTriggerEvent(%this, %triggerNum, %triggerValue)
+{
+ if(%triggerNum == 3 && %triggerValue)
+ {
+ if(%triggerValue)
+ {
+ %this.firstPerson = !%this.firstPerson;
+
+ if(%this.firstPerson)
+ {
+ %this.rotation.z = %this.cam.rotationOffset.z;
+ %this.camArm.orbitDistance = 0;
+ %this.camArm.maxPitchAngle = %this.aimedMaxPitch;
+ %this.camArm.minPitchAngle = %this.aimedMinPitch;
+
+ %this.cam.positionOffset = "0 0 0";
+ %this.cam.rotationOffset = "0 0 0";
+ }
+ else if(%this.aiming)
+ {
+ %this.camArm.orbitDistance = %this.aimOrbitDist;
+
+ %this.camArm.maxPitchAngle = %this.aimedMaxPitch;
+ %this.camArm.minPitchAngle = %this.aimedMinPitch;
+ }
+ else
+ {
+ %this.camArm.orbitDistance = %this.regularOrbitDist;
+
+ %this.camArm.maxPitchAngle = %this.regularOrbitMaxPitch;
+ %this.camArm.minPitchAngle = %this.regularOrbitMinPitch;
+ }
+
+ commandToClient(localclientConnection, 'SetClientRenderShapeVisibility',
+ localclientConnection.getGhostID(%this.getComponent("MeshComponent")), !%this.firstPerson);
+ }
+ }
+ else if(%triggerNum == 2 && %triggerValue == true)
+ {
+ //get our best collision assuming up is 0 0 1
+ %collisionAngle = %this.collision.getBestCollisionAngle("0 0 1");
+
+ if(%collisionAngle >= 80)
+ {
+ %surfaceNormal = %this.collision.getCollisionNormal(0);
+ %jumpVector = VectorScale(%surfaceNormal, 200);
+ echo("Jump surface Angle is at: " @ %surfaceNormal);
+
+ %this.phys.applyImpulse(%this.position, %jumpVector);
+ %this.setForwardVector(%jumpVector);
+ }
+ else
+ %this.phys.applyImpulse(%this.position, "0 0 300");
+ }
+ else if(%triggerNum == 4)
+ {
+ %this.crouch = %triggerValue;
+ }
+ else if(%triggerNum == 1)
+ {
+ %this.aiming = %triggerValue;
+
+ if(%this.aiming)
+ {
+ %this.rotation.z = %this.cam.rotationOffset.z;
+ %this.camArm.orbitDistance = %this.aimOrbitDist;
+ %this.camArm.maxPitchAngle = %this.aimedMaxPitch;
+ %this.camArm.minPitchAngle = %this.aimedMinPitch;
+ }
+ else
+ {
+ %this.camArm.orbitDistance = %this.regularOrbitDist;
+ %this.camArm.maxPitchAngle = %this.regularOrbitMaxPitch;
+ %this.camArm.minPitchAngle = %this.regularOrbitMinPitch;
+ }
+ }
+}
+
+function ThirdPersonPlayerObject::onCollisionEvent(%this, %colObject, %colNormal, %colPoint, %colMatID, %velocity)
+{
+ if(!%this.phys.isContacted())
+ echo(%this @ " collided with " @ %colObject);
+}
+
+function ThirdPersonPlayerObject::processTick(%this)
+{
+ %moveVec = %this.getMoveVector();
+ %bestFit = "";
+
+ if(%this.crouch)
+ {
+ if(%moveVec.x != 0 || %moveVec.y != 0)
+ %bestFit = "Crouch_Forward";
+ else
+ %bestFit = "Crouch_Root";
+ }
+ else
+ {
+ if(%moveVec.x != 0 || %moveVec.y != 0)
+ %bestFit = "Run";
+ else
+ %bestFit = "Root";
+ }
+
+ if(%this.animation.getThreadAnimation(0) !$= %bestFit)
+ %this.animation.playThread(0, %bestFit);
+}
+
+//Used for first person mode
+function clientCmdSetClientRenderShapeVisibility(%id, %visiblilty)
+{
+ %localID = ServerConnection.resolveGhostID(%id);
+ %localID.enabled = %visiblilty;
+}
+
+function serverToClientObject( %serverObject )
+{
+ assert( isObject( LocalClientConnection ), "serverToClientObject() - No local client connection found!" );
+ assert( isObject( ServerConnection ), "serverToClientObject() - No server connection found!" );
+
+ %ghostId = LocalClientConnection.getGhostId( %serverObject );
+ if ( %ghostId == -1 )
+ return 0;
+
+ return ServerConnection.resolveGhostID( %ghostId );
+}
\ No newline at end of file
diff --git a/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml
new file mode 100644
index 000000000..fcfead0d4
--- /dev/null
+++ b/Templates/Full/game/scripts/server/gameObjects/ThirdPersonPlayerObject.taml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Templates/Full/game/scripts/server/scriptExec.cs b/Templates/Full/game/scripts/server/scriptExec.cs
index a61204040..d48e268e7 100644
--- a/Templates/Full/game/scripts/server/scriptExec.cs
+++ b/Templates/Full/game/scripts/server/scriptExec.cs
@@ -58,3 +58,23 @@ exec("./turret.cs");
// Load our gametypes
exec("./gameCore.cs"); // This is the 'core' of the gametype functionality.
exec("./gameDM.cs"); // Overrides GameCore with DeathMatch functionality.
+
+//Entity/Component stuff
+if(isFile("./components/game/camera.cs"))
+ exec("./components/game/camera.cs");
+if(isFile("./components/game/controlObject.cs"))
+ exec("./components/game/controlObject.cs");
+if(isFile("./components/game/itemRotate.cs"))
+ exec("./components/game/itemRotate.cs");
+if(isFile("./components/game/playerSpawner.cs"))
+ exec("./components/game/playerSpawner.cs");
+if(isFile("./components/input/fpsControls.cs"))
+ exec("./components/input/fpsControls.cs");
+if(isFile("./components/input/inputManager.cs"))
+ exec("./components/input/inputManager.cs");
+
+if(isFile("./gameObjects/GameObjectManager.cs"))
+{
+ exec("./gameObjects/GameObjectManager.cs");
+ execGameObjects();
+}
\ No newline at end of file
diff --git a/Templates/Full/game/tools/componentEditor/gui/superToolTipDlg.ed.gui b/Templates/Full/game/tools/componentEditor/gui/superToolTipDlg.ed.gui
new file mode 100644
index 000000000..ef506941a
--- /dev/null
+++ b/Templates/Full/game/tools/componentEditor/gui/superToolTipDlg.ed.gui
@@ -0,0 +1,45 @@
+%guiContent = new GuiControl(SuperTooltipDlg) {
+ canSaveDynamicFields = "0";
+ Profile = "GuiTransparentProfileModeless";
+ class = "SuperTooltip";
+ HorizSizing = "right";
+ VertSizing = "bottom";
+ position = "0 0";
+ Extent = "640 480";
+ MinExtent = "8 2";
+ canSave = "1";
+ Visible = "1";
+ hovertime = "1000";
+
+ new GuiControl(SuperTooltipWindow) {
+ canSaveDynamicFields = "0";
+ Profile = "EditorTextEditBoldModeless";
+ HorizSizing = "right";
+ VertSizing = "bottom";
+ position = "216 160";
+ Extent = "221 134";
+ MinExtent = "8 2";
+ canSave = "1";
+ Visible = "1";
+ hovertime = "1000";
+ internalName = "tooltipWindow";
+
+ new GuiMLTextCtrl(SuperTooltipMLText) {
+ canSaveDynamicFields = "0";
+ Profile = "EditorMLTextProfileModeless";
+ HorizSizing = "right";
+ VertSizing = "bottom";
+ position = "5 5";
+ Extent = "210 14";
+ MinExtent = "8 2";
+ canSave = "1";
+ Visible = "1";
+ hovertime = "1000";
+ lineSpacing = "2";
+ allowColorChars = "0";
+ maxChars = "-1";
+ internalName = "tooltipMLText";
+ };
+ };
+};
+
diff --git a/Templates/Full/game/tools/componentEditor/main.cs b/Templates/Full/game/tools/componentEditor/main.cs
new file mode 100644
index 000000000..56d74830a
--- /dev/null
+++ b/Templates/Full/game/tools/componentEditor/main.cs
@@ -0,0 +1,28 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+//Scripts
+exec("./scripts/componentEditor.ed.cs");
+exec("./scripts/superToolTipDlg.ed.cs");
+
+//gui
+exec("./gui/superToolTipDlg.ed.gui");
diff --git a/Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs b/Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs
new file mode 100644
index 000000000..7f25bd5e6
--- /dev/null
+++ b/Templates/Full/game/tools/componentEditor/scripts/SuperToolTipDlg.ed.cs
@@ -0,0 +1,155 @@
+function createSuperTooltipTheme(%name)
+{
+ %theme = new ScriptObject()
+ {
+ class = SuperTooltipTheme;
+ };
+
+ %theme.setName(%name);
+
+ return %theme;
+}
+
+function SuperTooltipTheme::addStyle(%this, %name, %style)
+{
+ %this.styles[%name] = %style;
+}
+
+function SuperTooltipTheme::setDefaultStyle(%this, %type, %default)
+{
+ %this.defaultStyles[%type] = %default;
+}
+
+function SuperTooltipTheme::setSpacing(%this, %verticalSpace, %horizontalSpace)
+{
+ %this.verticalSpace = %verticalSpace;
+ %this.horizontalSpace = %horizontalSpace;
+}
+
+function SuperTooltipTheme::getStyle(%this, %name)
+{
+ return %this.styles[%name];
+}
+
+function SuperTooltip::init(%this, %theme)
+{
+ %this.clearTooltip();
+
+ if(isObject(%theme))
+ %this.setTheme(%theme);
+}
+
+function SuperTooltip::clearTooltip(%this)
+{
+ if(%this.paramCount > 0)
+ {
+ for(%i=0;%i<%this.paramCount;%i++)
+ %this.param[%i] = "";
+ }
+
+ %this.title = "";
+ %this.paramCount = 0;
+}
+
+function SuperTooltip::processTooltip(%this, %globalPos, %verticalAlign, %horizontalAlign)
+{
+ if (%verticalAlign $= "")
+ %verticalAlign = 1;
+ if (%horizontalAlign $= "")
+ %horizontalAlign = 0;
+
+ %tooltipWindow = %this.findObjectByInternalName("tooltipWindow");
+
+ if(isObject(%tooltipWindow))
+ %tooltipMLText = %tooltipWindow.findObjectByInternalName("tooltipMLText");
+ else
+ return false;
+
+ if(!isObject(%tooltipMLText))
+ return false;
+
+ %verticalSpace = %this.theme.verticalSpace;
+ %horizontalSpace = %this.theme.horizontalSpace;
+
+ if (%verticalAlign == 1)
+ %verticalSpace = -%verticalSpace;
+ if (%horizontalAlign == 1)
+ %horizontalSpace = -%horizontalSpace;
+
+ %text = %this.getFormatedText();
+ %tooltipMLText.setText(%text);
+
+ canvas.pushDialog(%this);
+
+ %tooltipMLText.forceReflow();
+ %MLExtent = %tooltipMLText.extent;
+ %MLHeight = getWord(%MLExtent, 1);
+
+ %tooltipExtent = %tooltipWindow.extent;
+ %tooltipWidth = getWord(%tooltipExtent, 0);
+ %tooltipHeight = %MLHeight;
+ %tooltipWindow.extent = %tooltipWidth SPC %tooltipHeight;
+
+ %globalPosX = getWord(%globalPos, 0);
+ %globalPosY = getWord(%globalPos, 1);
+
+ %tooltipPosX = %globalPosX - (%horizontalAlign * %tooltipWidth) + %horizontalSpace;
+ %tooltipPosY = %globalPosY - (%verticalAlign * %tooltipHeight) + %verticalSpace;
+
+ %tooltipWindow.setPosition(%tooltipPosX, %tooltipPosY);
+
+ return true;
+}
+
+function SuperTooltip::hide(%this)
+{
+ canvas.popDialog(%this);
+
+ %this.clearTooltip();
+}
+
+function SuperTooltip::setTheme(%this, %theme)
+{
+ %this.theme = %theme;
+}
+
+function SuperTooltip::setTitle(%this, %title, %style)
+{
+ if(%style !$= "")
+ %themeStyle = %this.theme.styles[%style];
+ else
+ %themeStyle = %this.theme.getStyle(%this.theme.defaultStyles[Title]);
+
+ %this.title = %themeStyle @ %title;
+}
+
+function SuperTooltip::addParam(%this, %title, %text, %paramTitleStyle, %paramStyle)
+{
+ if(%paramTitleStyle !$= "")
+ %themeTitleStyle = %this.theme.styles[%paramTitleStyle];
+ else
+ %themeTitleStyle = %this.theme.getStyle(%this.theme.defaultStyles[ParamTitle]);
+
+ if(%paramStyle !$= "")
+ %themeStyle = %this.theme.styles[%paramStyle];
+ else
+ %themeStyle = %this.theme.getStyle(%this.theme.defaultStyles[Param]);
+
+ if (%title $= "")
+ %this.param[%this.paramCount] = %themeStyle @ %text @ "\n";
+ else
+ %this.param[%this.paramCount] = %themeTitleStyle @ %title @ ": " @ %themeStyle @ %text @ "\n";
+ %this.paramCount++;
+}
+
+function SuperTooltip::getFormatedText(%this)
+{
+ %text = %this.title @ "\n\n";
+
+ for(%i=0;%i<%this.paramCount;%i++)
+ {
+ %text = %text @ %this.param[%i];
+ }
+
+ return %text;
+}
\ No newline at end of file
diff --git a/Templates/Full/game/tools/componentEditor/scripts/componentEditor.ed.cs b/Templates/Full/game/tools/componentEditor/scripts/componentEditor.ed.cs
new file mode 100644
index 000000000..9a9ce33d6
--- /dev/null
+++ b/Templates/Full/game/tools/componentEditor/scripts/componentEditor.ed.cs
@@ -0,0 +1,233 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+function GuiInspectorEntityGroup::CreateContent(%this)
+{
+}
+
+function GuiInspectorEntityGroup::InspectObject( %this, %targetObject )
+{
+ %this.stack.clear();
+ %this.stack.addGuiControl(%this.createAddComponentList());
+}
+
+function GuiInspectorEntityGroup::createAddComponentList(%this)
+{
+ %extent = %this.getExtent();
+
+ %container = new GuiControl()
+ {
+ Profile = "EditorContainerProfile";
+ HorizSizing = "width";
+ VertSizing = "bottom";
+ Position = "0 0";
+ Extent = %extent.x SPC "25";
+ };
+
+ %componentList = new GuiPopUpMenuCtrlEx(QuickEditComponentList)
+ {
+ Profile = "GuiPopupMenuProfile";
+ HorizSizing = "width";
+ VertSizing = "bottom";
+ position = "28 4";
+ Extent = (%extent.x - 28) SPC "18";
+ hovertime = "100";
+ tooltip = "The component to add to the object";
+ tooltipProfile = "EditorToolTipProfile";
+ };
+
+ %addButton = new GuiIconButtonCtrl() {
+ class = AddComponentQuickEditButton;
+ Profile = "EditorButton";
+ HorizSizing = "right";
+ VertSizing = "bottom";
+ Position = "2 0";
+ Extent = "24 24";
+ buttonMargin = "4 4";
+ iconLocation = "Left";
+ sizeIconToButton = "0";
+ iconBitmap = "tools/gui/images/iconAdd.png";
+ hovertime = "100";
+ tooltip = "Add the selected component to the object";
+ tooltipProfile = "EditorToolTipProfile";
+ componentList = %componentList;
+ };
+
+ %componentList.refresh();
+
+ %container.add(%componentList);
+ %container.add(%addButton);
+
+ if(!isObject("componentTooltipTheme"))
+ {
+ %theme = createsupertooltiptheme("componentTooltipTheme");
+ %theme.addstyle("headerstyle", "");
+ %theme.addstyle("headertwostyle", "");
+ %theme.addstyle("basictextstyle", "");
+ %theme.setdefaultstyle("title", "headerstyle");
+ %theme.setdefaultstyle("paramtitle", "headertwostyle");
+ %theme.setdefaultstyle("param", "basictextstyle");
+ %theme.setspacing(3, 0);
+ }
+
+ return %container;
+}
+
+function QuickEditComponentList::refresh(%this)
+{
+ %this.clear();
+
+ //find all ComponentAssets
+ %assetQuery = new AssetQuery();
+ if(!AssetDatabase.findAssetType(%assetQuery, "ComponentAsset"))
+ return; //if we didn't find ANY, just exit
+
+ // Find all the types.
+ %count = %assetQuery.getCount();
+
+ %categories = "";
+ for (%i = 0; %i < %count; %i++)
+ {
+ %assetId = %assetQuery.getAsset(%i);
+
+ %componentAsset = AssetDatabase.acquireAsset(%assetId);
+ %componentType = %componentAsset.componentType;
+ if (!isInList(%componentType, %categories))
+ %categories = %categories TAB %componentType;
+ }
+
+ %categories = trim(%categories);
+
+ %index = 0;
+ %categoryCount = getFieldCount(%categories);
+ for (%i = 0; %i < %categoryCount; %i++)
+ {
+ %category = getField(%categories, %i);
+ %this.addCategory(%category);
+
+ for (%j = 0; %j < %count; %j++)
+ {
+ %assetId = %assetQuery.getAsset(%j);
+
+ %componentAsset = AssetDatabase.acquireAsset(%assetId);
+ %componentType = %componentAsset.componentType;
+ %friendlyName = %componentAsset.friendlyName;
+
+ if (%componentType $= %category)
+ {
+ //TODO: Haven't worked out getting categories to look distinct
+ //from entries in the drop-down so for now just indent them for the visual distinction
+ %spacedName = " " @ %friendlyName;
+ %this.add(%spacedName, %index);
+ %this.component[%index] = %componentAsset;
+ %index++;
+ }
+ }
+ }
+}
+
+function QuickEditComponentList::onHotTrackItem( %this, %itemID )
+{
+ %componentObj = %this.component[%itemID];
+ if( isObject( %componentObj ) && %this.componentDesc != %componentObj )
+ {
+ SuperTooltipDlg.init("componentTooltipTheme");
+ SuperTooltipDlg.setTitle(%componentObj.friendlyName);
+ SuperTooltipDlg.addParam("", %componentObj.description @ "\n");
+
+ %fieldCount = %componentObj.getComponentFieldCount();
+ for (%i = 0; %i < %fieldCount; %i++)
+ {
+ %name = getField(%componentObj.getComponentField(%i), 0);
+
+ SuperTooltipDlg.addParam(%name, %description @ "\n");
+ }
+ %position = %this.getGlobalPosition();
+ SuperTooltipDlg.processTooltip( %position,0,1 );
+ %this.opened = true;
+ %this.componentDesc = %componentObj;
+ }
+ else if( !isObject( %componentObj ) )
+ {
+ if( %this.opened == true )
+ SuperTooltipDlg.hide();
+ %this.componentDesc = "";
+ }
+}
+
+function QuickEditComponentList::setProperty(%this, %object)
+{
+ %this.objectToAdd = %object;
+}
+
+function QuickEditComponentList::onSelect(%this)
+{
+ if( %this.opened == true )
+ SuperTooltipDlg.hide();
+
+ %this.componentToAdd = %this.component[%this.getSelected()];
+}
+
+function QuickEditComponentList::onCancel( %this )
+{
+ if( %this.opened == true )
+ SuperTooltipDlg.hide();
+}
+
+function AddComponentQuickEditButton::onClick(%this)
+{
+ %component = %this.componentList.componentToAdd;
+
+ %componentName = %this.componentList.componentToAdd.componentName;
+ %componentClass = %this.componentList.componentToAdd.componentClass;
+
+ %command = "$ComponentEditor::newComponent = new" SPC %componentClass SPC "(){ class = \""
+ @ %componentName @ "\"; };";
+
+ eval(%command);
+
+ %instance = $ComponentEditor::newComponent;
+ %undo = new UndoScriptAction()
+ {
+ actionName = "Added Component";
+ class = UndoAddComponent;
+ object = %this.componentList.objectToAdd;
+ component = %instance;
+ };
+
+ %undo.addToManager(LevelBuilderUndoManager);
+
+ %instance.owner = Inspector.getInspectObject(0);
+ %instance.owner.add(%instance);
+
+ Inspector.schedule( 50, "refresh" );
+ EWorldEditor.isDirty = true;
+}
+
+function addComponent(%obj, %instance)
+{
+ echo("Adding the component!");
+ %obj.addComponent(%instance);
+ Inspector.schedule( 50, "refresh" );
+ EWorldEditor.isDirty = true;
+}
+