mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-23 21:27:46 +00:00
added status effect saving
- added some of the packets to add/remove effects (todo: battle packet too)
This commit is contained in:
parent
d9d185d7e6
commit
53207a9ff0
7 changed files with 132 additions and 56 deletions
|
@ -1799,6 +1799,36 @@ namespace FFXIVClassic_Map_Server
|
|||
}
|
||||
return effects;
|
||||
}
|
||||
|
||||
public static void SavePlayerStatusEffects(Player player)
|
||||
{
|
||||
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
|
||||
{
|
||||
try
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
// we'll run them all at once instead of one at a time
|
||||
string queries = "";
|
||||
foreach (var effect in player.statusEffects.GetStatusEffects())
|
||||
{
|
||||
var duration = effect.GetDurationMs() + effect.GetStartTime().Millisecond - Program.Tick.Millisecond;
|
||||
|
||||
queries += Environment.NewLine + $"REPLACE INTO characters_statuseffect(characterId, statusId, magnitude, duration, tick, tier, extra) VALUES ({player.actorId}, {effect.GetEffectId()}, {effect.GetMagnitude()}, {duration}, {effect.GetTickMs()}, {effect.GetTier()}, {effect.GetExtra()});";
|
||||
}
|
||||
MySqlCommand cmd = new MySqlCommand(queries, conn);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
catch (MySqlException e)
|
||||
{
|
||||
Program.Log.Error(e.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
conn.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using FFXIVClassic_Map_Server.Actors;
|
||||
using FFXIVClassic_Map_Server.lua;
|
||||
using FFXIVClassic_Map_Server.packets.send.actor;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -440,6 +441,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
return (uint)id;
|
||||
}
|
||||
|
||||
public ushort GetEffectIdForCharaWork()
|
||||
{
|
||||
return (ushort)(id - 200000);
|
||||
}
|
||||
|
||||
public DateTime GetStartTime()
|
||||
{
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public string GetName()
|
||||
{
|
||||
return name;
|
||||
|
@ -480,6 +491,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
return (byte)overwrite;
|
||||
}
|
||||
|
||||
public void SetStartTime(DateTime time)
|
||||
{
|
||||
this.startTime = time;
|
||||
this.lastTick = time;
|
||||
}
|
||||
|
||||
public void SetOwner(Character owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
|
|
|
@ -16,11 +16,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
{
|
||||
private Character owner;
|
||||
private readonly Dictionary<uint, StatusEffect> effects;
|
||||
public static readonly int MAX_EFFECTS = 20;
|
||||
|
||||
public StatusEffectContainer(Character owner)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.effects = new Dictionary<uint, StatusEffect>(20);
|
||||
this.effects = new Dictionary<uint, StatusEffect>();
|
||||
}
|
||||
|
||||
public void Update(DateTime tick)
|
||||
|
@ -54,9 +55,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
(overwritable == (uint)StatusEffectOverwrite.GreaterOrEqualTo && (effect.GetDurationMs() == newEffect.GetDurationMs() || effect.GetMagnitude() == newEffect.GetMagnitude()));
|
||||
}
|
||||
|
||||
if (canOverwrite || effects.ContainsKey(effect.GetEffectId()))
|
||||
if (canOverwrite || effect == null)
|
||||
{
|
||||
if (!silent || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0)
|
||||
if (!silent || (effect?.GetFlags() & (uint)StatusEffectFlags.Silent) == 0)
|
||||
{
|
||||
// todo: send packet to client with effect added message
|
||||
}
|
||||
|
@ -65,8 +66,17 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
effects.Remove(effect.GetEffectId());
|
||||
|
||||
effects.Add(newEffect.GetEffectId(), newEffect);
|
||||
|
||||
// todo: this is retarded..
|
||||
{
|
||||
var index = Array.IndexOf(effects.Values.ToArray(), newEffect);
|
||||
owner.charaWork.status[index] = effect.GetEffectIdForCharaWork();
|
||||
owner.charaWork.statusShownTime[index] = effect.GetDurationMs() / 1000;
|
||||
this.owner.zone.BroadcastPacketAroundActor(this.owner, SetActorStatusPacket.BuildPacket(this.owner.actorId, (ushort)index, (ushort)effect.GetEffectId()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RemoveStatusEffect(StatusEffect effect, bool silent = false)
|
||||
|
@ -76,10 +86,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
// send packet to client with effect remove message
|
||||
if (!silent || (effect.GetFlags() & (uint)StatusEffectFlags.Silent) == 0)
|
||||
{
|
||||
// todo: send packet to client with effect added message
|
||||
// todo: send packet to client with effect removed message
|
||||
}
|
||||
|
||||
// function onLose(actor, effec)
|
||||
// todo: this is retarded..
|
||||
{
|
||||
var index = Array.IndexOf(effects.Values.ToArray(), effect);
|
||||
owner.charaWork.status[index] = effect.GetEffectIdForCharaWork();
|
||||
this.owner.zone.BroadcastPacketAroundActor(this.owner, SetActorStatusPacket.BuildPacket(owner.actorId, (ushort)index, (ushort)0));
|
||||
}
|
||||
// function onLose(actor, effect
|
||||
LuaEngine.CallLuaStatusEffectFunction(this.owner, effect, "onLose", this.owner, effect);
|
||||
effects.Remove(effect.GetEffectId());
|
||||
}
|
||||
|
@ -158,5 +174,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||
{
|
||||
return effects.Values;
|
||||
}
|
||||
|
||||
void SaveStatusEffectsToDatabase(StatusEffectFlags removeEffectFlags = StatusEffectFlags.None)
|
||||
{
|
||||
if (owner is Player)
|
||||
{
|
||||
Database.SavePlayerStatusEffects((Player)owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.state
|
|||
{
|
||||
var damage = utils.AttackUtils.CalculateDamage(owner, target);
|
||||
|
||||
lua.LuaEngine.GetInstance().CallLuaFunction(owner, target, "onAttack", false, damage);
|
||||
// onAttack(actor, target, damage)
|
||||
lua.LuaEngine.CallLuaBattleAction(owner, "onAttack", false, owner, target, damage);
|
||||
|
||||
//var packet = BattleAction1Packet.BuildPacket(owner.actorId, target.actorId);
|
||||
|
||||
|
|
|
@ -684,6 +684,7 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
//Save Player
|
||||
Database.SavePlayerPlayTime(this);
|
||||
Database.SavePlayerPosition(this);
|
||||
Database.SavePlayerStatusEffects(this);
|
||||
}
|
||||
|
||||
public void CleanupAndSave(uint destinationZone, ushort spawnType, float destinationX, float destinationY, float destinationZ, float destinationRot)
|
||||
|
@ -706,7 +707,9 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
//Save Player
|
||||
Database.SavePlayerPlayTime(this);
|
||||
Database.SavePlayerPosition(this);
|
||||
Database.SavePlayerPosition(this);
|
||||
this.statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnZoning, true);
|
||||
Database.SavePlayerStatusEffects(this);
|
||||
}
|
||||
|
||||
public Area GetZone()
|
||||
|
@ -721,13 +724,16 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||
|
||||
public void Logout()
|
||||
{
|
||||
// todo: really this should be in CleanupAndSave but we might want logout/disconnect handled separately for some effects
|
||||
QueuePacket(LogoutPacket.BuildPacket(actorId));
|
||||
statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnLogout);
|
||||
CleanupAndSave();
|
||||
}
|
||||
|
||||
public void QuitGame()
|
||||
{
|
||||
QueuePacket(QuitPacket.BuildPacket(actorId));
|
||||
statusEffects.RemoveStatusEffectsByFlags((uint)StatusEffectFlags.LoseOnLogout);
|
||||
CleanupAndSave();
|
||||
}
|
||||
|
||||
|
|
|
@ -134,32 +134,33 @@ namespace FFXIVClassic_Map_Server.lua
|
|||
/// // todo: this is dumb, should probably make a function for each action with different default return values
|
||||
/// or just make generic function and pass default value as first arg after functionName
|
||||
/// </summary>
|
||||
public static void CallLuaMonsterAction(Character actor, string functionName, params object[] args)
|
||||
public static void CallLuaBattleAction(Character actor, string functionName, params object[] args)
|
||||
{
|
||||
string path = $"./scripts/unique/{actor.zone.zoneName}/Monster/{actor.customDisplayName}.lua";
|
||||
|
||||
// todo: should we call this for players too?
|
||||
if (actor is BattleNpc)
|
||||
if (actor is Player)
|
||||
{
|
||||
// todo: check this is correct
|
||||
string path = $"./scripts/unique/{actor.zone.zoneName}/Monster/{actor.customDisplayName}.lua";
|
||||
|
||||
// dont wanna throw an error if file doesnt exist
|
||||
if (File.Exists(path))
|
||||
path = FILEPATH_PLAYER;
|
||||
}
|
||||
// dont wanna throw an error if file doesnt exist
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var script = LoadGlobals();
|
||||
try
|
||||
{
|
||||
var script = LoadGlobals();
|
||||
try
|
||||
{
|
||||
script.DoFile(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Log.Error($"LuaEngine.CallLuaMonsterAction [{functionName}] {e.Message}");
|
||||
}
|
||||
DynValue res = new DynValue();
|
||||
script.DoFile(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.Log.Error($"LuaEngine.CallLuaBattleAction [{functionName}] {e.Message}");
|
||||
}
|
||||
DynValue res = new DynValue();
|
||||
|
||||
if (!script.Globals.Get(functionName).IsNil())
|
||||
{
|
||||
res = script.Call(script.Globals.Get(functionName), args);
|
||||
}
|
||||
if (!script.Globals.Get(functionName).IsNil())
|
||||
{
|
||||
res = script.Call(script.Globals.Get(functionName), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,42 +391,41 @@ namespace FFXIVClassic_Map_Server.lua
|
|||
return null;
|
||||
}
|
||||
|
||||
public void CallLuaFunction(Actor actor, Actor target, string funcName, bool optional, params object[] args)
|
||||
public void CallLuaFunction(Player player, Actor target, string funcName, bool optional, params object[] args)
|
||||
{
|
||||
bool isPlayer = actor is Player;
|
||||
//Need a seperate case for NPCs cause that child/parent thing.
|
||||
if (target is Npc && isPlayer)
|
||||
if (target is Npc)
|
||||
{
|
||||
CallLuaFunctionNpc((Player)actor, (Npc)target, funcName, optional, args);
|
||||
CallLuaFunctionNpc(player, (Npc)target, funcName, optional, args);
|
||||
return;
|
||||
}
|
||||
|
||||
object[] args2 = new object[args.Length + 2];
|
||||
Array.Copy(args, 0, args2, 2, args.Length);
|
||||
args2[0] = actor;
|
||||
args2[0] = player;
|
||||
args2[1] = target;
|
||||
|
||||
string luaPath = GetScriptPath(target);
|
||||
LuaScript script = LoadScript(luaPath);
|
||||
if (script != null)
|
||||
{
|
||||
if (!script.Globals.Get(funcName).IsNil() && isPlayer)
|
||||
if (!script.Globals.Get(funcName).IsNil())
|
||||
{
|
||||
Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
|
||||
DynValue value = coroutine.Resume(args2);
|
||||
ResolveResume((Player)actor, coroutine, value);
|
||||
ResolveResume(player, coroutine, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!optional)
|
||||
SendError((Player)actor, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
|
||||
SendError(player, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(target is Area) && !optional && isPlayer)
|
||||
SendError((Player)actor, String.Format("Could not find script for actor {0}.", target.GetName()));
|
||||
}
|
||||
if (!(target is Area) && !optional)
|
||||
SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
|
||||
}
|
||||
}
|
||||
|
||||
public void EventStarted(Player player, Actor target, EventStartPacket eventStart)
|
||||
|
@ -456,18 +456,16 @@ namespace FFXIVClassic_Map_Server.lua
|
|||
}
|
||||
}
|
||||
|
||||
public DynValue ResolveResume(Actor actor, Coroutine coroutine, DynValue value)
|
||||
public DynValue ResolveResume(Player player, Coroutine coroutine, DynValue value)
|
||||
{
|
||||
var isPlayer = actor is Player;
|
||||
|
||||
if (value == null || value.IsVoid())
|
||||
return value;
|
||||
|
||||
if (isPlayer && value.String != null && value.String.Equals("_WAIT_EVENT"))
|
||||
if (player != null && value.String != null && value.String.Equals("_WAIT_EVENT"))
|
||||
{
|
||||
GetInstance().AddWaitEventCoroutine((Player)actor, coroutine);
|
||||
GetInstance().AddWaitEventCoroutine(player, coroutine);
|
||||
}
|
||||
else if (isPlayer && value.Tuple != null && value.Tuple.Length >= 1 && value.Tuple[0].String != null)
|
||||
else if (player != null && value.Tuple != null && value.Tuple.Length >= 1 && value.Tuple[0].String != null)
|
||||
{
|
||||
switch (value.Tuple[0].String)
|
||||
{
|
||||
|
@ -619,12 +617,12 @@ namespace FFXIVClassic_Map_Server.lua
|
|||
LuaParam.Insert(1, i - (playerNull ? 2 : 0));
|
||||
|
||||
// run the script
|
||||
script.Call(script.Globals["onTrigger"], LuaParam.ToArray());
|
||||
//script.Call(script.Globals["onTrigger"], LuaParam.ToArray());
|
||||
|
||||
// gm commands dont need to be coroutines?
|
||||
//Coroutine coroutine = script.CreateCoroutine(script.Globals["onTrigger"]).Coroutine;
|
||||
//DynValue value = coroutine.Resume(LuaParam.ToArray());
|
||||
//ResolveResume(player, coroutine, value);
|
||||
Coroutine coroutine = script.CreateCoroutine(script.Globals["onTrigger"]).Coroutine;
|
||||
DynValue value = coroutine.Resume(LuaParam.ToArray());
|
||||
LuaEngine.GetInstance().ResolveResume(player, coroutine, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `status_effect`
|
||||
-- Table structure for table `status_effects`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `status_effect`;
|
||||
DROP TABLE IF EXISTS `status_effects`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `status_effect` (
|
||||
CREATE TABLE `status_effects` (
|
||||
`id` smallint(5) unsigned NOT NULL,
|
||||
`name` varchar(128) NOT NULL,
|
||||
`flags` int(10) unsigned NOT NULL,
|
||||
|
@ -32,12 +32,12 @@ CREATE TABLE `status_effect` (
|
|||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `status_effect`
|
||||
-- Dumping data for table `status_effects`
|
||||
--
|
||||
|
||||
LOCK TABLES `status_effect` WRITE;
|
||||
/*!40000 ALTER TABLE `status_effect` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `status_effect` ENABLE KEYS */;
|
||||
LOCK TABLES `status_effects` WRITE;
|
||||
/*!40000 ALTER TABLE `status_effects` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `status_effects` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue