Compare commits

...

8 Commits

Author SHA1 Message Date
cake
8b4274dffd Fix build of mergee
All checks were successful
Tag and Release Lightless / tag-and-release (push) Successful in 2m10s
2026-01-22 02:46:05 +01:00
cake
571a9df483 version update
Some checks failed
Tag and Release Lightless / tag-and-release (push) Failing after 2m12s
2026-01-22 02:30:28 +01:00
cake
b3d1e80176 update dev 2026-01-22 02:30:22 +01:00
cake
0808dae4f1 Updated PTRGuard to use different values on windows. 2026-01-22 02:16:37 +01:00
defnotken
e00f80d7bd 2.1.1 2026-01-20 14:10:05 -06:00
72a62b7449 2.1.0 (#123)
All checks were successful
Tag and Release Lightless / tag-and-release (push) Successful in 2m9s
# Patchnotes 2.1.0
The changes in this update are more than just "patches". With a new UI, a new feature, and a bunch of bug fixes, improvements and a new member on the dev team, we thought this was more of a minor update.

We would like to introduce @tsubasahane of MareCN to the team! We’re happy to work with them to bring Lightless and its features to the CN client as well as having another talented dev bring features and ideas to us. Speaking of which:

# Location Sharing (Big shout out to @tsubasahane for bringing this feature)

- Are you TIRED of scrambling to find the address of the venue you're in to share with your friends? We are introducing Location Sharing! An optional feature where you can share your location with direct pairs temporarily [30 minutes, 1 hour, 3 hours] minutes or until you turn it off for them. That's up to you! [#125](<#125>)  [#49](<Lightless-Sync/LightlessServer#49>)
- To share your location with a pair, click the three dots beside the pair and choose a duration to share with them. [#125](<#125>)  [#49](<Lightless-Sync/LightlessServer#49>)
- To view the location of someone who's shared with you, simply hover over the globe icon! [#125](<#125>)  [#49](<Lightless-Sync/LightlessServer#49>)

[1]

# Model Optimization (Mesh Decimating)
 - This new option can automatically “simplify” incoming character meshes to help performance by reducing triangle counts. You choose how strong the reduction is (default/recommended is 80%). [#131](<#131>)
 - Decimation only kicks in when a mesh is above a certain triangle threshold, and only for the items that qualify for it and you selected for. [#131](<#131>)
 - Hair meshes is always excluded, since simplifying hair meshes is very prone to breaking.
 - You can find everything under Settings → Performance → Model Optimization. [#131](<#131>)
+ ** IF YOU HAVE USED DECIMATION IN TESTING, PLEASE CLEAR YOUR CACHE  **

[2]

# Animation (PAP) Validation (Safer animations)
 - Lightless now checks your currently animations to see if they work with your local skeleton/bone mod. If an animation matches, it’s included in what gets sent to other players. If it doesn’t, Lightless will skip it and write a warning to your log showing how many were skipped due to skeleton changes. Its defaulted to Unsafe (off). turn it on if you experience crashes from others users. [#131](<#131>)
 - Lightless also does the same kind of check for incoming animation files, to make sure they match the body/skeleton they were sent with. [#131](<#131>)
 - Because these checks can sometimes be a little picky, you can adjust how strict they are in Settings -> General -> Animation & Bones to reduce false positives. [#131](<#131>)

# UI Changes (Thanks to @kyuwu for UI Changes)
- The top part of the main screen has gotten a makeover. You can adjust the colors of the gradiant in the Color settings of Lightless. [#127](<#127>)

[3]

- Settings have gotten some changes as well to make this change more universal, and will use the same color settings. [#127](<#127>)
- The particle effects of the gradient are toggleable in 'Settings -> UI -> Behavior' [#127](<#127>)
- Instead of showing download/upload on bottom of Main UI, it will show VRAM usage and triangles with their optimization options next to it [#138](<#138>)

# LightFinder / ShellFinder
- UI Changes that follow our new design follow the color codes for the Gradient top as the main screen does.  [#127](<#127>)

[4]

Co-authored-by: defnotken <itsdefnotken@gmail.com>
Co-authored-by: azyges <aaaaaa@aaa.aaa>
Co-authored-by: cake <admin@cakeandbanana.nl>
Co-authored-by: Tsubasa <tsubasa@noreply.git.lightless-sync.org>
Co-authored-by: choco <choco@patat.nl>
Co-authored-by: celine <aaa@aaa.aaa>
Co-authored-by: celine <celine@noreply.git.lightless-sync.org>
Co-authored-by: Tsubasahane <wozaiha@gmail.com>
Co-authored-by: cake <cake@noreply.git.lightless-sync.org>
Reviewed-on: #123
2026-01-20 19:43:00 +00:00
defnotken
59b2776943 syncing dev and stable
All checks were successful
Tag and Release Lightless / tag-and-release (push) Successful in 2m17s
2026-01-20 13:28:38 -06:00
defnotken
b3c35dbfdc Changelogs 2026-01-20 13:22:34 -06:00
7 changed files with 120 additions and 53 deletions

View File

@@ -1,11 +1,86 @@
tagline: "Lightless Sync v2.0.1"
subline: "LIGHTLESS IS EVOLVING!!"
tagline: "Lightless Sync v2.1.0"
subline: "Location Sharing, Animation Scanning, Sync Improvements, Lifestream IPC, and More!"
changelog:
- name: "v2.1.0"
tagline: "Happy New Year!"
date: "January 20 2026"
# be sure to set this every new version
isCurrent: true
versions:
- number: "Location Sharing (S/O to Tsubasa from the MareCN team for this feature!)"
icon: ""
items:
- "Are you TIRED of scrambling to find the address of the venue you're in to share with your friends? We are introducing Location Sharing! An optional feature where you can share your location with direct pairs temporarily [30 minutes, 1 hour, 3 hours] or until you turn it off for them. That's up to you!"
- "To share your location with a pair, click the three dots beside the pair and choose a duration to share with them."
- "To view the location of someone who's shared with you, simply hover over the globe icon!"
- number: "Model Optimization (Mesh Decimating)"
icon: ""
items:
- "This new option can automatically “simplify” incoming character meshes to help performance by reducing triangle counts. You choose how strong the reduction is (default/recommended is 80%). "
- "Decimation only kicks in when a mesh is above a certain triangle threshold, and only for the items that qualify for it and you selected for."
- "Hair meshes is always excluded, since simplifying hair meshes is very prone to breaking."
- "You can find everything under Settings → Performance → Model Optimization."
- "IF YOU HAVE USED DECIMATION IN TESTING, PLEASE CLEAR YOUR CACHE!"
- number: "Animation (PAP) Validation (Safer animations)"
icon: ""
items:
- "Lightless now checks your currently animations to see if they work with your local skeleton/bone mod. If an animation matches, its included in what gets sent to other players. If it doesnt, Lightless will skip it and write a warning to your log showing how many were skipped due to skeleton changes. Its defaulted to Unsafe (off). turn it on if you experience crashes from others users."
- "Lightless also does the same kind of check for incoming animation files, to make sure they match the body/skeleton they were sent with."
- "Because these checks can sometimes be a little picky, you can adjust how strict they are in Settings -> General -> Animation & Bones to reduce false positives."
- number: "UI Changes (Thanks to Choco for UI Changes)"
icon: ""
items:
- "The top part of the main screen has gotten a makeover. You can adjust the colors of the gradiant in the Color settings of Lightless."
- "Settings have gotten some changes as well to make this change more universal, and will use the same color settings."
- "The particle effects of the gradient are toggleable in 'Settings -> UI -> Behavior"
- "Instead of showing download/upload on bottom of Main UI, it will show VRAM usage and triangles with their optimization options next to it"
- number: "LightFinder / ShellFinder"
icon: ""
items:
- "UI Changes that follow our new design follow the color codes for the Gradient top as the main screen does."
- "A list of players using LightFinder near you is now available."
- "Improved the look of ShellFinder; a new pop-up for the join screen is included. This will be merged into more spots later."
- number: "Syncing Changes"
icon: ""
items:
- "Fixed a bottleneck that caused hitching for some users."
- "Fixed a bug where files in the downscale directory were not being deleted correctly."
- "Improved performance tracking by tracking both original and effective triangle counts."
- "Improved owned object detection."
- "Reverted collection work to old way to mitigate the syncing and VFX issues."
- "Fixed minion/mount/pet tracking to validate against player-related."
- "Added timeout support to Wait For Fully Loaded."
- "Enhanced pair handling to support model decimation. (Effective Triangles)."
- "Improved downloads through atomization."
- "Improved data management by only pushing to online pairs."
- number: "Syncshell Admin Panel changes"
icon: ""
items:
- "Changes to banned userlist to allow for preemptive banning of users."
- "Fixed when you are the owner, the buttons aren't overflowing into the side."
- "Pruning has been fixed not to include online users. It will only focus on offline users now."
- "Fixed that moderators can finally broadcast the syncshell."
- number: "Bug Fixes"
icon: ""
items:
- "Fixed a bug in the client CI/CD workflow where the plugin was contained twice in the zip. This will cut down on overall plugin size."
- "Added new flags for certain ImGUI windows to fix focusing issues with Chat2."
- "Validating PTRs for the game objects to prevent crashing while switching characters."
- number: "Lifestream Plugin integration"
icon: ""
items:
- "We have added Lifestream as an optional plugin you can install to support multiple future implementations >:3. In the near future, you'll be able to go straight to your pair using the Lifestream plugin in as easy as one click. We are also cooking something up for now; it will simply show as an optional plugin."
- "Integrated Lifestream to Location Sharing to easily teleport to all plots/apartments, and most maps."
- number: "Q1 Roadmap"
icon: ""
items:
- "Diagnostics Window - Est. Feb"
- "Ability to set a location as a 'Home' in syncshells - Est. Mid-Late Feb"
- "Lifestream support for Syncshell Homes - Est. Mid-Late Feb"
- "Community-oriented feature - In Refinement (est. Mar/Apr)"
- name: "v2.0.2"
tagline: "Last update of 2025!... ... ... If Nothing breaks"
date: "December 28 2025"
# be sure to set this every new version
isCurrent: true
versions:
- number: "Chat"
icon: ""

View File

@@ -11,6 +11,8 @@ credits:
role: "Developer"
- name: "Kenny"
role: "Developer"
- name: "Tsubasa"
role: "Developer"
- name: "Zura"
role: "Developer"
- name: "Additional Contributors"

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Authors></Authors>
<Company></Company>
<Version>2.0.2.83</Version>
<Version>2.1.0.67</Version>
<Description></Description>
<Copyright></Copyright>
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>

View File

@@ -127,7 +127,7 @@ public class PlayerDataFactory
{
nint basePtr = playerPointer;
if (!PtrGuard.LooksLikePtr(basePtr))
if (!PtrGuard.LooksLikePtr(basePtr, _dalamudUtil.IsWine))
return true;
nint drawObjAddr = basePtr + _drawObjectOffset;
@@ -135,10 +135,10 @@ public class PlayerDataFactory
if (!PtrGuard.IsReadable(drawObjAddr, (nuint)IntPtr.Size))
return true;
if (!PtrGuard.TryReadIntPtr(drawObjAddr, out var drawObj))
if (!PtrGuard.TryReadIntPtr(drawObjAddr, _dalamudUtil.IsWine, out var drawObj))
return true;
if (drawObj != 0 && !PtrGuard.LooksLikePtr(drawObj))
if (drawObj != 0 && !PtrGuard.LooksLikePtr(drawObj, _dalamudUtil.IsWine))
return true;
return drawObj == 0;

View File

@@ -180,7 +180,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase, IHighP
var nextAddr = _getAddress();
if (nextAddr != IntPtr.Zero && !PtrGuard.LooksLikePtr(nextAddr))
if (nextAddr != IntPtr.Zero && !PtrGuard.LooksLikePtr(nextAddr, _dalamudUtil.IsWine))
{
nextAddr = IntPtr.Zero;
}
@@ -196,13 +196,8 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase, IHighP
if (Address != IntPtr.Zero)
{
var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)Address;
var draw = (nint)gameObject->DrawObject;
if (!PtrGuard.LooksLikePtr(draw) || !PtrGuard.IsReadable(draw, (nuint)sizeof(DrawObject)))
draw = 0;
DrawObjectAddress = draw;
var drawObjAddr = (IntPtr)gameObject->DrawObject;
DrawObjectAddress = drawObjAddr;
EntityId = gameObject->EntityId;
if (PtrGuard.IsReadable(Address, (nuint)sizeof(Character)))
@@ -360,10 +355,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase, IHighP
private unsafe bool CompareAndUpdateMainHand(Weapon* weapon)
{
var p = (nint)weapon;
if (!PtrGuard.LooksLikePtr(p) || !PtrGuard.IsReadable(p, (nuint)sizeof(Weapon)))
return false;
if ((nint)weapon == nint.Zero) return false;
bool hasChanges = false;
hasChanges |= weapon->ModelSetId != MainHandData[0];
MainHandData[0] = weapon->ModelSetId;
@@ -376,10 +368,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase, IHighP
private unsafe bool CompareAndUpdateOffHand(Weapon* weapon)
{
var p = (nint)weapon;
if (!PtrGuard.LooksLikePtr(p) || !PtrGuard.IsReadable(p, (nuint)sizeof(Weapon)))
return false;
if ((nint)weapon == nint.Zero) return false;
bool hasChanges = false;
hasChanges |= weapon->ModelSetId != OffHandData[0];
OffHandData[0] = weapon->ModelSetId;

View File

@@ -5,40 +5,41 @@ namespace LightlessSync.Utils
{
public static partial class PtrGuard
{
private const ulong _aligmentPtr = 0x7UL;
private static readonly nuint _minAppAddr = (nuint)GetMinAppAddr();
private static readonly nuint _maxAppAddr = (nuint)GetMaxAppAddr();
private static readonly nuint _hardMinWindows =
(nuint)(IntPtr.Size == 8 ? 0x0000000100000000UL : 0x0000000000010000UL);
private static readonly nuint _hardMaxWindows =
(nuint)(IntPtr.Size == 8 ? 0x00007FFFFFFFFFFFUL : 0x7FFFFFFFUL);
private const nuint _alignmentPtr = 0x7;
private static nint GetMinAppAddr()
private static readonly (nuint min, nuint max) _sysRange = GetSysRange();
private static (nuint min, nuint max) GetSysRange()
{
GetSystemInfo(out var si);
return si.lpMinimumApplicationAddress;
return ((nuint)si.lpMinimumApplicationAddress, (nuint)si.lpMaximumApplicationAddress);
}
private static nint GetMaxAppAddr()
private static nuint GetMinAppAddr(bool isWine) => isWine ? _sysRange.min : _hardMinWindows;
private static nuint GetMaxAppAddr(bool isWine) => isWine ? _sysRange.max : _hardMaxWindows;
public static bool LooksLikePtr(nint p, bool isWine = false)
{
GetSystemInfo(out var si);
return si.lpMaximumApplicationAddress;
if (p == 0) return false;
nuint u = (nuint)p;
if (u < GetMinAppAddr(isWine)) return false;
if (u > GetMaxAppAddr(isWine)) return false;
if ((u & _alignmentPtr) != 0) return false;
if ((uint)u == 0x12345679u) return false;
return true;
}
public static bool LooksLikePtr(nint p)
{
if (p == 0) return false;
nuint u = (nuint)p;
if (u < _minAppAddr) return false;
if (u > _maxAppAddr) return false;
if ((u & _aligmentPtr) != 0) return false;
if ((uint)u == 0x12345679u) return false;
return true;
}
public static bool TryReadIntPtr(nint addr, out nint value)
public static bool TryReadIntPtr(nint addr, bool isWine, out nint value)
{
value = 0;
if (!LooksLikePtr(addr))
if (!LooksLikePtr(addr, isWine))
return false;
return ReadProcessMemory(GetCurrentProcess(), addr, out value, (nuint)IntPtr.Size, out nuint bytesRead)
@@ -49,7 +50,7 @@ namespace LightlessSync.Utils
{
if (addr == 0 || size == 0) return false;
if (VirtualQuery(addr, out var mbi, (nuint)Marshal.SizeOf<MEMORY_BASIC_INFORMATION>()) == 0)
if (VirtualQuery(addr, out var mbi, (nuint)Marshal.SizeOf<MemoryBasicInformation>()) == 0)
return false;
const uint Commit = 0x1000;

View File

@@ -5,7 +5,7 @@ namespace LightlessSync.Utils
internal static class PtrGuardMemory
{
[StructLayout(LayoutKind.Sequential)]
internal struct MEMORY_BASIC_INFORMATION
internal struct MemoryBasicInformation
{
public nint BaseAddress;
public nint AllocationBase;
@@ -19,7 +19,7 @@ namespace LightlessSync.Utils
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern nuint VirtualQuery(
nint lpAddress,
out MEMORY_BASIC_INFORMATION lpBuffer,
out MemoryBasicInformation lpBuffer,
nuint dwLength);
[DllImport("kernel32.dll", SetLastError = true)]
@@ -34,10 +34,10 @@ namespace LightlessSync.Utils
internal static extern nint GetCurrentProcess();
[DllImport("kernel32.dll")]
internal static extern void GetSystemInfo(out SYSTEM_INFO lpSystemInfo);
internal static extern void GetSystemInfo(out SystemInfo lpSystemInfo);
[StructLayout(LayoutKind.Sequential)]
internal struct SYSTEM_INFO
internal struct SystemInfo
{
public ushort wProcessorArchitecture;
public ushort wReserved;