forked from elfinlazz/aura-2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathChannelClient.cs
196 lines (166 loc) · 5.28 KB
/
ChannelClient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright (c) Aura development team - Licensed under GNU GPL
// For more information, see license file in the main folder
using System.Linq;
using System.Collections.Generic;
using Aura.Channel.Database;
using Aura.Channel.Scripting;
using Aura.Channel.Util;
using Aura.Channel.World.Entities;
using Aura.Shared.Network;
using Aura.Channel.Skills.Life;
using Aura.Mabi.Const;
using Aura.Mabi.Network;
using Aura.Channel.World;
using Aura.Channel.World.Dungeons;
using System;
using Aura.Shared.Util;
namespace Aura.Channel.Network
{
public class ChannelClient : DefaultClient
{
public Account Account { get; set; }
/// <summary>
/// Main creature this client controls.
/// </summary>
public Creature Controlling { get; set; }
/// <summary>
/// List of creatures the client is controlling.
/// </summary>
public Dictionary<long, Creature> Creatures { get; protected set; }
/// <summary>
/// Information about a current NPC dialog.
/// </summary>
public NpcSession NpcSession { get; set; }
public ChannelClient()
{
this.Creatures = new Dictionary<long, Creature>();
this.NpcSession = new NpcSession();
}
/// <summary>
/// Returns creature by entity id or null.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Creature GetCreature(long id)
{
Creature creature;
this.Creatures.TryGetValue(id, out creature);
return creature;
}
/// <summary>
/// Returns creature or throws security exception if creature
/// couldn't be found in client.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Creature GetCreatureSafe(long id)
{
var result = this.GetCreature(id);
if (result == null)
throw new SevereViolation("Client doesn't control creature 0x{0:X}", id);
return result;
}
/// <summary>
/// Returns controlled creature or throws security exception if
/// it's null.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Creature GetControlledCreatureSafe()
{
var result = this.Controlling;
if (result == null)
throw new SevereViolation("Client doesn't control any creature");
return result;
}
/// <summary>
/// Calls <see cref="GetCreatureSafe(long)"/> and then checks the pet's master for null.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Creature GetSummonedPetSafe(long id)
{
var pet = this.GetCreatureSafe(id);
if (pet.Master == null)
throw new ModerateViolation("Pet 0x{0:X} doesn't have a master.", id);
return pet;
}
/// <summary>
/// Saves characters, despawns and disposes them, etc.
/// </summary>
public override void CleanUp()
{
// Moved here to always be called when a client is being killed off.
if (this.Controlling != null)
ChannelServer.Instance.Events.OnPlayerDisconnect(this.Controlling);
// Dispose creatures, to remove subscriptions and stuff.
// Do this before unspawning, the creature might need the region.
foreach (var creature in this.Creatures.Values)
creature.Dispose();
foreach (var creature in this.Creatures.Values.Where(a => a.Region != Region.Limbo))
{
// Close NPC sessions
if (creature.Client.NpcSession.Script != null)
creature.Client.NpcSession.Clear();
var newLocation = new Location();
// Use fallback location if creature is in a temp region.
if (creature.Region is DynamicRegion)
newLocation = creature.FallbackLocation;
// Use dungeon exit as fallback location if in a dungeon.
var dungeonRegion = creature.Region as DungeonRegion;
if (dungeonRegion != null)
{
try
{
newLocation = new Location(dungeonRegion.Dungeon.Data.Exit);
}
catch (Exception ex)
{
Log.Exception(ex, "Failed to fallback warp character in dungeon.");
newLocation = new Location(1, 12800, 38100); // Tir square
}
if (dungeonRegion.Dungeon.Script != null)
dungeonRegion.Dungeon.Script.OnLeftEarly(dungeonRegion.Dungeon, creature);
}
// Finish running cutscenes
var cutscene = creature.Temp.CurrentCutscene;
if (cutscene != null && cutscene.Leader == creature)
cutscene.Finish();
// Unspawn creature
creature.Region.RemoveCreature(creature);
// Set new location (if applicable) after everyting else is done,
// in case on of the previous calls needs the creature's
// original position.
if (newLocation.RegionId != 0)
creature.SetLocation(newLocation);
// Update online status
var playerCreature = creature as PlayerCreature;
if (playerCreature != null)
ChannelServer.Instance.Database.UpdateOnlineStatus(playerCreature.CreatureId, false);
}
// Save everything after we're done cleaning up
if (this.Account != null)
{
ChannelServer.Instance.Database.SaveAccount(this.Account);
ChannelServer.Instance.Database.SetAccountLoggedIn(this.Account.Id, false);
}
this.Creatures.Clear();
this.Account = null;
}
}
/// <summary>
/// Dummy client for creatures, so we don't have to care about who is
/// actually able to receive data.
/// </summary>
public class DummyClient : ChannelClient
{
public override void Send(byte[] buffer)
{ }
public override void Send(Packet packet)
{ }
public override void Kill()
{ }
public override void CleanUp()
{ }
}
}