Imported existing sources

This commit is contained in:
Daniel Brunner
2016-11-01 22:16:08 +01:00
parent 2cf604b8e2
commit 6bf5756740
50 changed files with 82592 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
namespace FluckyGame.Client.Pipeline.Animation
{
public class AnimationClip
{
public class Bone
{
public class Keyframe
{
public double Time;
public Quaternion Rotation;
public Vector3 Translation;
public Matrix Transform
{
get
{
return Matrix.CreateFromQuaternion(Rotation) * Matrix.CreateTranslation(Translation);
}
set
{
Matrix transform = value;
transform.Right = Vector3.Normalize(transform.Right);
transform.Up = Vector3.Normalize(transform.Up);
transform.Backward = Vector3.Normalize(transform.Backward);
Rotation = Quaternion.CreateFromRotationMatrix(transform);
Translation = transform.Translation;
}
}
}
private string name = "";
private List<Keyframe> keyframes = new List<Keyframe>();
public string Name { get { return name; } set { name = value; } }
public List<Keyframe> Keyframes { get { return keyframes; } }
}
private List<Bone> bones = new List<Bone>();
public string Name;
public double Duration;
public List<Bone> Bones { get { return bones; } }
}
}

View File

@@ -0,0 +1,38 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
namespace FluckyGame.Client.Pipeline.Animation
{
public class AnimationClipReader : ContentTypeReader<AnimationClip>
{
protected override AnimationClip Read(ContentReader input, AnimationClip existingInstance)
{
var clip = new AnimationClip();
clip.Name = input.ReadString();
clip.Duration = input.ReadDouble();
int boneCnt = input.ReadInt32();
for (int i = 0; i < boneCnt; i++)
{
var bone = new AnimationClip.Bone();
clip.Bones.Add(bone);
bone.Name = input.ReadString();
int keyframeCnt = input.ReadInt32();
for (int j = 0; j < keyframeCnt; j++)
{
var keyframe = new AnimationClip.Bone.Keyframe();
keyframe.Time = input.ReadDouble();
keyframe.Rotation = input.ReadQuaternion();
keyframe.Translation = input.ReadVector3();
bone.Keyframes.Add(keyframe);
}
}
return clip;
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
namespace FluckyGame.Client.Pipeline.Animation
{
[ContentTypeWriter]
public class AnimationClipWriter : ContentTypeWriter<AnimationClip>
{
protected override void Write(ContentWriter output, AnimationClip clip)
{
output.Write(clip.Name);
output.Write(clip.Duration);
output.Write(clip.Bones.Count);
foreach (var bone in clip.Bones)
{
output.Write(bone.Name);
output.Write(bone.Keyframes.Count);
foreach (var keyframe in bone.Keyframes)
{
output.Write(keyframe.Time);
output.Write(keyframe.Rotation);
output.Write(keyframe.Translation);
}
}
}
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return typeof(AnimationClipReader).AssemblyQualifiedName;
}
}
}

View File

@@ -0,0 +1,315 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
namespace FluckyGame.Client.Pipeline.Animation
{
[ContentProcessor(DisplayName = "Animation Processor")]
public class AnimationProcessor : ModelProcessor
{
private ModelContent model;
private ModelExtra modelExtra = new ModelExtra();
private Dictionary<MaterialContent, SkinnedMaterialContent> toSkinnedMaterial = new Dictionary<MaterialContent, SkinnedMaterialContent>();
private Dictionary<string, int> bones = new Dictionary<string, int>();
private Matrix[] boneTransforms;
private Dictionary<string, AnimationClip> clips = new Dictionary<string, AnimationClip>();
public override ModelContent Process(NodeContent input, ContentProcessorContext context)
{
var skeleton = ProcessSkeleton(input);
SwapSkinnedMaterial(input);
model = base.Process(input, context);
ProcessAnimations(model, input, context);
model.Tag = modelExtra;
return model;
}
private BoneContent ProcessSkeleton(NodeContent input)
{
var skeleton = MeshHelper.FindSkeleton(input);
if (skeleton == null)
return null;
FlattenTransforms(input, skeleton);
TrimSkeleton(skeleton);
var nodes = FlattenHeirarchy(input);
var bones = MeshHelper.FlattenSkeleton(skeleton);
var nodeToIndex = new Dictionary<NodeContent, int>();
for (int i = 0; i < nodes.Count; i++)
nodeToIndex[nodes[i]] = i;
foreach (var bone in bones)
modelExtra.Skeleton.Add(nodeToIndex[bone]);
return skeleton;
}
private List<NodeContent> FlattenHeirarchy(NodeContent item)
{
var nodes = new List<NodeContent>();
nodes.Add(item);
foreach (var child in item.Children)
FlattenHeirarchy(nodes, child);
return nodes;
}
private void FlattenHeirarchy(List<NodeContent> nodes, NodeContent item)
{
nodes.Add(item);
foreach (var child in item.Children)
FlattenHeirarchy(nodes, child);
}
void FlattenTransforms(NodeContent node, BoneContent skeleton)
{
foreach (var child in node.Children)
{
if (child == skeleton)
continue;
if(IsSkinned(child))
FlattenAllTransforms(child);
}
}
void FlattenAllTransforms(NodeContent node)
{
MeshHelper.TransformScene(node, node.Transform);
node.Transform = Matrix.Identity;
foreach (var child in node.Children)
FlattenAllTransforms(child);
}
void TrimSkeleton(NodeContent skeleton)
{
var todelete = new List<NodeContent>();
foreach (var child in skeleton.Children)
if (child.Name.EndsWith("Nub") || child.Name.EndsWith("Footsteps"))
todelete.Add(child);
else
TrimSkeleton(child);
foreach (var child in todelete)
skeleton.Children.Remove(child);
}
bool IsSkinned(NodeContent node)
{
var mesh = node as MeshContent;
if (mesh != null)
foreach (var geometry in mesh.Geometry)
foreach (var vchannel in geometry.Vertices.Channels)
if (vchannel is VertexChannel<BoneWeightCollection>)
return true;
return false;
}
void SwapSkinnedMaterial(NodeContent node)
{
var mesh = node as MeshContent;
if (mesh != null)
{
foreach (var geometry in mesh.Geometry)
{
bool swap = false;
foreach (var vchannel in geometry.Vertices.Channels)
{
if (vchannel is VertexChannel<BoneWeightCollection>)
{
swap = true;
break;
}
}
if (swap)
{
if (toSkinnedMaterial.ContainsKey(geometry.Material))
geometry.Material = toSkinnedMaterial[geometry.Material];
else
{
var smaterial = new SkinnedMaterialContent();
var bmaterial = geometry.Material as BasicMaterialContent;
smaterial.Alpha = bmaterial.Alpha;
smaterial.DiffuseColor = bmaterial.DiffuseColor;
smaterial.EmissiveColor = bmaterial.EmissiveColor;
smaterial.SpecularColor = bmaterial.SpecularColor;
smaterial.SpecularPower = bmaterial.SpecularPower;
smaterial.Texture = bmaterial.Texture;
smaterial.WeightsPerVertex = 4;
toSkinnedMaterial[geometry.Material] = smaterial;
geometry.Material = smaterial;
}
}
}
}
foreach (var child in node.Children)
SwapSkinnedMaterial(child);
}
private void ProcessAnimations(ModelContent model, NodeContent input, ContentProcessorContext context)
{
for (int i = 0; i < model.Bones.Count; i++)
bones[model.Bones[i].Name] = i;
boneTransforms = new Matrix[model.Bones.Count];
ProcessAnimationsRecursive(input);
if (modelExtra.Clips.Count == 0)
{
var clip = new AnimationClip();
modelExtra.Clips.Add(clip);
var clipName = "Take 001";
clips[clipName] = clip;
clip.Name = clipName;
foreach (var bone in model.Bones)
{
var clipBone = new AnimationClip.Bone();
clipBone.Name = bone.Name;
clip.Bones.Add(clipBone);
}
}
foreach (var clip in modelExtra.Clips)
{
for (int b = 0; b < bones.Count; b++)
{
var keyframes = clip.Bones[b].Keyframes;
if (keyframes.Count == 0 || keyframes[0].Time > 0)
{
var keyframe = new AnimationClip.Bone.Keyframe();
keyframe.Time = 0;
keyframe.Transform = boneTransforms[b];
keyframes.Insert(0, keyframe);
}
}
}
}
private void ProcessAnimationsRecursive(NodeContent input)
{
int inputBoneIndex;
if (bones.TryGetValue(input.Name, out inputBoneIndex))
boneTransforms[inputBoneIndex] = input.Transform;
foreach (var animation in input.Animations)
{
AnimationClip clip;
string clipName = animation.Key;
if (!clips.TryGetValue(clipName, out clip))
{
clip = new AnimationClip();
modelExtra.Clips.Add(clip);
clips[clipName] = clip;
clip.Name = clipName;
foreach (var bone in model.Bones)
{
var clipBone = new AnimationClip.Bone();
clipBone.Name = bone.Name;
clip.Bones.Add(clipBone);
}
}
if (animation.Value.Duration.TotalSeconds > clip.Duration)
clip.Duration = animation.Value.Duration.TotalSeconds;
foreach (var channel in animation.Value.Channels)
{
int boneIndex;
if (!bones.TryGetValue(channel.Key, out boneIndex))
continue;
if (UselessAnimationTest(boneIndex))
continue;
var keyframes = new LinkedList<AnimationClip.Bone.Keyframe>();
foreach (var keyframe in channel.Value)
{
var transform = keyframe.Transform;
var newKeyframe = new AnimationClip.Bone.Keyframe();
newKeyframe.Time = keyframe.Time.TotalSeconds;
newKeyframe.Transform = transform;
keyframes.AddLast(newKeyframe);
}
LinearKeyframeReduction(keyframes);
foreach (var keyframe in keyframes)
clip.Bones[boneIndex].Keyframes.Add(keyframe);
}
}
foreach (var child in input.Children)
ProcessAnimationsRecursive(child);
}
private const float TinyLength = 1e-8f;
private const float TinyCosAngle = 0.9999999f;
private void LinearKeyframeReduction(LinkedList<AnimationClip.Bone.Keyframe> keyframes)
{
if (keyframes.Count < 3)
return;
for (var node = keyframes.First.Next; ; )
{
var next = node.Next;
if (next == null)
break;
// Determine nodes before and after the current node.
var a = node.Previous.Value;
var b = node.Value;
var c = next.Value;
var t = (float)((node.Value.Time - node.Previous.Value.Time) / (next.Value.Time - node.Previous.Value.Time));
var translation = Vector3.Lerp(a.Translation, c.Translation, t);
var rotation = Quaternion.Slerp(a.Rotation, c.Rotation, t);
if ((translation - b.Translation).LengthSquared() < TinyLength && Quaternion.Dot(rotation, b.Rotation) > TinyCosAngle)
keyframes.Remove(node);
node = next;
}
}
bool UselessAnimationTest(int boneId)
{
foreach (var mesh in model.Meshes)
if (mesh.ParentBone.Index == boneId)
return false;
foreach (int b in modelExtra.Skeleton)
if (boneId == b)
return false;
return true;
}
}
}

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectGuid>{9975ED45-7A21-4F8A-9EC3-12F5845F681F}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FluckyGame.Client.Pipeline.Animation</RootNamespace>
<AssemblyName>FluckyGame.Client.Pipeline.Animation</AssemblyName>
<XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
<XnaPlatform>Windows</XnaPlatform>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\x86\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\x86\Release</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
<SpecificVersion>True</SpecificVersion>
</Reference>
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
<SpecificVersion>True</SpecificVersion>
</Reference>
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
<SpecificVersion>true</SpecificVersion>
</Reference>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AnimationClip.cs" />
<Compile Include="AnimationClipReader.cs" />
<Compile Include="AnimationClipWriter.cs" />
<Compile Include="AnimationProcessor.cs" />
<Compile Include="ModelExtra.cs" />
<Compile Include="ModelExtraReader.cs" />
<Compile Include="ModelExtraWriter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.ContentPipelineExtensions.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace FluckyGame.Client.Pipeline.Animation
{
public class ModelExtra
{
private List<int> skeleton = new List<int>();
private List<AnimationClip> clips = new List<AnimationClip>();
public List<int> Skeleton { get { return skeleton; } set { skeleton = value; } }
public List<AnimationClip> Clips { get { return clips; } set { clips = value; } }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
namespace FluckyGame.Client.Pipeline.Animation
{
public class ModelExtraReader : ContentTypeReader<ModelExtra>
{
protected override ModelExtra Read(ContentReader input, ModelExtra existingInstance)
{
var extra = new ModelExtra();
extra.Skeleton = input.ReadObject<List<int>>();
extra.Clips = input.ReadObject<List<AnimationClip>>();
return extra;
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
namespace FluckyGame.Client.Pipeline.Animation
{
[ContentTypeWriter]
public class ModelExtraWriter : ContentTypeWriter<ModelExtra>
{
protected override void Write(ContentWriter output, ModelExtra extra)
{
output.WriteObject(extra.Skeleton);
output.WriteObject(extra.Clips);
}
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return typeof(ModelExtraReader).AssemblyQualifiedName;
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("FluckyGame.Client.Pipeline.Animation")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FluckyGame.Client.Pipeline.Animation")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9975ed45-7a21-4f8a-9ec3-12f5845f681f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
namespace FluckyGame.Client
{
public class Bone
{
private Bone parent = null;
private List<Bone> children = new List<Bone>();
private Matrix bindTransform = Matrix.Identity;
private Vector3 bindScale = Vector3.One;
private Vector3 translation = Vector3.Zero;
private Quaternion rotation = Quaternion.Identity;
private Vector3 scale = Vector3.One;
public string Name = "";
public Matrix BindTransform { get { return bindTransform; } }
public Matrix SkinTransform { get; set; }
public Quaternion Rotation { get { return rotation; } set { rotation = value; } }
public Vector3 Translation { get { return translation; } set { translation = value; } }
public Vector3 Scale { get { return scale; } set { scale = value; } }
public Bone Parent { get { return parent; } }
public List<Bone> Children { get { return children; } }
public Matrix AbsoluteTransform = Matrix.Identity;
public Bone(string name, Matrix bindTransform, Bone parent)
{
this.Name = name;
this.parent = parent;
if (parent != null)
parent.children.Add(this);
this.bindScale = new Vector3(bindTransform.Right.Length(),
bindTransform.Up.Length(), bindTransform.Backward.Length());
bindTransform.Right = bindTransform.Right / bindScale.X;
bindTransform.Up = bindTransform.Up / bindScale.Y;
bindTransform.Backward = bindTransform.Backward / bindScale.Y;
this.bindTransform = bindTransform;
ComputeAbsoluteTransform();
SkinTransform = Matrix.Invert(AbsoluteTransform);
}
public void ComputeAbsoluteTransform()
{
var transform =
Matrix.CreateScale(Scale * bindScale) *
Matrix.CreateFromQuaternion(Rotation) *
Matrix.CreateTranslation(Translation) *
BindTransform;
if (Parent != null)
AbsoluteTransform = transform * Parent.AbsoluteTransform;
else
AbsoluteTransform = transform;
}
public void SetCompleteTransform(Matrix m)
{
var setTo = m * Matrix.Invert(BindTransform);
Translation = setTo.Translation;
Rotation = Quaternion.CreateFromRotationMatrix(setTo);
}
}
}

View File

@@ -0,0 +1,53 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace FluckyGame.Client.Entities
{
class BouncingEntity : ModelEntity
{
float ySpeed;
const float randomMin = 1;
const float randomMax = 5;
public BouncingEntity(Model model) :
base(model)
{
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
}
public BouncingEntity(Model model, Vector3 position) :
base(model, position)
{
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
}
public BouncingEntity(Model model, Vector3 position, Vector3 rotation) :
base(model, position, rotation)
{
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
}
public BouncingEntity(Model model, Vector3 position, Vector3 rotation, Vector3 scalation) :
base(model, position, rotation, scalation)
{
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
}
public override void Update(GameTime gameTime, KeyboardState keyboardState, MouseState mouseState)
{
base.Update(gameTime, keyboardState, mouseState);
if (Position.Y > 0)
ySpeed -= 0.1f / 17 * gameTime.ElapsedGameTime.Milliseconds;
else
ySpeed = ((float)Game1.random.NextDouble() * (randomMax - randomMin)) + randomMin;
Position.Y += ySpeed / 17 * gameTime.ElapsedGameTime.Milliseconds;
UpdateWorld();
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
namespace FluckyGame.Client
{
public class Entity
{
public virtual void Update(GameTime gameTime, KeyboardState keyboardState, MouseState mouseState)
{ }
public virtual void Draw(GameTime gameTime)
{ }
}
}

View File

@@ -0,0 +1,288 @@
using System;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using FluckyGame.Client.Pipeline.Animation;
namespace FluckyGame.Client.Entities
{
public class ModelEntity : Entity
{
public Vector3 Position;
public Vector3 Rotation;
public Vector3 Scalation;
Model model;
public Model Model { get { return model; } }
AnimationClip animationClip;
public AnimationClip AnimationClip
{
get { return animationClip; }
set
{
if (value == null)
{
if (animationClip == null)
throw new Exception("No clip playing!");
animationClip = value;
boneInfos = null;
}
else
{
if (animationClip != null)
throw new Exception("Another clip playing!");
animationClip = value;
animationPlaying = false;
animationLooping = false;
animationDuration = (float)animationClip.Duration;
animationSpeed = 1;
boneInfos = new BoneInfo[animationClip.Bones.Count];
for (int i = 0; i < boneInfos.Length; i++)
boneInfos[i] = new BoneInfo(model, animationClip.Bones[i]);
animationPosition = 0;
}
}
}
bool animationPlaying;
public bool AnimationPlaying
{
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationPlaying; }
set { if (animationClip == null) throw new Exception("No clip playing!"); else animationPlaying = value; }
}
bool animationLooping;
public bool AnimationLooping
{
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationLooping; }
set { if (animationClip == null) throw new Exception("No clip playing!"); else animationLooping = value; }
}
float animationDuration;
public float AnimationDuration
{
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationDuration; }
}
float animationSpeed;
public float AnimationSpeed
{
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationSpeed; }
set { if (animationClip == null) throw new Exception("No clip playing!"); else animationSpeed = value; }
}
float animationPosition;
public float AnimationPosition
{
get { if (animationClip == null) throw new Exception("No clip playing!"); else return animationPosition; }
set
{
if (animationClip == null)
throw new Exception("No clip playing!");
else
{
animationPosition = value;
while (animationPosition < 0)
animationPosition += animationDuration;
while (animationPosition > animationDuration)
animationPosition -= animationDuration;
foreach (var bone in boneInfos)
bone.SetPosition(animationPosition);
}
}
}
BoneInfo[] boneInfos;
Matrix world;
public ModelEntity(Model model)
{
this.model = model;
Position = Vector3.Zero;
Rotation = Vector3.Zero;
Scalation = new Vector3(1, 1, 1);
UpdateWorld();
}
public ModelEntity(Model model, Vector3 position)
{
this.model = model;
this.Position = position;
Rotation = Vector3.Zero;
Scalation = new Vector3(1, 1, 1);
UpdateWorld();
}
public ModelEntity(Model model, Vector3 position, Vector3 rotation)
{
this.model = model;
this.Position = position;
this.Rotation = rotation;
Scalation = new Vector3(1, 1, 1);
UpdateWorld();
}
public ModelEntity(Model model, Vector3 position, Vector3 rotation, Vector3 scalation)
{
this.model = model;
this.Position = position;
this.Rotation = rotation;
this.Scalation = scalation;
UpdateWorld();
}
public void UpdateWorld()
{
world = Matrix.CreateScale(Scalation) * Matrix.CreateFromYawPitchRoll(Rotation.X, Rotation.Y, Rotation.Z) * Matrix.CreateTranslation(Position);
}
public override void Draw(GameTime gameTime)
{
if (animationClip == null)
{
foreach (var mesh in model.Meshes)
{
foreach (var effect in mesh.Effects)
if (effect is IEffectMatrices)
(effect as IEffectMatrices).World = world;
mesh.Draw();
}
}
else
{
if (animationPlaying)
{
AnimationPosition += (float)gameTime.ElapsedGameTime.TotalSeconds * animationSpeed;
if (AnimationLooping && AnimationPosition >= AnimationDuration)
AnimationPosition -= AnimationDuration;
}
var modelExtra = Game1.currentInstance.modelExtras[model];
var bones = Game1.currentInstance.modelBones[model];
var boneTransforms = new Matrix[bones.Count];
for (int i = 0; i < bones.Count; i++)
{
var bone = bones[i];
bone.ComputeAbsoluteTransform();
boneTransforms[i] = bone.AbsoluteTransform;
}
var skeleton = new Matrix[modelExtra.Skeleton.Count];
for (int s = 0; s < modelExtra.Skeleton.Count; s++)
{
var bone = bones[modelExtra.Skeleton[s]];
skeleton[s] = bone.SkinTransform * bone.AbsoluteTransform;
}
foreach (var modelMesh in model.Meshes)
{
foreach (var effect in modelMesh.Effects)
{
if (effect is IEffectMatrices)
(effect as IEffectMatrices).World = boneTransforms[modelMesh.ParentBone.Index] * world;
if (effect is SkinnedEffect)
(effect as SkinnedEffect).SetBoneTransforms(skeleton);
modelMesh.Draw();
}
}
}
}
private class BoneInfo
{
private int currentKeyframe = 0;
private Bone assignedBone = null;
public bool valid = false;
private Quaternion rotation;
public Vector3 translation;
public AnimationClip.Bone.Keyframe Keyframe1;
public AnimationClip.Bone.Keyframe Keyframe2;
public AnimationClip.Bone ClipBone { get; set; }
public Bone ModelBone { get { return assignedBone; } }
public BoneInfo(Model model, AnimationClip.Bone bone)
{
this.ClipBone = bone;
SetKeyframes();
SetPosition(0);
assignedBone = Game1.currentInstance.modelBones[model].FirstOrDefault(o => o.Name == ClipBone.Name);
}
public void SetPosition(float position)
{
var keyframes = ClipBone.Keyframes;
if (keyframes.Count == 0)
return;
while (position < Keyframe1.Time && currentKeyframe > 0)
{
currentKeyframe--;
SetKeyframes();
}
while (position >= Keyframe2.Time && currentKeyframe < ClipBone.Keyframes.Count - 2)
{
currentKeyframe++;
SetKeyframes();
}
if (Keyframe1 == Keyframe2)
{
rotation = Keyframe1.Rotation;
translation = Keyframe1.Translation;
}
else
{
var t = (float)((position - Keyframe1.Time) / (Keyframe2.Time - Keyframe1.Time));
rotation = Quaternion.Slerp(Keyframe1.Rotation, Keyframe2.Rotation, t);
translation = Vector3.Lerp(Keyframe1.Translation, Keyframe2.Translation, t);
}
valid = true;
if (assignedBone != null)
{
var m = Matrix.CreateFromQuaternion(rotation);
m.Translation = translation;
assignedBone.SetCompleteTransform(m);
}
}
private void SetKeyframes()
{
if (ClipBone.Keyframes.Count > 0)
{
Keyframe1 = ClipBone.Keyframes[currentKeyframe];
if (currentKeyframe == ClipBone.Keyframes.Count - 1)
Keyframe2 = Keyframe1;
else
Keyframe2 = ClipBone.Keyframes[currentKeyframe + 1];
}
else
{
Keyframe1 = null;
Keyframe2 = null;
}
}
}
}
}

View File

@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using FluckyGame.Library;
namespace FluckyGame.Client.Entities
{
public class PlayerEntity : ModelEntity
{
bool lastDragging;
float cameraYaw;
float CameraYaw { get { return cameraYaw; } }
float cameraPitch;
float CameraPitch { get { return cameraPitch; } }
float cameraDistance;
float CameraDistance { get { return cameraDistance; } }
public PlayerEntity() :
base(Game1.currentInstance.models["dude"])
{
AnimationClip = Game1.currentInstance.modelExtras[Model].Clips[0];
AnimationLooping = true;
cameraDistance = 200;
}
public override void Update(GameTime gameTime, KeyboardState keyboardState, MouseState mouseState)
{
base.Update(gameTime, keyboardState, mouseState);
var shift = keyboardState.IsKeyDown(Keys.LeftShift);
if (keyboardState.IsKeyDown(Keys.W))
Position += Vector3.Transform(new Vector3(0, 0, shift ? -3 :-1), Matrix.CreateRotationY(Rotation.X));
if (keyboardState.IsKeyDown(Keys.S))
Position += Vector3.Transform(new Vector3(0, 0, shift ? 3 : 1), Matrix.CreateRotationY(Rotation.X));
if (keyboardState.IsKeyDown(Keys.A))
Rotation.X += 0.05f;
if (keyboardState.IsKeyDown(Keys.D))
Rotation.X -= 0.05f;
Rotation.X = MathHelper.WrapAngle(Rotation.X);
if (Game1.currentInstance.IsActive)
{
bool currentlyDragging = mouseState.LeftButton == ButtonState.Pressed;
if (currentlyDragging)
{
var centerX = Game1.currentInstance.graphicsDeviceManager.PreferredBackBufferWidth / 2;
var centerY = Game1.currentInstance.graphicsDeviceManager.PreferredBackBufferHeight / 2;
if (lastDragging)
{
cameraYaw -= (mouseState.X - centerX) / 500.0f;
cameraPitch -= (mouseState.Y - centerY) / 500.0f;
cameraYaw = MathHelper.WrapAngle(cameraYaw);
cameraPitch = MathHelper.Clamp(cameraPitch, -MathHelper.PiOver2, MathHelper.PiOver2);
}
Mouse.SetPosition(centerX, centerY);
}
lastDragging = currentlyDragging;
}
if (keyboardState.IsKeyDown(Keys.W) ||
keyboardState.IsKeyDown(Keys.S) ||
keyboardState.IsKeyDown(Keys.A) ||
keyboardState.IsKeyDown(Keys.D))
{
AnimationPlaying = true;
AnimationSpeed = keyboardState.IsKeyDown(Keys.S) ? (shift ? -3 : -1) : (shift ? 3 : 1);
if (Game1.currentInstance.IsActive && mouseState.LeftButton == ButtonState.Released)
{
cameraYaw = MathHelper.SmoothStep(cameraYaw, new List<float>() { Rotation.X - MathHelper.TwoPi, Rotation.X, Rotation.X + MathHelper.TwoPi }.OrderBy(o => Math.Abs(o - cameraYaw)).First(), 0.1f);
cameraPitch = MathHelper.SmoothStep(cameraPitch, Rotation.Y + (MathHelper.PiOver4 / 4), 0.1f);
}
Game1.currentInstance.SendPacket(new Packet() {
{ "type", "PLAYER" },
{ "position", Position },
{ "rotation", Rotation }
});
}
else
{
AnimationPlaying = false;
}
UpdateWorld();
var test = new Vector3(0, 50, 0);
var view = Matrix.CreateLookAt(test + Position + Vector3.Transform(new Vector3(0, cameraDistance, 0), Matrix.CreateRotationX(cameraPitch - MathHelper.PiOver2) * Matrix.CreateRotationY(cameraYaw - MathHelper.Pi)), test + Position, Vector3.Up);
foreach (var model in Game1.currentInstance.models.Values)
foreach (var mesh in model.Meshes)
foreach (var effect in mesh.Effects)
if (effect is IEffectMatrices)
{
var meffect = effect as IEffectMatrices;
meffect.View = view;
}
Game1.currentInstance.terrain.View = view;
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace FluckyGame.Client.Entities
{
public class TerrainEntity : Entity
{
VertexPositionColor[] vertices;
short[] indices;
BasicEffect effect;
GraphicsDevice graphicsDevice;
public Matrix View { set { effect.View = value; } }
public TerrainEntity(int width, int height, GraphicsDevice graphicsDevice, Matrix projection) :
base()
{
this.graphicsDevice = graphicsDevice;
effect = new BasicEffect(this.graphicsDevice);
effect.Projection = projection;
effect.VertexColorEnabled = true;
vertices = new VertexPositionColor[width * height];
indices = new short[(width - 1) * (height - 1) * 6];
int currentIndex = 0;
for (int x = 0; x < width; x++)
for(int z = 0; z < height; z++)
{
vertices[x + z * width].Position = new Vector3(-8000 + (16000 / width * x), (float)Game1.random.NextDouble() * 50 - 50, -8000 + (16000 / height * z));
vertices[x + z * width].Color = new Color(Game1.random.Next(0, 255), Game1.random.Next(0, 255), Game1.random.Next(0, 255));
if(x < width - 1 && z < height - 1)
{
short downLeft = (short)(x + z * width);
short downRight = (short)((x + 1) + z * width);
short upLeft = (short)(x + (z + 1) * width);
short upRight = (short)((x + 1) + (z + 1) * width);
indices[currentIndex++] = downRight;
indices[currentIndex++] = upLeft;
indices[currentIndex++] = downLeft;
indices[currentIndex++] = upRight;
indices[currentIndex++] = upLeft;
indices[currentIndex++] = downRight;
}
}
}
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
effect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3);
}
}
}

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}</ProjectGuid>
<ProjectTypeGuids>{6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FluckyGame.Client</RootNamespace>
<AssemblyName>FluckyGame.Client</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
<XnaPlatform>Windows</XnaPlatform>
<XnaProfile>HiDef</XnaProfile>
<XnaCrossPlatformGroupID>51098c2e-0727-4c82-8833-f5db8d6e4d2f</XnaCrossPlatformGroupID>
<XnaOutputType>Game</XnaOutputType>
<ApplicationIcon>Game.ico</ApplicationIcon>
<Thumbnail>GameThumbnail.png</Thumbnail>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\x86\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
<UseVSHostingProcess>false</UseVSHostingProcess>
<PlatformTarget>x86</PlatformTarget>
<XnaCompressContent>false</XnaCompressContent>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\x86\Release</OutputPath>
<DefineConstants>TRACE;WINDOWS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
<UseVSHostingProcess>false</UseVSHostingProcess>
<PlatformTarget>x86</PlatformTarget>
<XnaCompressContent>true</XnaCompressContent>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
<Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
<Reference Include="Microsoft.Xna.Framework.GamerServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Net" />
</ItemGroup>
<ItemGroup>
<Compile Include="Bone.cs" />
<Compile Include="Entities\BouncingEntity.cs" />
<Compile Include="Entities\Entity.cs" />
<Compile Include="Entities\TerrainEntity.cs" />
<Compile Include="Entities\ModelEntity.cs" />
<Compile Include="Entities\PlayerEntity.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Program.cs" />
<Compile Include="Game1.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Game.ico" />
<Content Include="GameThumbnail.png">
<XnaPlatformSpecific>true</XnaPlatformSpecific>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FluckyGame.Library\FluckyGame.Library.csproj">
<Project>{1cef270c-fce8-4bd1-920f-440d9cc8ed5b}</Project>
<Name>FluckyGame.Library</Name>
</ProjectReference>
<ProjectReference Include="..\FluckyGame.Client.Pipeline\FluckyGame.Client.Pipeline.Animation\FluckyGame.Client.Pipeline.Animation.csproj">
<Project>{9975ed45-7a21-4f8a-9ec3-12f5845f681f}</Project>
<Name>FluckyGame.Client.Pipeline.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\FluckyGame.ClientContent\FluckyGame.ClientContent.contentproj">
<Name>FluckyGame.ClientContent</Name>
<XnaReferenceType>Content</XnaReferenceType>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4 Client Profile %28x86 und x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
<Visible>False</Visible>
<ProductName>Windows Installer 4.5</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.targets" />
<!--
To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,362 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using FluckyGame.Client.Entities;
using FluckyGame.Client.Pipeline.Animation;
using FluckyGame.Library;
namespace FluckyGame.Client
{
public class Game1 : Microsoft.Xna.Framework.Game
{
public static Game1 currentInstance;
public static Random random;
SpriteBatch spriteBatch;
SpriteFont spriteFont;
public GraphicsDeviceManager graphicsDeviceManager;
public Dictionary<string, Model> models;
public Dictionary<Model, ModelExtra> modelExtras;
public Dictionary<Model, List<Bone>> modelBones;
public List<Entity> entities;
public Dictionary<string, ModelEntity> entitiesById;
public PlayerEntity player;
public TerrainEntity terrain;
bool[] last;
bool wireframe;
public Thread networkingThread;
public TcpClient tcpClient;
public NetworkStream networkStream;
private Queue<Packet> queue;
private bool exiting;
static Game1()
{
random = new Random();
}
public Game1(TcpClient tcpClient)
{
this.tcpClient = tcpClient;
currentInstance = this;
graphicsDeviceManager = new GraphicsDeviceManager(this)
{
PreferredBackBufferWidth = 1920 / 2,
PreferredBackBufferHeight = 1080 / 2
};
Content.RootDirectory = "Content";
IsMouseVisible = true;
last = new bool[] { false, false, false, false, false, false, false, false, false, false };
}
protected override void Initialize()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spriteFont = Content.Load<SpriteFont>("SpriteFont");
models = new Dictionary<string, Model>();
modelExtras = new Dictionary<Model, ModelExtra>();
modelBones = new Dictionary<Model, List<Bone>>();
var projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 0.1f, 5000.0f);
foreach (var modelName in new[] { "box", "cone", "cylinder", "dude", "figure", "monkey", "sphere", "torus", "Victoria-hat-dance", "Victoria-hat-tpose" })
{
var model = Content.Load<Model>(Path.Combine("Models", modelName));
foreach (var mesh in model.Meshes)
{
foreach (var effect in mesh.Effects)
{
if (effect is IEffectMatrices)
(effect as IEffectMatrices).Projection = projection;
if (effect is IEffectLights)
(effect as IEffectLights).EnableDefaultLighting();
if (effect is BasicEffect)
(effect as BasicEffect).PreferPerPixelLighting = true;
if (effect is SkinnedEffect)
(effect as SkinnedEffect).PreferPerPixelLighting = true;
}
}
models.Add(modelName, model);
var bones = new List<Bone>();
foreach (ModelBone bone in model.Bones)
bones.Add(new Bone(bone.Name, bone.Transform, bone.Parent != null ? bones[bone.Parent.Index] : null));
modelBones.Add(model, bones);
if (model.Tag is ModelExtra)
{
var modelExtra = model.Tag as ModelExtra;
modelExtras.Add(model, modelExtra);
}
}
var texture = Content.Load<Texture2D>(Path.Combine("Models", "figure_texture"));
foreach (var mesh in models["figure"].Meshes)
foreach (BasicEffect effect in mesh.Effects)
{
effect.Texture = texture;
effect.TextureEnabled = true;
}
entities = new List<Entity>()
{
(player = new PlayerEntity()),
(terrain = new TerrainEntity(200, 200, GraphicsDevice, projection))
};
entitiesById = new Dictionary<string, ModelEntity>();
queue = new Queue<Packet>();
networkStream = this.tcpClient.GetStream();
networkingThread = new Thread(ReceivePackets);
networkingThread.IsBackground = true;
networkingThread.Start();
base.Initialize();
}
private void ReceivePackets()
{
while(true)
{
try
{
var packet = Packet.Receive(networkStream);
lock (queue)
queue.Enqueue(packet);
}
catch(Exception ex)
{
if (!exiting)
{
System.Windows.Forms.MessageBox.Show("Verbindungsfehler:\n\n" + ex.Message, "Verbindungsfehler!", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
Exit();
}
return;
}
}
}
public void SendPacket(Packet packet)
{
packet.Send(networkStream);
}
protected override void Update(GameTime gameTime)
{
lock(queue)
{
while(queue.Count > 0)
{
var packet = queue.Dequeue();
var type = (string)packet["type"];
if (type == "NEW")
{
var model = (string)packet["model"];
var position = (Vector3)packet["position"];
var rotation = (Vector3)packet["rotation"];
var scalation = (Vector3)packet["scalation"];
var entity = new ModelEntity(
models[model],
position,
rotation,
scalation
);
entities.Add(entity);
entitiesById.Add((string)packet["id"], entity);
}
else if(type == "REMOVE")
{
var id = (string)packet["id"];
entities.Remove(entitiesById[id]);
entitiesById.Remove(id);
}
else if (type == "UPDATE")
{
ModelEntity entity = entitiesById[(string)packet["id"]];
if (packet.ContainsKey("position"))
entity.Position = (Vector3)packet["position"];
if (packet.ContainsKey("rotation"))
entity.Rotation = (Vector3)packet["rotation"];
if (packet.ContainsKey("scalation"))
entity.Scalation = (Vector3)packet["scalation"];
entity.UpdateWorld();
}
else
throw new Exception("Unknown packet type!");
}
}
var kState = IsActive ? Keyboard.GetState() : new KeyboardState();
var mState = IsActive ? Mouse.GetState() : new MouseState();
if (kState.IsKeyDown(Keys.Escape))
{
exiting = true;
networkingThread.Abort();
Exit();
}
if (kState.IsKeyDown(Keys.D1) && !last[0])
SendPacket(new Packet() {
{ "type", "ADD" },
{ "model", "box" },
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
{ "rotation", player.Rotation },
{ "scalation", new Vector3(25) }
});
last[0] = kState.IsKeyDown(Keys.D1);
if (kState.IsKeyDown(Keys.D2) && !last[1])
SendPacket(new Packet() {
{ "type", "ADD" },
{ "model", "cone" },
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
{ "rotation", player.Rotation },
{ "scalation", new Vector3(25) }
});
last[1] = kState.IsKeyDown(Keys.D2);
if (kState.IsKeyDown(Keys.D3) && !last[2])
SendPacket(new Packet() {
{ "type", "ADD" },
{ "model", "cylinder" },
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
{ "rotation", player.Rotation },
{ "scalation", new Vector3(25) }
});
last[2] = kState.IsKeyDown(Keys.D3);
if (kState.IsKeyDown(Keys.D4) && !last[3])
SendPacket(new Packet() {
{ "type", "ADD" },
{ "model", "dude" },
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
{ "rotation", player.Rotation },
{ "scalation", new Vector3(1) }
});
last[3] = kState.IsKeyDown(Keys.D4);
if (kState.IsKeyDown(Keys.D5) && !last[4])
SendPacket(new Packet() {
{ "type", "ADD" },
{ "model", "monkey" },
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
{ "rotation", player.Rotation },
{ "scalation", new Vector3(25) }
});
last[4] = kState.IsKeyDown(Keys.D5);
if (kState.IsKeyDown(Keys.D6) && !last[5])
SendPacket(new Packet() {
{ "type", "ADD" },
{ "model", "sphere" },
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
{ "rotation", player.Rotation },
{ "scalation", new Vector3(25) }
});
last[5] = kState.IsKeyDown(Keys.D6);
if (kState.IsKeyDown(Keys.D7) && !last[6])
SendPacket(new Packet() {
{ "type", "ADD" },
{ "model", "torus" },
{ "position", player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)) + new Vector3(0, 25, 0) },
{ "rotation", player.Rotation },
{ "scalation", new Vector3(25) }
});
last[6] = kState.IsKeyDown(Keys.D7);
if (kState.IsKeyDown(Keys.D8) && !last[7])
entities.Add(new ModelEntity(models["Victoria-hat-tpose"], player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)), player.Rotation));
last[7] = kState.IsKeyDown(Keys.D8);
if (kState.IsKeyDown(Keys.D9) && !last[8])
{
var entity = new ModelEntity(models["Victoria-hat-tpose"], player.Position + Vector3.Transform(new Vector3(0, 0, -100), Matrix.CreateRotationY(player.Rotation.X)), player.Rotation, new Vector3(0.4f));
entity.AnimationClip = modelExtras[models["Victoria-hat-dance"]].Clips[0];
entity.AnimationLooping = true;
entity.AnimationPlaying = true;
entities.Add(entity);
}
last[8] = kState.IsKeyDown(Keys.D9);
if (kState.IsKeyDown(Keys.R) && !last[9])
wireframe = !wireframe;
last[9] = kState.IsKeyDown(Keys.R);
foreach (var entity in entities)
entity.Update(gameTime, kState, mState);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
if(wireframe)
{
var rState = new RasterizerState();
rState.FillMode = FillMode.WireFrame;
GraphicsDevice.RasterizerState = rState;
}
foreach (var entity in entities)
entity.Draw(gameTime);
spriteBatch.Begin();
{
var text = string.Format("{0} FPS", (int)(1000 / gameTime.ElapsedGameTime.TotalMilliseconds));
spriteBatch.DrawString(spriteFont, text, new Vector2(graphicsDeviceManager.PreferredBackBufferWidth - spriteFont.MeasureString(text).X, 0), Color.White);
}
spriteBatch.DrawString(spriteFont, string.Format("Player: Position: {0:F2}, {1:F2}, {2:F2} Rotation: {3:F2} {4:F2} {5:F2}", player.Position.X, player.Position.Y, player.Position.Z, player.Rotation.X, player.Rotation.Y, player.Rotation.Z), Vector2.Zero, Color.White);
spriteBatch.DrawString(spriteFont, "Press any key to spawn entity:", new Vector2(0, 40), Color.White);
spriteBatch.DrawString(spriteFont, "1 - Box", new Vector2(0, 60), Color.White);
spriteBatch.DrawString(spriteFont, "2 - Cone", new Vector2(0, 80), Color.White);
spriteBatch.DrawString(spriteFont, "3 - Cylinder", new Vector2(0, 100), Color.White);
spriteBatch.DrawString(spriteFont, "4 - Dude", new Vector2(0, 120), Color.White);
spriteBatch.DrawString(spriteFont, "5 - Monkey", new Vector2(0, 140), Color.White);
spriteBatch.DrawString(spriteFont, "6 - Sphere", new Vector2(0, 160), Color.White);
spriteBatch.DrawString(spriteFont, "7 - Torus", new Vector2(0, 180), Color.White);
spriteBatch.DrawString(spriteFont, "8 - Victoria (not synced)", new Vector2(0, 200), Color.White);
spriteBatch.DrawString(spriteFont, "9 - Victoria (dancing) (not synced)", new Vector2(0, 220), Color.White);
spriteBatch.DrawString(spriteFont, string.Format("{0} entities", entities.Count), new Vector2(0, 260), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -0,0 +1,28 @@
using System;
using System.Net.Sockets;
using System.Windows.Forms;
namespace FluckyGame.Client
{
static class Program
{
static void Main(string[] args)
{
TcpClient tcpClient;
try
{
tcpClient = new TcpClient("home.brunner.ninja", 8001);
}
catch (Exception ex)
{
MessageBox.Show("Konnte keine Verbindung herstellen:\n\n" + ex.Message, "Konnte keine Verbindung herstellen!", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
using (Game1 game = new Game1(tcpClient))
game.Run();
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("FluckyGame.Client")]
[assembly: AssemblyProduct("FluckyGame.Client")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. Only Windows
// assemblies support COM.
[assembly: ComVisible(false)]
// On Windows, the following GUID is for the ID of the typelib if this
// project is exposed to COM. On other platforms, it unique identifies the
// title storage container when deploying this assembly to the device.
[assembly: Guid("8cad4fa5-8d97-4c56-83af-8f305e78f60b")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]

View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}</ProjectGuid>
<ProjectTypeGuids>{96E2B04D-8817-42c6-938A-82C39BA4D311};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
<ContentRootDirectory>Content</ContentRootDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<RootNamespace>FluckyGame.ClientContent</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.EffectImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.FBXImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.TextureImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.XImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.AudioImporters, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Xna.Framework.Content.Pipeline.VideoImporters, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL" />
</ItemGroup>
<ItemGroup>
<Compile Include="SpriteFont.spritefont">
<Name>SpriteFont</Name>
<Importer>FontDescriptionImporter</Importer>
<Processor>FontDescriptionProcessor</Processor>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Models\box.fbx">
<Name>box</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Models\cone.fbx">
<Name>cone</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
<Compile Include="Models\cylinder.fbx">
<Name>cylinder</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
<Compile Include="Models\monkey.fbx">
<Name>monkey</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
<Compile Include="Models\sphere.fbx">
<Name>sphere</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
<Compile Include="Models\torus.fbx">
<Name>torus</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Models\Victoria-hat-tpose.FBX">
<Name>Victoria-hat-tpose</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Models\Victoria-hat-dance.FBX">
<Name>Victoria-hat-dance</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluckyGame.Client.Pipeline\FluckyGame.Client.Pipeline.Animation\FluckyGame.Client.Pipeline.Animation.csproj">
<Project>{9975ed45-7a21-4f8a-9ec3-12f5845f681f}</Project>
<Name>FluckyGame.Client.Pipeline.Animation</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Models\dude.fbx">
<Name>dude</Name>
<Importer>FbxImporter</Importer>
<Processor>AnimationProcessor</Processor>
</Compile>
<Compile Include="Models\figure.fbx">
<Name>figure</Name>
<Importer>FbxImporter</Importer>
<Processor>ModelProcessor</Processor>
</Compile>
<None Include="Models\head.tga">
<Name>head</Name>
<Importer>TextureImporter</Importer>
<Processor>TextureProcessor</Processor>
</None>
<None Include="Models\jacket.tga">
<Name>jacket</Name>
<Importer>TextureImporter</Importer>
<Processor>TextureProcessor</Processor>
</None>
<None Include="Models\pants.tga">
<Name>pants</Name>
<Importer>TextureImporter</Importer>
<Processor>TextureProcessor</Processor>
</None>
<None Include="Models\upBodyC.tga">
<Name>upBodyC</Name>
<Importer>TextureImporter</Importer>
<Processor>TextureProcessor</Processor>
</None>
</ItemGroup>
<ItemGroup>
<Compile Include="Models\figure_texture.png">
<Name>figure_texture</Name>
<Importer>TextureImporter</Importer>
<Processor>TextureProcessor</Processor>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(XnaFrameworkVersion)\Microsoft.Xna.GameStudio.ContentPipeline.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>Segoe UI Mono</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>14</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<!-- <DefaultCharacter>*</DefaultCharacter> -->
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#126;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FluckyGame.Library</RootNamespace>
<AssemblyName>FluckyGame.Library</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Packet.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace FluckyGame.Library
{
[Serializable]
public class Packet : Dictionary<string, object>
{
private static readonly IFormatter formatter;
static Packet()
{
formatter = new BinaryFormatter();
}
public Packet() : base() { }
public Packet(int capacity) : base(capacity) { }
public Packet(IEqualityComparer<string> comparer) : base(comparer) { }
public Packet(IDictionary<string, object> dictionary) : base(dictionary) { }
public Packet(int capacity, IEqualityComparer<string> comparer) : base(capacity, comparer) { }
public Packet(IDictionary<string, object> dictionary, IEqualityComparer<string> comparer) : base(dictionary, comparer) { }
public Packet(SerializationInfo info, StreamingContext context) : base(info, context) { }
public static Packet Receive(Stream stream)
{
var obj = formatter.Deserialize(stream);
var packet = obj as Packet;
if (packet == null)
throw new Exception("no packet received!");
return packet;
}
public void Send(Stream stream)
{
formatter.Serialize(stream, this);
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("FluckyGame.Library")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FluckyGame.Library")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("1cef270c-fce8-4bd1-920f-440d9cc8ed5b")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup>
</configuration>

View File

@@ -0,0 +1,40 @@
using System;
using Microsoft.Xna.Framework;
using FluckyGame.Library;
namespace FluckyGame.Server
{
class BouncingEntity : Entity
{
private float ySpeed;
const float randomMin = 1;
const float randomMax = 5;
public BouncingEntity(string id, string model, Vector3 position, Vector3 rotation, Vector3 scalation) :
base(id, model, position, rotation, scalation)
{
ySpeed = ((float)Program.random.NextDouble() * (randomMax - randomMin)) + randomMin;
}
public override void Update()
{
base.Update();
if (Position.Y > 0)
ySpeed -= 0.1f;
else
ySpeed = ((float)Program.random.NextDouble() * (randomMax - randomMin)) + randomMin;
Position.Y += ySpeed;
lock (Program.clients)
foreach (var client in Program.clients)
client.SendPacket(new Packet() {
{"type", "UPDATE" },
{"id", Id },
{"position", Position }
});
}
}
}

View File

@@ -0,0 +1,148 @@
using System;
using System.Net.Sockets;
using System.Threading;
using Microsoft.Xna.Framework;
using FluckyGame.Library;
namespace FluckyGame.Server
{
internal class Client
{
TcpClient tcpClient;
NetworkStream networkStream;
Thread thread;
bool disconnecting;
Entity playerEntity;
public Client(TcpClient tcpClient)
{
Console.WriteLine("New connection from {0}", tcpClient.Client.RemoteEndPoint);
this.tcpClient = tcpClient;
this.networkStream = this.tcpClient.GetStream();
lock (Program.entities)
{
foreach (var entity in Program.entities)
SendPacket(new Packet() {
{"type", "NEW" },
{"id", entity.Id },
{"model", entity.Model },
{"position", entity.Position },
{"rotation", entity.Rotation },
{"scalation", entity.Scalation }
});
Program.entities.Add(playerEntity = new Entity(Guid.NewGuid().ToString(), "dude", Vector3.Zero, Vector3.Zero, new Vector3(1)));
lock (Program.clients)
foreach (var client in Program.clients)
if(client != this)
client.SendPacket(new Packet() {
{"type", "NEW" },
{"id", playerEntity.Id },
{"model", playerEntity.Model },
{"position", playerEntity.Position },
{"rotation", playerEntity.Rotation },
{"scalation", playerEntity.Scalation }
});
}
thread = new Thread(ReceivePackets);
thread.IsBackground = true;
thread.Start();
}
private void ReceivePackets()
{
try
{
while (true)
{
var packet = Packet.Receive(networkStream);
var type = (string)packet["type"];
if (type == "ADD")
{
lock (Program.entities)
{
var entity = new Entity(
Guid.NewGuid().ToString(),
(string)packet["model"],
(Vector3)packet["position"],
(Vector3)packet["rotation"],
(Vector3)packet["scalation"]
);
Program.entities.Add(entity);
lock (Program.clients)
foreach (var client in Program.clients)
client.SendPacket(new Packet() {
{"type", "NEW" },
{"id", entity.Id },
{"model", entity.Model },
{"position", entity.Position },
{"rotation", entity.Rotation },
{"scalation", entity.Scalation }
});
}
}
else if (type == "PLAYER")
{
playerEntity.Position = (Vector3)packet["position"];
playerEntity.Rotation = (Vector3)packet["rotation"];
lock (Program.clients)
foreach (var client in Program.clients)
if(client != this)
client.SendPacket(new Packet() {
{"type", "UPDATE" },
{"id", playerEntity.Id },
{"position", playerEntity.Position },
{"rotation", playerEntity.Rotation }
});
}
else
throw new Exception("Unknown packet type!");
}
}
catch(Exception ex)
{
if(!disconnecting)
Console.WriteLine(ex.Message);
lock (Program.clients)
Program.clients.Remove(this);
lock (Program.entities)
Program.entities.Remove(playerEntity);
lock (Program.clients)
foreach (var client in Program.clients)
client.SendPacket(new Packet() {
{ "type", "REMOVE" },
{ "id", playerEntity.Id }
});
networkStream.Dispose();
tcpClient.Dispose();
return;
}
}
public void SendPacket(Packet packet)
{
if (disconnecting)
return;
try
{
//TODO: lock to avoid message mixing (one message sending while other)
packet.Send(networkStream);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
disconnecting = true;
thread.Abort();
}
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using Microsoft.Xna.Framework;
namespace FluckyGame.Server
{
class Entity
{
public string Id;
public string Model;
public Vector3 Position;
public Vector3 Rotation;
public Vector3 Scalation;
public Entity(string id, string model, Vector3 position, Vector3 rotation, Vector3 scalation)
{
Id = id;
Model = model;
Position = position;
Rotation = rotation;
Scalation = scalation;
}
public virtual void Update() { }
}
}

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{85507C7D-93AB-4344-9290-4A79396C083E}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FluckyGame.Server</RootNamespace>
<AssemblyName>FluckyGame.Server</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BouncingEntity.cs" />
<Compile Include="Client.cs" />
<Compile Include="Entity.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FluckyGame.Library\FluckyGame.Library.csproj">
<Project>{1cef270c-fce8-4bd1-920f-440d9cc8ed5b}</Project>
<Name>FluckyGame.Library</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.Xna.Framework;
namespace FluckyGame.Server
{
internal static class Program
{
internal static List<Client> clients;
private static Thread acceptThread;
internal static Random random;
internal static List<Entity> entities;
private static void Main(string[] args)
{
Console.WriteLine("Initializing FluckyGame Server 1.0...");
clients = new List<Client>();
acceptThread = new Thread(AcceptConnections);
acceptThread.IsBackground = true;
acceptThread.Start();
//Game Server Initialization
random = new Random();
entities = new List<Entity>();
const int testSize = 200;
const int testStep = 50;
for (var z = -testSize; z <= testSize; z += testStep)
for (var x = -testSize; x <= testSize; x += testStep)
{
entities.Add(new BouncingEntity(
Guid.NewGuid().ToString(),
(new List<string>() { "box", "cone", "cylinder", "figure", "monkey", "sphere", "torus" }).OrderBy(o => random.Next()).First(),
new Vector3(x, 50, z),
Vector3.Zero,
new Vector3(5)));
}
const int minTime = 1000 / 60; //60 FPS
int count = 0;
var dateTime = DateTime.Now;
while (true)
{
var started = DateTime.Now;
var changedEntities = new List<Entity>();
lock (entities)
{
foreach (var entity in entities)
entity.Update();
}
count++;
if((DateTime.Now - dateTime).TotalSeconds >= 1)
{
Console.WriteLine("{0} Updates per Second ({1} clients)", count, clients.Count);
count = 0;
dateTime = DateTime.Now;
}
int elapsed = (int)(DateTime.Now - started).TotalMilliseconds;
if (elapsed < minTime)
Thread.Sleep(minTime - elapsed);
}
}
private static void AcceptConnections()
{
var listener = new TcpListener(IPAddress.Any, 8001);
listener.Start();
while (true)
{
var client = new Client(listener.AcceptTcpClient());
lock(clients)
clients.Add(client);
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("FluckyGame.Server")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FluckyGame.Server")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("85507c7d-93ab-4344-9290-4a79396c083e")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

68
src/FluckyGame.sln Normal file
View File

@@ -0,0 +1,68 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.Client", "FluckyGame.Client\FluckyGame.Client\FluckyGame.Client.csproj", "{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.ClientContent", "FluckyGame.Client\FluckyGame.ClientContent\FluckyGame.ClientContent.contentproj", "{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FluckyGame.Client.Pipeline", "FluckyGame.Client.Pipeline", "{84CFF729-9434-4313-80E9-38853290643D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.Client.Pipeline.Animation", "FluckyGame.Client\FluckyGame.Client.Pipeline\FluckyGame.Client.Pipeline.Animation\FluckyGame.Client.Pipeline.Animation.csproj", "{9975ED45-7A21-4F8A-9EC3-12F5845F681F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.Server", "FluckyGame.Server\FluckyGame.Server.csproj", "{85507C7D-93AB-4344-9290-4A79396C083E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluckyGame.Library", "FluckyGame.Library\FluckyGame.Library.csproj", "{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Debug|Any CPU.ActiveCfg = Debug|x86
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Debug|Any CPU.Build.0 = Debug|x86
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Debug|x86.ActiveCfg = Debug|x86
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Debug|x86.Build.0 = Debug|x86
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Release|Any CPU.ActiveCfg = Release|x86
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Release|x86.ActiveCfg = Release|x86
{8CAD4FA5-8D97-4C56-83AF-8F305E78F60B}.Release|x86.Build.0 = Release|x86
{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}.Debug|Any CPU.ActiveCfg = Debug|x86
{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}.Debug|x86.ActiveCfg = Debug|x86
{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}.Release|Any CPU.ActiveCfg = Release|x86
{C47EAA2D-CEA4-47F0-A413-0DD04E8DEC23}.Release|x86.ActiveCfg = Release|x86
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Debug|Any CPU.ActiveCfg = Debug|x86
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Debug|Any CPU.Build.0 = Debug|x86
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Debug|x86.ActiveCfg = Debug|x86
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Debug|x86.Build.0 = Debug|x86
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Release|Any CPU.ActiveCfg = Release|x86
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Release|Any CPU.Build.0 = Release|x86
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Release|x86.ActiveCfg = Release|x86
{9975ED45-7A21-4F8A-9EC3-12F5845F681F}.Release|x86.Build.0 = Release|x86
{85507C7D-93AB-4344-9290-4A79396C083E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85507C7D-93AB-4344-9290-4A79396C083E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85507C7D-93AB-4344-9290-4A79396C083E}.Debug|x86.ActiveCfg = Debug|Any CPU
{85507C7D-93AB-4344-9290-4A79396C083E}.Debug|x86.Build.0 = Debug|Any CPU
{85507C7D-93AB-4344-9290-4A79396C083E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85507C7D-93AB-4344-9290-4A79396C083E}.Release|Any CPU.Build.0 = Release|Any CPU
{85507C7D-93AB-4344-9290-4A79396C083E}.Release|x86.ActiveCfg = Release|Any CPU
{85507C7D-93AB-4344-9290-4A79396C083E}.Release|x86.Build.0 = Release|Any CPU
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Debug|x86.ActiveCfg = Debug|Any CPU
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Debug|x86.Build.0 = Debug|Any CPU
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Release|Any CPU.Build.0 = Release|Any CPU
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Release|x86.ActiveCfg = Release|Any CPU
{1CEF270C-FCE8-4BD1-920F-440D9CC8ED5B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9975ED45-7A21-4F8A-9EC3-12F5845F681F} = {84CFF729-9434-4313-80E9-38853290643D}
EndGlobalSection
EndGlobal